IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 数据结构-单向链表的操作(详细思路和实例) -> 正文阅读

[数据结构与算法]数据结构-单向链表的操作(详细思路和实例)

一、链表

1. 链表的概念

顺序表在内存中开辟空间是连续的,实际开发中这是一种奢望。
在实际开发中无法满足大型数据量的项目,想出一种解决大型数据量的数据操作方法 --> 链表
链表可以解决无法开辟连续空间的问题

链表的逻辑结构:线性结构,一对一
链表的储存结构:链式储存,在内存中储存不一定连续

链表分为有头节点无头节点的,区别就是头结点是否存储数据。
有头链表现在常用,相较于无头链表浪费了一个节点空间,但是会带来操作上的方便。
还分为单向链表和双向链表,还有循环链表。此次我们着重有头单向链表的操作进行讲解和演示。

2.顺序表(数组)和链表的区别

顺序表:
1.插入和删除数据比较麻烦,需要批量的移动元素
2.按照位置访问元素比较方便,可以通过数组下标操作
3.使用前需要明确最大的长度,对空间使用不够灵活
链表:
1.增删数据比较方便,只需要改变指针的指向即可
2.查找数据比较麻烦,无法通过下标直接获取,只能通过next指针遍历
3.使用前无需确定长度,每次malloc即可,对空间的使用比较灵活

二、链表的相关操作

1. 链表的创建操作

有头链表的创建本质就是创建头结点,我们依然是将链表在堆区创建,头结点数据域不使用,主要使用指针域。

1.1定义节点类型

typedef int data_t;
typedef struct node{
    data_t data; //数据域 不一定是int也可以是自己封装的结构体
    struct node *next;//指针域
}link_list_t;

1.2定义链表头节点指针

link_list_t *L==NULL;

1.3从堆区分配空间给头节点

L=(link_list_t *)malloc(sizeof(link_list_t));

1.4初始化头节点

L->next=NULL;
L->data=-1;

1.5返回链表头节点地址

return L;

创建链表完整函数源码

link_list_t *create_linklist(void)
{
    //从堆区申请头结点空间
    link_list_t *L=(link_list_t *)malloc(sizeof(link_list_t));
    //健壮性判断
    if(NULL==L)
    {
        puts("申请结点空间失败");
        return NULL;
    }
    //初始化头链表结点
    L->next=NULL;//链表头节点指针域 置NULL 是方便操作单链表
    L->data=-1;//头结点数据不使用,可以赋任意值
    //返回链表头结点首地址
    return L;
}

创建节点演示图

2.对链表进行头部插入操作

当链表创建完成后(本质就是创建了一个头结点),我们可以使用链表对数据进行管理。

1.创建新的链表节点

link_list_t *N=create_linklist();

2.新的链表节点赋值

 N->data=value;

3.进行头部插入操作

link_list_t *q=L;
N->next=q->next;
q->next=N;

头部插入操作图如下:
头部插入示意图

头部插入操作函数源码

int head_insert(link_list_t *L,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //创建新节点
    link_list_t *N=create_linklist();//调用了上述创建节点函数
    //新节点赋值
    N->data=value; //上述图片圈1
    
    //进行头部插入操作
	//建议使用第三方变量来承接传入的表参数,方便保护调用者的数据。
	link_list_t *q=L;
	//先将头结点的指针域赋值给新节点的指针域,将新节点指针域指向链表第一个数据元素。图片圈2
    N->next=q->next; 
    //将头节点的指针域指向新节点的首地址,让头结点的指针域指向改变,指向新节点。图片圈3
    q->next=N; 
    return 0;
}

3.对链表进行遍历操作

遍历链表的思路和算法:
1.前提条件表不为空。
2.遍历从首节点的下一个节点开始。
3.尾结点的指针域为 NULL 其他节点均不为 NULL,我们可以根据尾结点的指针域的特点作为循环遍历结束的条件。
4.设一个指针指向首节点的下一个节点,输出数据域,再将该指针指向下一个节点,按照上述循环操作,直到指针指向节点为NULL停止循环。

	link_list_t *q=L->next;

    while(q!=NULL)
    {
        printf("%d ",q->data);
        q=q->next;
    }

遍历操作图如下:
遍历操作图

遍历操作函数源码

