C语言之单链表逆序

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);
将剩下的结点头插入到链表中,插入后的链表如下所示:
在这里插入图片描述
通过以上分析单链表逆序就完成了,如果对大家有帮助请点个赞支持,谢谢!

  • 10
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值