完整代码在最后

一.单链表基本操作

1.初始化

1)创建结构体,储存节点的数据+指针域; 2)创建指向结构体的指针; 3)用结构体定义单链表; 4)初始化链表头节点:为头节点开辟内存; 5)判断内存是否开辟成功; 6)头节点的指针域置空,使链表长度为0。

typedef struct Node//1
{
     ElemType data;
     struct Node *next;
}Node;
typedef struct Node *LinkList;//2
Status InitList(LinkList& L)//3
{
     L=(Node*)malloc(sizeof(Node));//4
     if(L==NULL)//5
     {
          printf("申请内存空间失败\n");
     }
     L->next=NULL;//6
}

2.创建单链表(尾插法)

1)生成新结点p和尾结点r; 2)为新节点开辟内存; 3)存入数据域; 4)存入指针域:把原来的尾结点指针域存入,即在末尾插入p; 5)更新r,使其依然为链表尾结点; 6)尾结点指针域置空

void CreateListTail(LinkList *L,int n)
{
     LinkList p,r;//1
     while(n--)
     {
          p=(Node*)malloc(sizeof(Node));//2
          scanf("%d",&p->data);//3
          r->next=p;//4
          r=p;//5
     }
     r->next=NULL;
}

3.整表清除

1)结点p储存头结点; 2)判断p是否到表尾,没到就进入以下循环; a.结点q指向p下一个结点; b.释放p结点; c.p指向q结点。 3)头指针置空,相当于初始化链表。

  • 注:不能用p=p->next代替q,∵在free(p)时也释放了指针域,∴p->next不存在。

Statue ClearList(ListLine *L)
{
     ListLine p,q;
     p=(*L)->next;//1
     while(p)//2
     {
          q=p->next;//a
          free(p);//b
          p=q;//c
     }
     (*L)->next=NULL; 
}

4.获取第 i 个元素

1)用p指向链表第一个元素; 2)用j遍历链表,直到找到i或p已经到链表结尾,即p=NULL; 3)如果没找到,p指向下一个结点; 4)若退出循环时p为NULL或i元素不存在,则返回ERROR; 5)若找到就把数据存入。

Statue GetElem(LinkList *L,int i,int *e)
{
     int j=1;
     p=(*L)->next;//1
     while(j<i&&p)//2
     {
          p=p->next;//3
          j++;
     }
     if(j>i||!p)//4
     {
          return ERROR;
     }
     *e=p->data;//5
     return OK;
}

5.插入元素

在第i位后插入元素e。变成a,e,a+1。

1)遍历链表找到第i位; 2)创立要插入的新节点s; 3)开辟新节点s的内存; 4)s的数据域存入e; 5)连接e与a+1:把a+1的指针域给新结点s; 6)连接a与e:把s给a的指针域。

Statue ListInsert(LinkList *L,int i,ElemType e)
{
     //1
     int j=1;
     LinkList p;
     p=(*L)->next;//p从头开始找:将链表头结点给p
     while(p&&j<i)
     {
          p=p->next;
          j++;
     }
     if(!p||j>i)
     {
          return ERROR;
     }
     LinkList s;//2
     s=(Node*)malloc(sizeof(Node));//3
     s->data=e;//4
     s->next=p->next;//5
     p->next=s;//6
     return OK;
}

6.删除元素

删除i位的元素,并把删除的元素值返回到e中。

1)遍历列表找到i位,注:∵要删除p->next结点,∴p->next不能为NULL; 2)将预删除的结点储存在q内; 3)将p->next赋值为q->next,即进行了p->next=p->next->next操作; 4)把q里的数据——需删除的数据,给e; 5)释放结点q。

Statue ListDelete(LinkList *L,int i,ElemType *e)
{
     //1
     int j=1;
     LinkList p;
     p=(*L)->next;
     while(p->next&&j<i)
     {
          p=p->next;
          j++;
     }
     if(!(p->next)||j>i)
     {
          return ERROR;
     }
     LinkList q;
     q=p->next;//2
     p->next=q->next;//3
     *e=q->data;//4
     free(q);//5
     return OK;
}

7.输出链表

void OutPutList(LinkList *L)
{
     LinkList p;
     p=(*L)->next;
     while(p)
     {
          printf("%d\n",p->data);
     }
}

完整代码