int show_linklist(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空,空链表不需要遍历
    if(L->next==NULL)
    {
        puts("链表为空");
        return -1;
    }
    //遍历链表操作
    link_list_t *q=L->next;//q指向链表头结点的下一个节点

    while(q!=NULL)
    {
        printf("%d ",q->data);//输出指向的数据域 
        q=q->next;//q指向下一个节点
    }
    puts("");
    return 0;
}

通过创建,头插,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        head_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    return 0;
}

结果如下:
结果
因为是头插,最后插入的数据在遍历的时候最先遍历到,从结果可知上述函数无误。

4.对链表进行尾部插入操作

链表的尾部插入思路和算法:

1.创建新节点,初始化新节点。

	link_list_t *N=create_linklist();
	N->data=value;

2.再插入节点前需要先通过循环将q指向最后一个节点。

	while(NULL!=q->next)
    {
        q=q->next;
    }

3.q的指针域t指向新节点的首地址。

	q->next=N;

尾插操作图如下:
尾插演示图

尾插操作函数源码

int tail_insert(link_list_t *L,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    link_list_t *q=L;
    //将q指向最后一个节点
    while(NULL!=q->next)
    {
        q=q->next;
    }
    //创建新节点并赋值
    link_list_t *N=create_linklist();

    N->data=value;
    //尾部插入操作
    q->next=N;
    return 0;
}

通过创建,尾插,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    return 0;
}

结果如下:
尾插演示

5.对链表进行任意位置插入操作(重点)

链表的任意位置插入思路和算法:
1.判断插入位置的合理性

	if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    } 

2.创建新节点并进行赋值

	link_list_t *N=create_linklist();
    N->data=value;

3.找到插入位置的前一个节点

	for(;i<pos-1;i++)//pos=1插入到头结点后第一个位置
    {
        if(NULL!=q->next)
        {
             q=q->next;
        }
        else
        {
            puts("输入的位置不合理");
            return -1;
        }
    }

4.进行插入操作

	N->next=q->next;
    q->next=N;

任意位置插入操作图如下:
任意位置插入操作

任意位置插入操作函数源码

int pos_insert(link_list_t *L,int pos,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //创建新节点并赋值
    link_list_t *N=create_linklist();
    N->data=value;
    //判断插入位置的合法性
    if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    } 
    int i=0;
    link_list_t *q=L;
    //找到待插入位置的前一节点
    for(;i<pos-1;i++)//pos=1插入到头结点后第一个位置
    {
        if(NULL!=q->next)
        {
             q=q->next;
        }
        else
        {
            puts("输入的位置不合理");
            return -1;
        }
    }
    //进行插入操作
    N->next=q->next;
    q->next=N;
    return 0;
}

通过创建,任意插入,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //头插
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
任意插结果

6.对链表进行头部删除操作

链表的头部删除思路和算法:
1.判断链表是否为空

	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }

2.用q指针指向要删除的节点

link_list_t *q=L->next;

3.头部删除操作

	L->next=q->next;
    q->next=NULL;

4.释放删除的节点

	free(q);
    q=NULL;

头部删除操作图如下
头删图

头部删除操作函数源码

int head_delect(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    //q指向要背删除的节点
    link_list_t *q=L->next;
    //头结点指向要被删除的节点的下一个节点
    L->next=q->next;
    //断开要被删除的节点与下一个节点的连接
    q->next=NULL;
    free(q);//释放q指向的空间并置空,防止野指针
    q=NULL;
    return 0;
}

通过创建,头删,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    head_delect(L);
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
头删

7.对链表进行尾部删除操作

链表的尾部删除思路和算法:
1.判断链表是否为空

	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }

2.找到倒数第二个节点

	link_list_t *q=L;
    while(q->next->next!=NULL)
    {
        q=q->next;
    }

3.尾部删除操作

	free(q->next);

4.对q指向的节点next域赋NULL

	q->next=NULL;

尾部删除操作图如下
尾删

尾部删除操作函数源码

int tail_delect(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    link_list_t *q=L;
    //通过循环将q指向倒数第二个节点
    while(q->next->next!=NULL)
    {
        q=q->next;
    }
    //释放q指向的下一个节点也就是尾部节点
    free(q->next);
    q->next=NULL;
    return 0;
}

通过创建,尾删,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    tail_delect(L);
    //head_delect(L);
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
尾删

8.对链表进行任意位置删除操作(重点)

