单链表:


1、逻辑上连续,位置上可以不连续的存储方式。

2、单链表由无数个结点组成,每个结点由数据段和指针域组成,数据段存储数据,指针域存储后继的地址。

3、每个结点最多有一个前继和一个后继。

4、第一个结点没有前继,通常建立一个头结点来保存其地址。最后一个结点没有后继,通常将其指针域赋为NULL。


其他:


5.单链表和双链表:双链表每个结点还存在一个指向上一个结点的指针,所以在向上访问时,双链表的效率更高。


6.静态链表和动态链表:静态链表由数组实现,存储空间预先分配是静态的,物理地址是连续的。动态链表是函数malloc()动态申请的,物理地址可以不连续,通过指针实现访问。


#include<stdio.h>
#include<stdlib.h>
typedef int ElemType;
typedef struct linknode
{
    ElemType data;
    struct linknode *next;
}node;
void judgement_memory(node * p);
node* creat_order();
node * creat_reverse();
int length_list(node *head);
void find_element(node *head, ElemType const x);
void find_place(node *head, int i);
void insert(node *head, int i, ElemType x);
void delete_place(node *head, int i);
int delete_element(node *head, ElemType const x);
     node* inits_linklist(node *head);
void output(node *head);
int means();
void delete_all_element(node *ret, ElemType x);

void judgement_memory(node * p)     //判断开辟内存是否成功
{
    if (NULL == p)
    {
        perror("out of memory:");
        exit(EXIT_FAILURE);
    }
}
node* creat_order()                    //建立一个具有头结点单链表,顺序插入(尾插法)
{
    printf("开始建立:");
    node *head, *p, *r;
    int x = 0;
    head = (node *)malloc(sizeof(node));             //建立头结点
    judgement_memory(head);
    r = head;
    while (1)
    {
        scanf("%d", &x);
        if (x != 0)                                        //以0作为链表结束标志
        {
            p = (node *)malloc(sizeof(node));
            judgement_memory(p);
            p->data = x;
            r->next = p;
            r = p;
        }
        else
            break;
    }
    r->next = NULL;
    return head;
}
node * creat_reverse()           //建立一个具有头结点的单链表,逆序输入(头插法)
{
    printf("开始建立:");
    node *head, *p, *r, *q;
    int x = 0;
    head = (node *)malloc(sizeof(node));
    judgement_memory(head);
    p = (node *)malloc(sizeof(node));                  //开辟最后一个结点
    judgement_memory(p);
    p->next = NULL;
    scanf("%d", &x);
    p->data =x;
    r = head;
    q = p;
    r->next = q;
    while (1)
    {
        scanf("%d", &x);
        if (x != 0)
        {
            p = (node *)malloc(sizeof(node));
            judgement_memory(p);
            p->data = x;
            r->next = p;
            p->next = q;
            q = p;
        }
        else
            break;
    }
    return head;
}
int length_list(node *head)           //求链表长度
{
    int count = 0;
    while (head)
    {
        count++;
        head = head->next;
    }
    return count;
}
void find_element(node *head, ElemType const x)          //通过元素查找链表中该元素的位置找到返回结点
{
    head = head->next;                                   //head是头结点,head->next指向下一个结点
    int count = 0;
    int i = 0;
    while (head)
    {
        count++;
        if (head->data == x)                            //如果找到输出count
        {
            i++;
            printf("%d  ", count);
        }
        head = head->next;
    }
    if (i == 0)                                       //如果没有输出count,说明没有x,所以i==0;
        printf("查询无果\n");
    else
        printf("\n");
}
void find_place(node *head, int i)              //通过位置来查找该链表中位于此位置的元素
{
    head = head->next;
    while (i>1)
    {                                             //如果要找第i个结点的元素,则要先找到第i-1个结点
        i--;
        head = head->next;
        if (head->next == NULL)
            break;
    }
    if (i == 1)
        printf("%d\n", head->data);
    else
        printf("查询无果\n");
}
void insert(node *head, int i, ElemType x)                 //插入一个结点
{
    node *r;
    node *s = (node *)malloc(sizeof(node));
    judgement_memory(s);
    s->data = x;
        while (NULL != head&&i>1)                         //要在第i个结点上插入,则先找到第i-1个结点
        {
            i--;
            head = head->next;
        }
        if (NULL != head&&i!=0)                           //判断是不是头结点和结点是否存在
        {
            //r = head->next;
            //head->next = s;
            //s->next = r;
            r = head->next;
            head->next = s;
            s->next = r;
            printf("插入成功\n");
        }
        else
            printf("结点不存在\n");
}
void delete_place(node *head, int i)                 //删除链表中一个指定位置的结点
{
    node *p;
    if (NULL == head)
    {
        printf("链表下溢\n");
    }
    else
    {
            while (NULL != head&&i>1)            //找到第i-1个结点
            {
                i--;
                head = head->next;
            }
            if (NULL == head||i==0)
                printf("没有该位置\n");
            else
            {
                p = head->next;
                head->next = p->next;
                free(p);
                printf("删除成功\n");
            }
         }
}
int delete_element(node *head, ElemType const x)   //删除链表中一个指定的x元素
{
    node *p, *q;
    if (head == NULL)                              //链表下溢,-1
        return -1;
    if (x == head->data)                           //判断第一个结点的数据是不是x
    {
        p = head;
        head = head->next;
        free(p);
        return 0;
    }
    else
    {
        while (NULL != head&&head->data != x)            //在链表剩下的元素中寻找x
        {
            q = head;
            head = head->next;
        }
        if (NULL == head)                                //没找到返回 0
            return 0;
        else
        {
            p = head;
            q->next = p->next;
            free(p);
        }
    }
    return 1;                                            //删除成功返回1
}