#include<stdio.h>
#include<stdlib.h>
#include<time.h>//用于生成随机数
​
typedef int Status;//用Status来进行替代int,方便数据类型的修改
typedef int ElemType;
#define OK 1;
#define ERROR 0;
​
//单链表储存结构
typedef struct Node//定义结构体LNode
{
    ElemType data;//结点数据域
    struct Node* next;//结点指针域
}Node;
typedef struct Node* LinkList;//LinkList为指向结构体Node的指针类型
​
//初始化一个空的单链表L
Status InitList(LinkList& L) //InitList()顺序表的初始化函数
{     
    L = (Node*)malloc(sizeof(Node));          //申请空间,生成新结点作为L头结点
    if (L == NULL)                           //判断是否有足够的内存空间 
    {
        printf("申请内存空间失败\n");
    }
    L->next = NULL;          //头结点的指针域置空,初始长度为0
    return OK;
}
​
//尾插法创建链表
void CreateListTail(LinkList* L, int n)//*L即调用已经存在的线性表L
{
    LinkList p, r;//L:指整个单链表;p:需创建的新节点;r:指向尾结点的变量。
    r = *L;//r指向尾部节点
    printf("1.输入初始数据\n2.自动生成数据\n");//链表生成类型选择
    int a;
    scanf("%d", &a);
    if (a == 1)
    {
        while (n--)
        {
            p = (Node*)malloc(sizeof(Node));//为新结点开辟内存
            scanf("%d", &p->data);//读取数据
            r->next = p;//在原来的尾结点r后存入
            r = p;//更新尾结点
        }
        r->next = NULL;//链表结束
    } 
    else if(a==2)
    {
        srand(time(0));//初始化随机数种子
        r = *L;//r指向链表尾部
        while (n--)
        {
            p = (Node*)malloc(sizeof(Node));//生成新结点
            p->data = rand() % 100 + 1;//随机产生100以内的数
            r->next = p;//将新结点添加到表尾
            r = p;//更新尾结点:将新结点更新为尾结点
        }
        r->next = NULL;//表示链表结束
    }
    printf("链表创建成功!\n");
}
​
//整表删除,即变成空表
Status ClearList(LinkList* L)
{
    LinkList p, q;
    p =(*L)->next;//使p指向线性表第一个结点
    while (p)//如果p不为NULL
    {
        q = p->next;//q指向p的下一个结点,防止释放p后找不到下一个结点
        free(p);//释放p结点
        p = q;//p指向下一个结点
    }
    (*L)->next = NULL;//使头结点为空,相当于链表初始化时的操作
    return OK;
}
​
//查找,读取元素,获取第i个元素数据,返回到e
Status GetElem(LinkList *L, int i, ElemType* e)
{
    int j=1;//计数,最后一个结点是NULL,不需要遍历∴从1开始计
    LinkList p;
    p=(*L)->next;//p从头结点开始找
    //遍历链表,找到第i个元素
    while (j <i&&p)//若没找到||p=NULL退出
    {
        p=p->next;//指向下一个结点
        j++;
    }
    if (!p||j>i)//p为空||不存在i结点时
    {
        printf("出错!查找位置在链表之外!\n");
        return ERROR;
    }
    *e = p->data;
    return OK;
}
​
//在位置i插入元素e,使链表成为 a,e,a+1
Status ListInsert(LinkList* L, int i, ElemType *e)
{
    //先遍历找到第i个结点
    int j=1;
    LinkList p;
    p = (*L)->next;//p指向链表头结点
    if (i == 0)//头结点插入特判
    {
        LinkList s;
        s = (Node*)malloc(sizeof(Node));
        s->data = *e;//存数据域
        s->next = (*L)->next;//把原头结点给s的下一个结点
        (*L)->next = s;//更新新结点
        printf("成功!\n");
        return OK;
    }
    while (j < i && p)
    {
        p=p->next;
        j++;
    }
    if (!p || j > i)//没找到
    {
        printf("出错!插入位置在链表之外!\n");
        return ERROR;
    }
​
    //找到位置后插入
    LinkList s;//创建要插入的新结点
    s= (Node*)malloc(sizeof(Node));//为新节点开辟内存
    s->data = *e;//储存数据域
    s->next = p->next;//将p后继结点给s的后继,即连接e和a+1
    p->next = s;//将s给p的后继,即连接a和e
    printf("成功!\n");
    return OK;
}
​
//删除第i个元素,并用e返回其值
Status ListDelete(LinkList* L, int i, ElemType* e)
{
    //遍历找到第i个结点
    int j=1;
    LinkList p;
    p = (*L)->next;
    if (i == 1)//若是头结点需特判
    {
        *e = p->data;
        (*L)->next = p->next;//使链表头结点直接指向下一个
        printf("删除元素的值为:%d\n", *e);
        printf("成功!\n");
        return OK;
    }
    i--;
    while (j < i && p->next)//∵需删除p后的结点,∴p->next必须存在
    {
        p = p->next;
        j++;
    }
     if (!(p->next) || i < j)
     {
        printf("出错!删除位置在链表之外!\n");
        return ERROR;
     }
        LinkList q;
        q = p->next;//将预删除的结点给q
        p->next = q->next;//p连接需删除结点后的结点,即p->next=p->next->next
        *e = q->data;//删除结点中的数据给e
        free(q);//释放删除的结点
        printf("删除元素的值为:%d\n", *e);
        printf("成功!\n");
    return OK;
}
​
//输出链表
void OutPutList(LinkList* L)
{
    LinkList p;
    p = (*L)->next;
    while (p)
    {
        printf("%d\n", p->data);
        p = p->next;
    }
}
​
​
int main()
{
    Node *L;
    int n,i,e,q;
    InitList(L);
    //目录
    printf("                目录\n");
    printf("1.创建链表\n2.查找列表元素\n3.清空链表\n4.插入元素\n5.删除元素\n6.输出链表\n\n");
    while (~scanf("%d", &q))
    {
        if (q == 1)
        {
            printf("请输入链表数据个数:\n");
            scanf("%d", &n);
            CreateListTail(&L, n);
        }
        else if (q == 2)
        {
            scanf("%d", &i);
            GetElem(&L, i, &e);
        }
        else if (q == 3)
        {
            ClearList(&L);
            printf("链表已清空!\n");
        }
        else if(q==4)
        {
            printf("请输入需插入的位置:\n");
            scanf("%d", &i);
            printf("请输入需插入元素的值:\n");
            scanf("%d", &e);
            ListInsert(&L, i, &e);
        }
        else if (q == 5)
        {
            printf("请输入需删除的元素位置:\n");
            scanf("%d", &i);
            ListDelete(&L, i, &e);
        }
        else if (q == 6)
        {
            printf("\n");
            OutPutList(&L);
        }
        printf("                目录\n");
        printf("1.创建链表\n2.查找列表元素\n3.清空链表\n4.插入元素\n5.删除元素\n6.输出链表\n\n");
    }
    return 0;
}

运行截图:

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