链表的任意位置删除思路和算法:
1.判断表是否为空表

	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }

2.判断输入位置的合法性

	if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    }

3.将q指针指向想要删除节点的上一个节点

 	for(;i<pos-1&&q->next!=NULL;i++)
    {
        q=q->next;
    }
    if(q->next==NULL)
    {
        puts("输入的位置不合理");
        return -1;
    }

4.使用p指向要删除的节点

	link_list_t *p=q->next;

5.使q的next域指向p指向的next域

	q->next=p->next;

6.将p指向的节点next域置空断开连接

	p->next=NULL;

7.释放p指向的节点

	free(p);
    p=NULL;

任意位置删除操作图如下
任意删除

任意位置删除操作函数源码

int pos_delect(link_list_t *L,int pos)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    //判断插入位置的合法性
    if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    }
    link_list_t *q=L;
    int i=0;
    //通过循环进行把q指向要删除位置节点的前一个节点
    for(;i<pos-1&&q->next!=NULL;i++)
    {
        q=q->next;
    }
    //如果q->next==NULL则说明它指向最后一个节点,后面无节点可删除,
    //或者还没走到地方链表就结束了
    if(q->next==NULL)
    {
        puts("输入的位置不合理");
        return -1;
    }
    link_list_t *p=q->next;//将p指向要删除位置的节点
    q->next=p->next;//将p的下一个节点赋给q的next域
    p->next=NULL;//断开p与下一个节点的连接
    free(p);//释放p
    p=NULL;
    return 0;
}

通过创建,任意位置删除,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
任意位置删除

9.对链表进行清空操作

链表的清空思路和算法:
清空所有的数据节点,只保留头节点
1.判断链表是否为空

	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }

2.通过头删和循环结合进行清空操作

	while(q->next!=NULL)
    {
        head_delect(q);
    }

清空操作函数源码

int clear_linklist(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    link_list_t *q=L;
    while(q->next!=NULL)//当首节点next域为空时结束循环
    {
        head_delect(q);//头删函数
    }
    return 0;
}

通过创建,清空,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
清空

10.对链表进行排序操作(重点)

链表的排序思路和算法:
1.判断链表是否为空表或者只要一个节点

 	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    if(NULL==L->next->next)
    {
        puts("链表只有一个节点,无需排序");
        return -1;
    }

2.用指针p指向头节点后下一个节点

	link_list_t *p=L->next;

3.用指针q指向p指向节点的下一个节点

	link_list_t *q=p->next;

4.p指向下一个节点,直到p指向的下一个节点为NULL
5.q指向下一个节点直到q==NULL,表示一趟排序结束,p的数据域保存的就是最小值
6.比较p,q的数据域大小,如果p的数据大于q的数据,进行三杯水交换
7.交换后p指向下一个节点,q指向p的下一个节点

	while(p->next!=NULL)
    {
        //q指向下一个节点直到q==NULL,表示一趟排序结束,p的数据域保存的就是最小值
        while(q!=NULL)
        {
            //比较p,q的数据域大小,如果p的数据大于q的数据,进行三杯水交换
            if(p->data>q->data)
            {
                temp=q->data;
                q->data=p->data;
                p->data=temp;
            }
            q=q->next;
        }
        p=p->next;
        q=p->next;
    }

排序操作图如下
链表排序演示图

排序操作函数源码

int sort_linklist(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    if(NULL==L->next->next)
    {
        puts("链表只有一个节点,无需排序");
        return -1;
    }
    link_list_t *p=L->next;//p指向链表首地址的下一个节点
    link_list_t *q=p->next;//q指向p指向的下一个节点
    int temp;
    //p指向下一个节点,直到p指向的下一个节点为NULL
    while(p->next!=NULL)
    {
        //q指向下一个节点直到q==NULL,表示一趟排序结束,p的数据域保存的就是最小值
        while(q!=NULL)
        {
            //比较p,q的数据域大小,如果p的数据大于q的数据,进行三杯水交换
            if(p->data>q->data)
            {
                temp=q->data;
                q->data=p->data;
                p->data=temp;
            }
            q=q->next;
        }
        p=p->next;
        q=p->next;
    }
    return 0;
}

通过创建,排序,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    sort_linklist(L);//链表排序
    //clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
排序结果

11.对链表进行翻转操作(重点)

