这是我用来展示单链表逆序所定义的结构体(结点):
`struct node
{
int data;
struct node* next;//后继指针
};`
data为整型数据。
初始链表如下:
这里要特别说明下,在建立单链表时,我个人习惯于建立一个空数据域的头结点(并用指针head指向该头结点)。以上图为例,头结点的data并未被人为赋值,这在后面会导致一个特别的现象。
:
(这里的prev刚开始是被赋空的)(这里指向prev的叙述可能不准确。虽然struct node* prev*,但因为prev此时为空,所以prev此时并不指向任何结点);
此时如图所示,指针head已指向1结点,next指向了2结点,原头结点已经被剥离链表。
对剩余四个结点的逆序所需操作也与上述相同,因此是单链表的逆序可以通过循环解决的。以下是循环体代码:
head->next=prev;
prev=head;
head=next;
if(head==NULL)
{
break;
}
next=head->next;
第四次操作后
此时3结点被剥离链表,next指针已经为空,head指针指向原链表的尾结点4.原链表中只剩下了4结点(尾结点)。
易知在连接最后一个结点后,prev指针会指向4结点,head指针被赋空,此时需要跳出循环。所以循环的中止条件是head!=NULL.
最后再来解释一下在循环体条件中加上
if(head==NULL)
{
break;
}
的原因:
当head==NULL,由赋值语句next=head->next知,若再执行该语句,程序会崩溃。
这是未加上述判断语句的循环体:
while(head!=NULL)
{
head->next=prev;
prev=head;
head=next;
next=head->next;//
}
#include
#include
//从头结点开始将链表节点逆序重组
struct node
{
int data;
struct node* next;//后继指针
};
//初始化链表
struct node* creat()
{
int n,i;//n为要创建结点的数目
struct node* move,*prev;//移动指针move,指向前结点的指针prev
struct node*head=NULL;//指向头结点的指针
head=(struct node*)malloc(sizeof(struct node));
head->next=NULL;
prev=head;
scanf("%d",&n);
printf("n=%d\n",n);
//尾插法创建链表
for(i=n;i>0;i--)
{
printf("i=%d ",i);
move=(struct node*)malloc(sizeof(struct node));
printf("number\n");
scanf("%d",&(move->data));
prev->next=move;
move->next=NULL;
prev=move;//这轮创建的结点作为下一轮的prev结点
}
move=head->next;
while(move!=NULL)
{
printf("%d ",move->data);
move=move->next;
}
return(head);
}
//逆序
struct node* reversed_order(struct node* head)
{
struct node* prev=NULL,*next;//tail标记原尾结点
next=head->next;//next指向头结点的下一结点(若有)
while(head!=NULL)
{
head->next=prev;
prev=head;
head=next;
if(head==NULL)
{
break;
}
next=head->next;//
}
return(prev);//prev为新的头结点指针,指向新的头结点
}
int main()
{
struct node* head,*move;
head=creat();
move=reversed_order(head);
printf("\n");
while(move->next!=NULL)//打印逆序后的链表
{
printf("%d ",move->data);
move=move->next;
}
return 0;
}
最后,阐述一下我在本文开头提及的特殊现象。
因为我构造的原链表中有一个空数据的头结点,而在逆序链表时并未释放该结点,所以在逆序完成后,原链表的头结点会成为新链表的尾结点。如果最后打印链表时所用循环是
while(move!=NULL)//打印逆序后的链表
{
printf("%d ",move->data);
move=move->next;
}
程序会把新链表的尾结点中的乱码打印出来。
为了避免这个现象,只需把while循环的终止条件改为
move->next!=NULL
(不打印尾结点)
大家如果觉得哪些地方我讲得不易懂,可以在评论区留言哦(我经常会强迫自己尽量用专业术语去讲解问题,所以有些地方可能会把大家绕糊涂……)