C语言单链表的逆序重排

	 这是我用来展示单链表逆序所定义的结构体(结点):
`struct node
{
    int data;
    struct node* next;//后继指针
};`

data为整型数据。
初始链表如下:
在这里插入图片描述 这里要特别说明下,在建立单链表时,我个人习惯于建立一个空数据域的头结点(并用指针head指向该头结点)。以上图为例,头结点的data并未被人为赋值,这在后面会导致一个特别的现象。

主要步骤

令head指针向后指向prev(即head->next=prev)

(这里的prev刚开始是被赋空的)(这里指向prev的叙述可能不准确。虽然struct node* prev*,但因为prev此时为空,所以prev此时并不指向任何结点);

再使prev指向此时的头结点(prev=head)

此时头结点(head)已经脱离原链表(如下图):
在这里插入图片描述

接着将指向原头结点的指针head和原指向1结点的指针next后移(head=next;next=head->next)

此时在这里插入图片描述如图所示,指针head已指向1结点,next指向了2结点,原头结点已经被剥离链表。

第一次完整操作至此结束

对剩余四个结点的逆序所需操作也与上述相同,因此是单链表的逆序可以通过循环解决的。以下是循环体代码:

head->next=prev;
 prev=head;
 head=next;
if(head==NULL)
{
    break;
}
next=head->next;

第二次操作后
在这里插入图片描述

第三次操作后
在这里插入图片描述2结点已经被剥离链表

第四次操作后
在这里插入图片描述
此时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 <stdio.h>
#include <stdlib.h>

//从头结点开始将链表节点逆序重组

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

(不打印尾结点)

不当之处,敬请斧正……

大家如果觉得哪些地方我讲得不易懂,可以在评论区留言哦(我经常会强迫自己尽量用专业术语去讲解问题,所以有些地方可能会把大家绕糊涂……)

发布了13 篇原创文章 · 获赞 0 · 访问量 260

猜你喜欢

转载自blog.csdn.net/ZhuhaoNan134/article/details/104583102