链表的翻转思路和算法:
1.判断链表是否为空或者只有一个节点

	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    if(NULL==L->next->next)
    {
        puts("链表只有一个节点,无需翻转");
        return -1;
    }

2.定义一个q指向头节点之后的第二个节点,定义一个p节点指向q的后一个节点,以防头插的时候链表丢失

	link_list_t *q=L->next->next;
	link_list_t *p=NULL;

3.将头节点后一个节点的next域置空,断开连接,变成两个链表

	L->next->next=NULL;

4.将q指向的链表头节点进行头部插入进入原链表中,q指向后一个节点
5.重复第4步直到q==NULL

	while(q!=NULL)
    {
        p=q->next;
        q->next=L->next;
        L->next=q;
        q=p;
    }

翻转操作图如下
翻转示意图

翻转操作函数源码

int overturn_linklist(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    //判断链表是否只有一个节点
    if(NULL==L->next->next)
    {
        puts("链表只有一个节点,无需翻转");
        return -1;
    }
    //定义一个q指向头节点之后的第二个节点,
    //定义一个p节点指向q的后一个节点,以防头插的时候链表丢失
    link_list_t *q=L->next->next;
    L->next->next=NULL;//将头节点后一个节点的next域置空,断开连接,变成两个链表
    link_list_t *p=NULL;

    while(q!=NULL)
    {
        //p指向q后一个节点,将q指向的链表头节点进行头部插入进入原链表中,再将q指向p
        p=q->next;
        q->next=L->next;
        L->next=q;
        q=p;
    }
    return 0;
}

通过创建,翻转,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    overturn_linklist(L);//链表翻转
    //sort_linklist(L);//链表排序
    //clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
翻转结果

12.对两个链表进行合并操作

链表的合并思路和算法:
1.用循环将q指向链表最后一个节点

	while(q->next!=NULL)
    {
        q=q->next;
    }

2.将最后一个节与另一个链表头结点后一位进行连接

	q->next=(*L1)->next;

3.释放头结点

	free(*L1);
    (*L1)=NULL;

合并操作图如下
链表合并示意图

合并操作函数源码

int merge_linklist(link_list_t *L,link_list_t **L1)
{
    //健壮性判断
    if(NULL==L||NULL==L1||NULL==*L1)
    {
        puts("传入参数非法");
        return -1;
    }

    link_list_t *q=L;
    //将q指向链表最后一个节点
    while(q->next!=NULL)
    {
        q=q->next;
    }
    //将最后一个节与另一个链表头结点后一位进行连接
    q->next=(*L1)->next;
    //释放头结点
    free(*L1);
    (*L1)=NULL;
    return 0;
}

通过创建,合并,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    //创建链表头结点
    link_list_t *L1=create_linklist();
    //健壮性判断
    if(NULL==L1)
    {
        puts("创建链表失败");
        return -1;
    }
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L1,i);
    }
    show_linklist(L1);
    merge_linklist(L,&L1);//合并链表
    //overturn_linklist(L);//链表翻转
    //sort_linklist(L);//链表排序
    //clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
在这里插入图片描述

13.对链表进行查找数据操作

链表的查找数据思路和算法:
1.判断链表是否为空

	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }

2.对链表节点数据进行遍历

while(q->next!=NULL)
    {
        i++;
        if(q->data==value)
        {
            printf("%d在链表第%d位\n",q->data,i);
            return 0;
        }
        q=q->next;
    }
    printf("数据在表中不存在\n");
    return -1;

查找数据操作函数源码

int find_insert(link_list_t *L,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    link_list_t *q=L->next;
    int i=0;
    //遍历查找数据
    while(q->next!=NULL)
    {
        i++;
        if(q->data==value)
        {
            printf("%d在链表第%d位\n",q->data,i);
            return 0;
        }
        q=q->next;
    }
    printf("数据在表中不存在\n");
    return -1;
}

通过创建,查找数据,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    //创建链表头结点
    /*link_list_t *L1=create_linklist();
    //健壮性判断
    if(NULL==L1)
    {
        puts("创建链表失败");
        return -1;
    }*/
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    /*while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L1,i);
    }*/
    find_insert(L,3);//对3进行查找
    find_insert(L,100);//对100进行查找
    //show_linklist(L1);//遍历链表
    //merge_linklist(L,&L1);//合并链表
    //overturn_linklist(L);//链表翻转
    //sort_linklist(L);//链表排序
    //clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    //show_linklist(L);//遍历链表
    return 0;
}