node* inits_linklist(node *head)    //初始化链表
{
    node *p = head->next;
    free(p);
    head->next=NULL;
    printf("初始化成功\n");
    return NULL;
}

void output(node *head)                          //打印链表
{
    head = head->next;                            //让头结点指向下一个结点
    printf("输出链表:");
    while (head != NULL)
    {
        printf("%d  ", head->data);
        head = head->next;
    }
    printf("\n");
}
int means()                                     //选择方式
{
    int means = 0;
    while (1)
    {
        printf("请选择的方式:");
        scanf("%d", &means);
        if (means == 1 || means == 2)
            break;
        else
            printf("选择无效,请重新输入\n");
    }
    return means;
}

void delete_all_element(node *ret,ElemType x)       //根据元素删除,将这个链表里面的这个元素的结点全部删除
{
    int m = 0;
    int count = 0;
    while (1)
    {
        m = delete_element(ret, x);
        if (m == 0 || m == -1)
            break;
        count++;
    }
    if (m == 0)
    {
        if (count == 0)
            printf("没有此元素\n");
        else
            printf("删除成功\n");
    }
    else
        printf("链表下溢\n");
}


int main()
{
    printf("*****************************************\n");
    printf("*****************************************\n");
    printf("**1.Create_LinkList    2.Insert_Element **\n");
    printf("**3.Find              4.Delete_Element **\n");
    printf("**5.Length_LinkList   6.Output_LinkList**\n");
    printf("**7.Inits_LinkList    0.Exit           **\n\n\n");

    node *ret=NULL;
    ElemType x;
    int i=0;
    int n = 0;
    while (1)                                      //循环起来,直到选择0结束
    {
        printf("请选择功能:");
        scanf("%d", &n);
        if (n == 0)
        {
            free(ret);
            exit(1);
        }
        //选择正序建立链表还是逆序建立链表,并且链表以0作为结束标志
        if (n == 1 && ret == NULL)
        {
            printf("**1.creat_order  2.creat_reverse **\n");
            if (means() == 1)
                ret = creat_order();
            else
                ret = creat_reverse();
        }
        else if (n != 1&& ret == NULL)
            printf("\n请先建立链表\n\n");
        else if (ret!=NULL)
        {
            switch (n)
            {
            case 2:
                printf("请输入要插入的位置和要插入的元素\n");
                scanf("%d", &i);
                scanf("%d", &x);
                insert(ret, i, x);
                break;
            case 3:             //选择根据位置查找还是根据元素查找
            {
                 printf("**1.find_place         2.find_element **\n");
                 if (means() == 1)
                 {
                     printf("请输入要查找的位置:");
                     scanf("%d", &i);
                     find_place(ret, i);
                 }
                 else
                 {
                    printf("请输入要查找的元素:");
                    scanf("%d", &x);
                    find_element(ret, x);
                }
             }
                break;
            case 4:                //选择根据位置删除还是根据元素删除
            {
                printf("**1.delete_place     2.delete_element **\n");
                if (means() == 1)
                {
                    printf("请输入要删除的位置:");
                    scanf("%d", &i);
                    delete_place(ret, i);
                }
                else
                            //根据元素删除,将这个链表里面的这个元素的结点全部删除
                {
                    printf("请输入要删除的元素:");
                    scanf("%d", &x);
                    delete_all_element(ret, x);
                }
            }
                break;
            case 5:
                printf("链表长度:%d\n", length_list(ret));
                break;
            case 6:                           //打印链表
                output(ret);
                break;
            case 7:              //初始化链表,如果继续的话,需要重新建立链表
                ret = inits_linklist(ret);
                break;
            default:
                printf("选择无效,请重新选择\n");
                break;
            }
        }

    }
    system("pause");
    return 0;
}