一、链表
1. 链表的概念
顺序表在内存中开辟空间是连续的,实际开发中这是一种奢望。 在实际开发中无法满足大型数据量的项目,想出一种解决大型数据量的数据操作方法 --> 链表 链表可以解决无法开辟连续空间的问题
链表的逻辑结构:线性结构,一对一 链表的储存结构:链式储存,在内存中储存不一定连续
链表分为有头节点和无头节点的,区别就是头结点是否存储数据。 有头链表现在常用,相较于无头链表浪费了一个节点空间,但是会带来操作上的方便。 还分为单向链表和双向链表,还有循环链表。此次我们着重有头单向链表的操作进行讲解和演示。
2.顺序表(数组)和链表的区别
顺序表: 1.插入和删除数据比较麻烦,需要批量的移动元素 2.按照位置访问元素比较方便,可以通过数组下标操作 3.使用前需要明确最大的长度,对空间使用不够灵活 链表: 1.增删数据比较方便,只需要改变指针的指向即可 2.查找数据比较麻烦,无法通过下标直接获取,只能通过next指针遍历 3.使用前无需确定长度,每次malloc即可,对空间的使用比较灵活
二、链表的相关操作
1. 链表的创建操作
有头链表的创建本质就是创建头结点,我们依然是将链表在堆区创建,头结点数据域不使用,主要使用指针域。
1.1定义节点类型
typedef int data_t;
typedef struct node{
data_t data;
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;
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;
link_list_t *q=L;
N->next=q->next;
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;
while(q!=NULL)
{
printf("%d ",q->data);
q=q->next;
}
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)
{
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;
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)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
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++)
{
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++)
{
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)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
pos_insert(L,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;
}
link_list_t *q=L->next;
L->next=q->next;
q->next=NULL;
free(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)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
head_delect(L);
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;
while(q->next->next!=NULL)
{
q=q->next;
}
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)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
tail_delect(L);
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;
for(;i<pos-1&&q->next!=NULL;i++)
{
q=q->next;
}
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 main(int argc,const char * argv[])
{
int i;
link_list_t *L=create_linklist();
if(NULL==L)
{
puts("创建链表失败");
return -1;
}
while(1)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
pos_delect(L,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)
{
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)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
clear_linklist(L);
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)
{
while(q!=NULL)
{
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;
link_list_t *q=p->next;
int temp;
while(p->next!=NULL)
{
while(q!=NULL)
{
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)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
sort_linklist(L);
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;
}
link_list_t *q=L->next->next;
L->next->next=NULL;
link_list_t *p=NULL;
while(q!=NULL)
{
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)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
overturn_linklist(L);
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;
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)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
while(1)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L1,i);
}
show_linklist(L1);
merge_linklist(L,&L1);
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;
}
while(1)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
find_insert(L,3);
find_insert(L,100);
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;
for(;i<pos;i++)
{
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;
}
while(1)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
pos_revise_linklist(L,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;
while(q->next!=NULL)
{
q=q->next;
if(q->data==data)
{
q->data=value;
flag=1;
}
}
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;
}
while(1)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
data_revise_linklist(L,4,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;
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;
}
while(1)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
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;
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;
while(q!=NULL)
{
printf("%d ",q->data);
q=q->next;
}
puts("");
return 0;
}
int tail_insert(link_list_t *L,data_t value)
{
if(NULL==L)
{
puts("传入参数非法");
return -1;
}
link_list_t *q=L;
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++)
{
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;
}
link_list_t *q=L->next;
L->next=q->next;
q->next=NULL;
free(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;
while(q->next->next!=NULL)
{
q=q->next;
}
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;
for(;i<pos-1&&q->next!=NULL;i++)
{
q=q->next;
}
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)
{
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;
link_list_t *q=p->next;
int temp;
while(p->next!=NULL)
{
while(q!=NULL)
{
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;
}
link_list_t *q=L->next->next;
L->next->next=NULL;
link_list_t *p=NULL;
while(q!=NULL)
{
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;
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;
for(;i<pos;i++)
{
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;
while(q->next!=NULL)
{
q=q->next;
if(q->data==data)
{
q->data=value;
flag=1;
}
}
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;
}
while(1)
{
scanf("%d",&i);
if(i==-1)
{
break;
}
tail_insert(L,i);
}
show_linklist(L);
data_revise_linklist(L,4,3);
show_linklist(L);
free_linklist(&L);
return 0;
}
|