结果如下:
查找数据结果

14.对链表进行按照位置修改节点数据操作

链表的按照位置修改数据思路和算法:
1.判断链表是否为空和输入的位置参数是否正确

	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    }

2.使q指向需要修改的节点位置

for(;i<pos;i++)
    {
        if(q->next!=NULL)
        {
            q=q->next;
        }
        else
        {
            puts("输入位置参数错误");
            return -1;
        }
    }

3.将要修改的值赋给想要修改位置所指的数据域

	q->data=value;

按照位置修改数据操作函数源码

int pos_revise_linklist(link_list_t *L,data_t pos,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空和输入的位置参数是否正确
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    }
    int i=0;
    link_list_t *q=L;
    //使q指向需要修改的节点位置
    for(;i<pos;i++)
    {
        //如果q指向节点的next域为NULL说明位于最后一个节点不能进行偏移操作
        //否则超越了链表,说明位置参数错误
        if(q->next!=NULL)
        {
            q=q->next;
        }
        else
        {
            puts("输入位置参数错误");
            return -1;
        }
    }
    //将要修改的值赋给想要修改位置所指的数据域
    q->data=value;
    return 0;
}

通过创建,按位置修改数据,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    //创建链表头结点
    /*link_list_t *L1=create_linklist();
    //健壮性判断
    if(NULL==L1)
    {
        puts("创建链表失败");
        return -1;
    }*/
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    pos_revise_linklist(L,3,3);//对3位置上的数据进行修改,修改为3
    /*while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L1,i);
    }*/
    //find_insert(L,3);//在链表中对3数据进行查找
    //find_insert(L,100);//在链表中对100数据进行查找
    //show_linklist(L1);//遍历链表
    //merge_linklist(L,&L1);//合并链表
    //overturn_linklist(L);//链表翻转
    //sort_linklist(L);//链表排序
    //clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
按照位置修改链表数据结果图

15.对链表进行按照值修改节点数据操作

链表的按照值修改数据思路和算法:
1.判断该链表是否为空

	if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }

2.遍历该链表节点的值,如果找到节点数据域值与data值相同,则进行对该节点修改操作

while(q->next!=NULL)
    {
        q=q->next;
        if(q->data==data)
        {
            q->data=value;
            flag=1;
        }
    }

3.定义一个标号为flag=0,如果进行了修改操作则flag=1,否则没有找到该data值

	int flag=0;
	
	if(flag==0)
    {
        puts("没有找到该值");
    }

按照值修改数据操作函数源码

int data_revise_linklist(link_list_t *L,data_t data,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    link_list_t *q=L;
    int flag=0;//标号判断是否找到该data值
    
    while(q->next!=NULL)
    {
        q=q->next;//q指向头结点后下一个节点
        //如果q指向的数据域等于搜索的data值
        //则将该data值重新赋值为value
        if(q->data==data)
        {
            q->data=value;
            flag=1;//赋值后将标号置1
        }
    }
    //如果标号还为0,则代表没有找到data值,无法进行修改
    if(flag==0)
    {
        puts("没有找到该值");
    }
    return 0;
}

通过创建,按值修改数据,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    //创建链表头结点
    /*link_list_t *L1=create_linklist();
    //健壮性判断
    if(NULL==L1)
    {
        puts("创建链表失败");
        return -1;
    }*/
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    data_revise_linklist(L,4,3);//对值为4的数据进行修改,修改为3
    //pos_revise_linklist(L,3,3);//对3位置上的数据进行修改,修改为3
    /*while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L1,i);
    }*/
    //find_insert(L,3);//在链表中对3数据进行查找
    //find_insert(L,100);在链表中对100数据进行查找
    //show_linklist(L1);//遍历链表
    //merge_linklist(L,&L1);//合并链表
    //overturn_linklist(L);//链表翻转
    //sort_linklist(L);//链表排序
    //clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    return 0;
}

结果如下:
按值修改数据结果

16.对链表进行释放操作

链表的释放思路和算法:
1.定义一个节点指针变量 q 作为引导动点 初始化为 头结点的指向

	link_list_t *q=*L;

2.q变量作为动点开始移动到下一个位置

	q=q->next;

3.将头结点*L指向的节点释放掉

	q=q->next;

