单链表的创建、删除、反转、插入、排序操作
文章目录
1.1 链表引言
在初学链表时很多人会问,什么是链表,链表怎么实现,原理是什么?的确带着问题学习会让你变得更快,链表可以简单理解为老师领着幼儿园小朋友过马路,他们手拉手牵着一起,老师在最前面领着后面的小朋友,老师就是这个领头人(链表的头节点),每一个小朋友可以看做一个节点。
1.2 单链表节点的数据结构
单链表的节点数据根据自己的需要自行设置,但是数据中必然存在一个指针,而且指针类型为本数据类型,本文为了展示出其相关操作的原理,因此节点的数据定义相对简单。
/*链表的节点结构定义*/
typedef struct list_node {
int data;
struct list_node *next;
}list_node;
1.3 创建链表
创建链表需要自定义一个函数,指定链表头,应该创建几个节点,每个节点的数据自行输入所以进行如下定义。使用whlie语句进行创建几个节点的判断,并且对每一个节点进行动态分配空间,通过scanf输入数据。当知道有几个小朋友需要连接老师(头节点)时就很容易知道,老师的下一个牵手的应该是一个小朋友,而最后一个小朋友没有东西牵着,所以为NULL。
int creat_list(list_node *head,int n)
{
if(head!=NULL&&n>0)
{
list_node *p=head;
int input_data;
while(n>0)
{
p->next=(list_node *)malloc(sizeof (list_node));
printf("please input data:\n");
scanf("%d",&input_data);
p->next->data=input_data;
p=p->next;
n--;
head->data++;
}
p->next=NULL;//链表的尾部节点下个指向为空,理解最后一个小朋友没东西牵着
return 0;
}
else
{
printf("输入创建链表参数出错:\n");
return -1;
}
}
1.4 打印整个链表
打印链表实现相对简单,相当于老师牵着小朋友,让每个小朋友进行报数,当到最后一个小朋友时牵着为空气,报数完毕,所以判断条件就是当下一个指针指向为空的时候停止遍历链表。
/*打印整个链表*/
void print_list(list_node *head)
{
if(head!=NULL)
{
printf("sum node %d\n",head->data);
list_node *p=head->next;
while(p!=NULL)
{
printf("~~~~~~~~~~~%d\n",p->data);
p=p->next;
}
}
}
1.5 链表插入数据
链表插入的函数,指定要插入的链表的头节点,插入的位置,需要插入的数据。插入的原理如下图:假设在1号和2号之间需要插入一个小朋友,首先应该报数,当一号报数完毕后,我们知道了应该在此插入,然后停下操作,先创建一个节点空间,然后把小朋友(节点数据)放进这个空间,新插入的小朋友应该是一边被一号牵着,另一边牵着2号。
/*第一个参数指定链表头,第二参数在哪一个位置之后插入值*/
void insert_data(list_node *head,int data,int n)
{
if(n<0||head->data<n||head==NULL)
{
printf("插入参数出错\n");
}
else
{
list_node *p=head->next;
list_node *pre=head;
while(n>0)//此处相当于先报数
{
pre=p;
p=p->next;
n--;
}
list_node *new_node=(list_node *)malloc(sizeof (list_node));
new_node->data=data;
new_node->next=p; //此处对应红色解释图
pre->next=new_node;
head->data++;
}
}
1.6 删除某一个节点
删除某一个节点,也是需要知道链表的表头,和删除第几个节点,原理和插入类似,如下图所示:
void delete_data(list_node *head,int n)
{
if(n<=0||head==NULL)
{
printf("输入参数错误");
return;
}
else
{
list_node *pre=NULL;
list_node *current=head;
list_node *next=head->next;
while(n>0)
{
pre=current;
current=next;
next=next->next;
n--;
}
pre->next=next;
free(current);
}
}
1.7 删除整个链表
删除整个链表可不是直接free表头就行了,要一个个遍历整个链表,然后记录前一个指针的位置进行一个一个free,原理和删除一个类似,这里直接上代码。
/*对整个链表进行删除*/
void delete_list(list_node *head)
{
if(head!=NULL)
{
list_node *pre=NULL;
list_node *current=head;
list_node *next=head->next;
while(current!=NULL)
{
pre=current;
current=next;
next=next->next;
free(pre);
}
free(current);
}
else
{
printf("链表已经为空\n");
}
}
1.8 链表的反转
这个相对来说难一点,但是理解原理之后还是很容易的,有点类似于排序,但是有点区别。
反转一步一步的过程应该是这样,也有其他方法,自己查一下。
head->1->2->3->4->5
--------------------------------------原始链表
head->2->1->3->4->5
---------------------------------------第一步
head->3->2->1->4->5
---------------------------------------第二步
head->4->3->2->1->5
---------------------------------------第三步
head->5->4->3->2->1
---------------------------------------第四步
也就是相当于,每次把遍历到的当前数据提到最前面。
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
/*链表的反转*/
void reversal_list(list_node *head)
{
if(head!=NULL)
{
list_node *current=head->next;
list_node *next=current->next;
while(next!=NULL)
{
current->next=next->next;
next->next=head->next;
head->next=next;
next=current->next;
}
}
else
{
printf("链表为空\n");
}
}
1.9 链表的排序
此次链表的排序使用的是选择排序,相对简单,使用冒泡等也能实现,简单讲一下冒泡的原理:
head->1->2->3->4
--------------------------------------原始链表
head->4->2->3->1
---------------------------------------第一步
head->4->3->2->1
---------------------------------------第二步
就是进行先让第一个数和之后的每一个数比较,只要遇到比他大的就和第一个位置交换数据,然后第一个位置就是最大的数据,之后让第二位与之后的每一个数据比较只要比他大的数就交换位置,…一直这么结束,排序完成。
/*使用选择排序*/
void list_sort(list_node *head)
{
/*头节点的data用来存储总共有多少节点*/
if(head==NULL)
return;
int i=0;
int k=0;
list_node *p=head->next;
for(i=0;i<head->data-1;i++)
{
list_node *s=p->next;
for(k=i+1;k<head->data;k++)
{
if((s->data)<(p->data))
{
int tem=p->data;
p->data=s->data;
s->data=tem;
}
s=s->next;
}
p=p->next;
}
}
**持续更新链表的循环链表、双向链表操作**