大家好,我是A导,数据结构系列早在今年二月份我就想着每一章节都出一篇博客介绍《数据结构》相关的知识点和相关代码,之前也干过这件事,后来因为其他种种原因(其实就是我懒)没有更新下来,好不容易到暑假,我准备改过自新,开始更新博客。
文章较长,还请一定仔细看完
开篇
在我们刚学习数据结构这门学科时,最先遇到的就是单链表这个知识,这是最基础的链式存储结构,单链表如果学的迷迷糊糊,那下面的树还有串的学习将十分困难。
下面我们就从单链表开始讲起(文章最后会给出测试代码)
首先,先上一张思维导图,了解单链表需要掌握的操作
1.创建
废话不所说,先上代码
struct node//节点的定义(这里我们使用int数值来作为数据类型!!!!!!!)
{
int num;
struct node* next;
};
struct node* create()//声明创建函数
{
int n,i;
struct node* head;
struct node* p;
p=head=(struct node*)malloc(sizeof(struct node));
printf("请输入链表长度:");
scanf("%d",&n);
for(i=0;i<n;i++)
{
struct node*s=(struct node*)malloc(sizeof(struct node));
scanf("%d",&s->num);
p->next=s;
p=s;
}
p->next=NULL;
head=head->next;
return head;
}
这里代码中比较难理解的就是这一部分
for(i=0;i<n;i++)
{
struct node*s=(struct node*)malloc(sizeof(struct node));
scanf("%d",&s->num);
p->next=s;
p=s;
}
p->next=NULL;
head=head->next;
下面我们画图来讲解这几步
1.首先,我们先要malloc一个内存空间让p和head同时指向这个空间,
struct node* p,head;
p=head=(struct node)malloc(sizeof(struct node));
结果如下图所示
2.然后的for循环中其实就是重复了下列步骤
struct nodes=(struct node)malloc(sizeof(struct node))
这时候就开辟出了一个新的内存区域,使s指针指向当前区域
然后p->next=s;
p=s;
则画图表现为
这样原来的一个节点和新malloc出来的节点就连接在了一起,for循环就是重复这个操作
3.for循环结束之后需要注意p->next=NULL,因为每个链表都要有头有尾,不然在以后遍历的时候会出错
完整的表建完之后应该是这个样子,这就是一个完整的尾插法单链表的创建
2.插入
链表性能的优越性就在它的插入和删除,和传统的数组相比,其插入操作的效率会高出很多。因为数组在插入时需要将插入位置的数据均向后挪一格,腾出一个空间供插入。而链表不需要这样,只需新创建一个节点,然后执行插入操作即可
下面先给出插入操作的代码
struct node* insert(struct node*head)
{
int i,n;
struct node*p=NULL; /*我们这里先假定要插入的位置小于节点数+1;*/
printf("请输入要插入的位置:");
scanf("%d",&n);
struct node*s=(struct node*)malloc(sizeof(struct node));
printf("输入数值:");
scanf("%d",&s->num);
if(n==1)
{
s->next=head;
head=s;
}
else
{
p=head;
for(i=0;i<n-2;i++)
{
p=p->next;
}
s->next=p->next;
p->next=s;
}
return head;
}
单链表的插入大体上有两个点要注意,我们还是就着代码来分析
if(n==1)
{
s->next=head;
head=s;
}
上面的变量创建区域就不再过多赘述
我们首先来看这个if lese语句,为什么这里要有一个if else 语句呢,因为在链表的插入中,在头部插入和在链表中插入,操作是不太相同的.我们还是画图来解释,这样解释的清楚一点
首先我们来看一下在头部插入的过程(就是上面的if语句里代码的可视化)
if(n==1)
s->next=head
则如图
head=s
这里特别注意,在刚开始学习时有人会把head=s写反,写成s=head (早上我在整理代码的时候我自己也写错了,哈哈哈)
的确,新插入了一个节点这时候节点的头就变成s了,所以我们要把head指向s然后将head return回去这是值得注意的一个点
再来要插入的位置在链表中的情况
先找到要插入位置前一个节点(看上面else后面的代码)
s->next=p->next;
则如图
p->next=s;
则如图
这样插入操作就完成了
可能有同学要问了,为社么先连后面再连前面呢?我直接,顺着连,p->next=s,s->next=p->next不就行了.
对于这位同学,只能说你太年轻,没有经理过数据结构的毒打(我就经历过),在链表中,我们只能通过前面一个节点得到下一个节点,当p->next=s之后,p节点就和原来后面的节点断开了,后面的节点就永远找不到了,还谈何连接呢?
3.删除
链表的删除操作和插入操作和删除相较于数组的存储同样具有优越性
还是先上代码
struct node *delet( struct node *head)/*删除节点*/
{
int i,n;
struct node *p;
struct node *s;
p=head;
printf("请输入要删除的节点:");
scanf("%d",&n);
if(n==1)
{
head=head->next;
free(p);
}
else
{
for(i=1;i<n-1;i++)
{
p=p->next;
}
s=p->next;
p->next=s->next;
free(s);
}
return head;
}
删除同插入类似,也要分两种情况,一种是删除的节点在表头,一种在表中
我们先来看删除节点在表头的情况
这是刚开始的情况
if(n==1)
{
head=head->next
free( p );
}
则如图所示
删除的节点在中间的状况就更复杂一点
我们先找到需要删除的前一个节点,让指针p指向这个节点,指针s指向要删除的节点
p->next=s->next;
free(s)
则如图
这样,删除操作就完成了
由于篇幅的限制,这里就不对两种排序进行分解叙述了,因为排序涉及到的内容较多,我会再写一篇博客进行系统的阐述,还是按步骤图解哦!
结束语:
肝了两个晚上,两个下午(也不知道这篇文章是多少头发换来的,哈哈),终于写完了对链表本操作的详解,我本人经受过数据结构的摧残,也深知老师上课讲的是什么鬼东西,书上又跳了多少步骤,所以我在博客中都是按步骤每一步都有图解,致力于让大家能形象化的清楚的领会数据结构的一些精髓,也供大家学习和交流.最后,谢谢各位
(注:转载请注明出处)