4.使*L重新指向q

	*L=q;

释放操作函数源码

int free_linklist(link_list_t **L)
{
    //健壮性判断
    if(NULL==L||NULL==*L)
    {
        puts("传入参数非法");
        return -1;
    }
    link_list_t *q=*L;
    //当 *L == NULL时释放结束
    while(*L!=NULL)
    {
        q=q->next;
        printf("%d即将被释放\n",(*L)->data);
        free(*L);
        *L=q;
    }
    *L=NULL;
    return 0;
}

通过创建,释放,遍历进行验证代码
主函数如下:

int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    //创建链表头结点
    /*link_list_t *L1=create_linklist();
    //健壮性判断
    if(NULL==L1)
    {
        puts("创建链表失败");
        return -1;
    }*/
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    //show_linklist(L);
    //data_revise_linklist(L,4,3);//对值为4的数据进行修改,修改为3
    //pos_revise_linklist(L,3,3);//对3位置上的数据进行修改,修改为3
    /*while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L1,i);
    }*/
    //find_insert(L,3);//在链表中对3数据进行查找
    //find_insert(L,100);在链表中对100数据进行查找
    //show_linklist(L1);//遍历链表
    //merge_linklist(L,&L1);//合并链表
    //overturn_linklist(L);//链表翻转
    //sort_linklist(L);//链表排序
    //clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    free_linklist(&L);
    return 0;
}

结果如下:
释放结果

在图中 -1被释放是因为头节点数据域初始化为-1,释放链表时头节点也被释放,结果是正确的

三、源代码

1.link_list.h

#ifndef __LINK_LIST_H__
#define __LINK_LIST_H__

typedef int data_t;
typedef struct node{
    data_t data; //数据域 不一定是int也可以是自己封装的结构体
    struct node *next;//指针域
}link_list_t;

//创建节点
link_list_t *create_linklist(void);
//头部插入
int head_insert(link_list_t *L,data_t value);
//遍历链表
int show_linklist(link_list_t *L);
//尾部插入
int tail_insert(link_list_t *L,data_t value);
//按位置插入
int pos_insert(link_list_t *L,int pos,data_t value);
//头部删除
int head_delect(link_list_t *L);
//尾部删除
int tail_delect(link_list_t *L);
//按任意位置删除
int pos_delect(link_list_t *L,int pos);
//清空链表
int clear_linklist(link_list_t *L);
//链表排序
int sort_linklist(link_list_t *L);
//翻转链表
int overturn_linklist(link_list_t *L);
//合并链表
int merge_linklist(link_list_t *L,link_list_t **L1);
//查找链表
int find_insert(link_list_t *L,data_t value);
//按照位置修改链表数据
int pos_revise_linklist(link_list_t *L,data_t pos,data_t value);
//按照值修改链表数据
int data_revise_linklist(link_list_t *L,data_t data,data_t value);
//释放链表
int free_linklist(link_list_t **L);

#endif

