1.什么是链表逆序?(本次所使用的链表是包含头结点的链表)
举个例子,有这样的一个链表:
逆序后的链表:
注意:逆序前后的头指针和头结点是一样的。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
//定义链表的数据结构
struct plist
{
int data;
struct plist* next;
};
//定义创建链表结点函数
struct plist* createnode(int data)
{
struct plist* p=(struct plist*)malloc(sizeof(struct plist));
if(NULL==p)
{
printf("malloc failed.\n");
return NULL;
}
memset(p,0,sizeof(struct plist));
p->data=data;
p->next=NULL;
return p;
}
//定义向尾结点插入结点函数
void inserttail(struct plist* ph,struct plist* newnode)
{
int cnt=0;
struct plist* temp=ph;
while(NULL!=temp->next)
{
temp=temp->next;
cnt++;
}
temp->next=newnode;
ph->data+=1;
}
//从链表第一个有效结点前插入结点函数
void inserthead(struct plist* ph,struct plist* newnode)
{
newnode->next=ph->next;
ph->next=newnode;
ph->data+=1;
}
//删除链表结点函数
int deletenode(struct plist* ph,int data)
{
//1.先找到要删除的结点
struct plist* prev=NULL;
struct plist* temp=ph;
while(NULL!=temp->next)
{
prev=temp;
temp=temp->next;
if(data==temp->data)
{
//是尾结点
if(NULL==temp->next)
{
prev->next=NULL;
free(temp);
ph->data-=1;
return 0;
}
//不是尾结点
else
{
prev->next=temp->next;
free(temp);
ph->data-=1;
return 0;
}
}
}
printf("没找到想要删除的结点.\n");
return -1;
}
//定义链表逆序函数
void invert(struct plist *ph)
{
struct plist* temp=ph->next;//指向第一个有效结点
struct plist* pback=NULL;//做备份
if((NULL==temp)||(NULL==temp->next))
{
//说明只有头结点或除了头结点外还有一个有效结点
return ;//不用逆序
}
while(NULL!=temp->next)
{
pback=temp->next;//保存后一个结点地址
//有多个有效结点
if(temp==ph->next)//满足说明该结点是第一个有效结点
{
temp->next=NULL;//逆序之后为NULL
}
else
{
temp->next=ph->next;
}
ph->next=temp;
temp=pback;
}
inserthead(ph,temp);
}
int main()
{
struct plist* pheader=createnode(0);//头指针指向头结点
inserttail(pheader,createnode(1));
inserttail(pheader,createnode(2));
inserttail(pheader,createnode(3));
//插入3个结点完成后(以尾结点插入方式),开始逆序
invert(pheader);
printf("逆序后\n");
while(NULL!=pheader)
{
printf("%d\n",pheader->data);
pheader=pheader->next;
}
return 0;
}
逆序部分代码分析过程如下:
原链表:
程序执行到invert(pheader);
将pheader参数传递给ph,所以此时链表变为如下:
接下来程序开始执行struct plist* temp=ph->next;
将ph—>next的值赋值给temp,所以此时链表变为如下:
接下来程序开始执行struct plist* pback=NULL;
这行代码稍放一下,等下后边会说,在这里讲会很突然,接受不了。
接下来程序开始执行if((NULL==temp)||(NULL==temp->next))
它的意思是以下两种情况链表不逆序:只有头结点或只有一个头结点+一个有效结点时不逆序
接下来程序开始执行while(NULL!=temp->next)
temp->next指向第二个有效结点的首地址,不为NULL成立。可以说明该链表至少含有两个有效结点。
接下来程序执行pback=temp->next;
这里还设计pback,先不管。
接下来程序开始执行if(temp==ph->next)
该句话的目的是判断是不是第一个有效结点,从紧邻的上图中可以看出,ph->next正好指向第一个有效结点,temp也指向第一个有效结点,因此判断成立。
接下来程序开始执行temp->next=NULL;
红色叉断开(temp->next=NULL赋值成功那刻起就断开了,是赋值=使其断开的)。
断开后链表变为
这里解释之前讲的pback部分,如果没有pback那么就意味着第二个有效结点和第三个有效结点地址丢失,因此增加pback目的是保存后边结点的地址。
接下来开始开始执行ph->next=temp;
和temp=pback;
接下来程序开始执行while(NULL!=temp->next)
temp->next指向第三个有效结点的地址,不等于NULL,条件成立。
接下来程序开始执行pback=temp->next;
接下来程序开始执行temp->next=ph->next;
红色叉断开(temp->next=ph->next赋值成功那刻起就断开了,是赋值=使其断开的)。
断开后链表变为
接下来程序开始执行ph->next=temp;
和temp=pback;
将红叉去掉整理后链表变为
再整理如下:
接下来程序执行while(NULL!=temp->next)
temp->next为NULL,所以循环不成立,直接退出循环。
然后程序开始执行inserthead(ph,temp);
将剩下的结点头插入到链表中,插入后的链表如下所示:
通过以上分析单链表逆序就完成了,如果对大家有帮助请点个赞支持,谢谢!