2.link_list.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "link_list.h"
//创建节点
link_list_t *create_linklist(void)
{
    //从堆区申请头结点空间
    link_list_t *L=(link_list_t *)malloc(sizeof(link_list_t));
    //健壮性判断
    if(NULL==L)
    {
        puts("申请结点空间失败");
        return NULL;
    }
    //初始化头链表结点
    L->next=NULL;
    //头结点数据不使用,可以赋任意值
    L->data=-1;
    //返回链表头结点首地址
    return L;
}
//头部插入
int head_insert(link_list_t *L,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //创建新节点
    link_list_t *N=create_linklist();//调用了上述创建节点函数
    //新节点赋值
    N->data=value;
    //进行头部插入操作
    link_list_t *q=L;
    N->next=q->next;
    q->next=N;
    return 0;
}
//遍历链表
int show_linklist(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空,空链表不需要遍历
    if(L->next==NULL)
    {
        puts("链表为空");
        return -1;
    }
    //遍历链表操作
    link_list_t *q=L->next;//q指向链表头结点的下一个节点

    while(q!=NULL)
    {
        printf("%d ",q->data);//输出指向的数据域 
        q=q->next;//q指向下一个节点
    }
    puts("");
    return 0;
}
//尾部插入
int tail_insert(link_list_t *L,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    link_list_t *q=L;
    //将q指向最后一个节点
    while(NULL!=q->next)
    {
        q=q->next;
    }
    //创建新节点并赋值
    link_list_t *N=create_linklist();

    N->data=value;
    //尾部插入操作
    q->next=N;
    return 0;
}
//按位置插入
int pos_insert(link_list_t *L,int pos,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //创建新节点并赋值
    link_list_t *N=create_linklist();
    N->data=value;
    //判断插入位置的合法性
    if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    } 
    int i=0;
    link_list_t *q=L;
    //找到待插入位置的前一节点
    for(;i<pos-1;i++)//pos=1插入到头结点后第一个位置
    {
        if(NULL!=q->next)
        {
             q=q->next;
        }
        else
        {
            puts("输入的位置不合理");
            return -1;
        }
    }
    //进行插入操作
    N->next=q->next;
    q->next=N;
    return 0;
}
//头部删除
int head_delect(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    //q指向要背删除的节点
    link_list_t *q=L->next;
    //头结点指向要被删除的节点的下一个节点
    L->next=q->next;
    //断开要被删除的节点与下一个节点的连接
    q->next=NULL;
    free(q);//释放q指向的空间并置空,防止野指针
    q=NULL;
    return 0;
}
//尾部删除
int tail_delect(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    link_list_t *q=L;
    //通过循环将q指向倒数第二个节点
    while(q->next->next!=NULL)
    {
        q=q->next;
    }
    //释放q指向的下一个节点也就是尾部节点
    free(q->next);
    q->next=NULL;
    return 0;
}
//按任意位置删除
int pos_delect(link_list_t *L,int pos)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    //判断插入位置的合法性
    if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    }
    link_list_t *q=L;
    int i=0;
    //通过循环进行把q指向要删除位置节点的前一个节点
    for(;i<pos-1&&q->next!=NULL;i++)
    {
        q=q->next;
    }
    //如果q->next==NULL则说明它指向最后一个节点,后面无节点可删除,
    //或者还没走到地方链表就结束了
    if(q->next==NULL)
    {
        puts("输入的位置不合理");
        return -1;
    }
    link_list_t *p=q->next;
    q->next=p->next;
    p->next=NULL;
    free(p);
    p=NULL;
    return 0;
}
int clear_linklist(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    link_list_t *q=L;
    while(q->next!=NULL)//当首节点next域为空时结束循环
    {
        head_delect(q);//头删函数
    }
    return 0;
}
//链表排序
int sort_linklist(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    if(NULL==L->next->next)
    {
        puts("链表只有一个节点,无需排序");
        return -1;
    }
    link_list_t *p=L->next;//p指向链表首地址的下一个节点
    link_list_t *q=p->next;//q指向p指向的下一个节点
    int temp;
    //p指向下一个节点,直到p指向的下一个节点为NULL
    while(p->next!=NULL)
    {
        //q指向下一个节点直到q==NULL,表示一趟排序结束,p的数据域保存的就是最小值
        while(q!=NULL)
        {
            //比较p,q的数据域大小,如果p的数据大于q的数据,进行三杯水交换
            if(p->data>q->data)
            {
                temp=q->data;
                q->data=p->data;
                p->data=temp;
            }
            q=q->next;
        }
        p=p->next;
        q=p->next;
    }
    return 0;
}
//翻转链表
int overturn_linklist(link_list_t *L)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    //判断链表是否只有一个节点
    if(NULL==L->next->next)
    {
        puts("链表只有一个节点,无需翻转");
        return -1;
    }
    //定义一个q指向头节点之后的第二个节点,
    //定义一个p节点指向q的后一个节点,以防头插的时候链表丢失
    link_list_t *q=L->next->next;
    L->next->next=NULL;//将头节点后一个节点的next域置空,断开连接,变成两个链表
    link_list_t *p=NULL;

    while(q!=NULL)
    {
        //p指向q后一个节点,将q指向的链表头节点进行头部插入进入原链表中,再将q指向p
        p=q->next;
        q->next=L->next;
        L->next=q;
        q=p;
    }
    return 0;
}
//合并链表
int merge_linklist(link_list_t *L,link_list_t **L1)
{
    //健壮性判断
    if(NULL==L||NULL==L1||NULL==*L1)
    {
        puts("传入参数非法");
        return -1;
    }

    link_list_t *q=L;
    //将q指向链表最后一个节点
    while(q->next!=NULL)
    {
        q=q->next;
    }
    //将最后一个节与另一个链表头结点后一位进行连接
    q->next=(*L1)->next;
    //释放头结点
    free(*L1);
    (*L1)=NULL;
    return 0;
}
//查找链表
int find_insert(link_list_t *L,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    link_list_t *q=L->next;
    int i=0;
    //遍历查找数据
    while(q->next!=NULL)
    {
        i++;
        if(q->data==value)
        {
            printf("%d在链表第%d位\n",q->data,i);
            return 0;
        }
        q=q->next;
    }
    printf("数据在表中不存在\n");
    return -1;
}
//按照位置修改链表数据
int pos_revise_linklist(link_list_t *L,data_t pos,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空和输入的位置参数是否正确
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    if(pos<1)
    {
        puts("输入的位置不合理");
        return -1;
    }
    int i=0;
    link_list_t *q=L;
    //使q指向需要修改的节点位置
    for(;i<pos;i++)
    {
        //如果q指向节点的next域为NULL说明位于最后一个节点不能进行偏移操作
        //否则超越了链表,说明位置参数错误
        if(q->next!=NULL)
        {
            q=q->next;
        }
        else
        {
            puts("输入位置参数错误");
            return -1;
        }
    }
    //将要修改的值赋给想要修改位置所指的数据域
    q->data=value;
    return 0;
}
//按照值修改链表数据
int data_revise_linklist(link_list_t *L,data_t data,data_t value)
{
    //健壮性判断
    if(NULL==L)
    {
        puts("传入参数非法");
        return -1;
    }
    //判断链表是否为空
    if(NULL==L->next)
    {
        puts("链表为空");
        return -1;
    }
    link_list_t *q=L;
    int flag=0;//标号判断是否找到该data值
    
    while(q->next!=NULL)
    {
        q=q->next;//q指向头结点后下一个节点
        //如果q指向的数据域等于搜索的data值
        //则将该data值重新赋值为value
        if(q->data==data)
        {
            q->data=value;
            flag=1;//赋值后将标号置1
        }
    }
    //如果标号还为0,则代表没有找到data值,无法进行修改
    if(flag==0)
    {
        puts("没有找到该值");
    }
    return 0;
}
//释放链表
int free_linklist(link_list_t **L)
{
    //健壮性判断
    if(NULL==L||NULL==*L)
    {
        puts("传入参数非法");
        return -1;
    }
    link_list_t *q=*L;
    while(*L!=NULL)
    {
        q=q->next;
        printf("%d即将被释放\n",(*L)->data);
        free(*L);
        *L=q;
    }
    *L=NULL;
    return 0;
}

3.main.c

#include "link_list.c"


int main(int argc,const char * argv[])
{
    int i;
    //创建链表头结点
    link_list_t *L=create_linklist();
    //健壮性判断
    if(NULL==L)
    {
        puts("创建链表失败");
        return -1;
    }
    //创建链表头结点
    /*link_list_t *L1=create_linklist();
    //健壮性判断
    if(NULL==L1)
    {
        puts("创建链表失败");
        return -1;
    }*/
    while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L,i);
    }
    //遍历链表
    show_linklist(L);
    data_revise_linklist(L,4,3);//对值为4的数据进行修改,修改为3
    //pos_revise_linklist(L,3,3);//对3位置上的数据进行修改,修改为3
    /*while(1)
    {
        //头插法输入数据,当输入-1时结束循环
        scanf("%d",&i);
        if(i==-1)
        {
            break;
        }
        //head_insert(L,i);
        //尾部插入
        tail_insert(L1,i);
    }*/
    //find_insert(L,3);//在链表中对3数据进行查找
    //find_insert(L,100);在链表中对100数据进行查找
    //show_linklist(L1);//遍历链表
    //merge_linklist(L,&L1);//合并链表
    //overturn_linklist(L);//链表翻转
    //sort_linklist(L);//链表排序
    //clear_linklist(L);//清空链表
    //pos_delect(L,3);//第三个位置节点删除
    //tail_delect(L);//尾删
    //head_delect(L);//头删
    //pos_insert(L,3,3);//第三个位置插入3
    show_linklist(L);//遍历链表
    free_linklist(&L);
    return 0;
}
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2022-08-06 11:07:37  更:2022-08-06 11:12:13 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/25 21:38:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码