链表逆置 C语言

创建所需的相关结构体

struct List
{int date;struct List* next;
};

首先我们创建一个函数用于创建链表的。
建立创建链表的函数

struct List* writeList()
{struct List* head = NULL, * current = NULL, * prev = NULL;int data;while (~scanf("%d", &data) && data != 0)//0为标记输入结束{current = (struct List*)malloc(sizeof(struct List*));if (head == NULL)head = current;elseprev->next = current;current->date = data;current->next = NULL;prev = current;}return head;
}

我们有了链表当然也得有个输出链表内部数据的函数,来验证查看我们链表内的内容。
建立打印链表内容的函数

void printList(struct List* L)
{struct List* p = L;while (p){printf("%d", p->date);p = p->next;}printf("\n");
}

当然链表申请了内存空间我们就得释放内存空间
建立释放内存空间的函数

void freeList(struct List* head)
{struct List* freeNode;while (NULL != head){freeNode = head;head = head->next;free(freeNode);}
}

开始正题。
链表逆置
首先我们要明白什么是链表逆置,链表逆置顾名思义,链表的表头和表位改变,打个比方如果链表就是一列火车的话链表逆置以后火车头变成火车尾,第二节车厢会变成倒数第二节车厢,第三节车厢变成倒数第三节车厢以此类推最后火车尾变成火车头。如图所示:
实现逆置的方法
1.迭代实现逆置
链表迭代逆置的时候需要借助三个指针,这里我们把三个指针定义为bigin,mid,end这三个并让他们分别指向如图所示。
bigen指针指向初始化为空null,mid指针指向初始化为链表头head,end指针指向初始化为第二节点。
准备工作做好了现在就可以开始一个节点一个节点的逆置了。
第一步:mid指针指向的节点的指针域要与begin相同。也就是mid指针指向的节点的指针域变成与begin相同的值null。这样子链表第一节点也就是链表头会和其他节点分离出来。
第二步:每个指针都向后移动一个节点准备逆置下一个节点,也就是说begin指针指向原链表第一节点也就是头节点,mid指针指向原链表第二节点,end指针指向原链表第三节点。
上述步骤可以看下面的解析图。


继续上述操作。
第一步:mid指针指向的节点的指针域要与begin相同也就是指向原链表第一节点原链表的链表头。
第二步:每个指针都向后移动一个节点准备逆置下一个节点。这个时候begin指针指向原链表第二节点,mid指针指向原链表第三节点,end指针指向原链表第四节点。
如图所示:

继续。
第一步:mid指针指向的节点的指针域要与begin相同也就是指向原链表第二节点。
第二步:每个指针都向后移动一个节点准备逆置下一个节点。这个时候begin指针指向原链表第三节点,mid指针指向原链表第四节点,end指针指向原链表第四节点的指针域也就是null。因为原链表已经没有了第五节点所以第四节点就是链表的表尾。
具体步骤解析如图所示。

到了这一步不难发现现在离完成逆置很接近了。接下来我们只需要改变mid指针的指向和head头指针的指向就好了。
第一步:mid指针指向的节点的指针域要与begin相同也就是指向原链表第三节点。
第二步:这一次我们不需要移动begin,mid,end三个指针了,现在我们只需要改变head头指针的指向就好了,head头指针的指向改为和mid指针相同。
以下为解析图:

到了这里我们的链表就已经逆置完毕了,这就是用迭代方法逆置链表。
代码实现如下:
样例代码(C语言):

//迭代逆置法,head 为无头节点链表的头指针
struct List* iteration_reverseList(struct List* head)
{if (head == NULL || head->next == NULL)return head;else{struct List* beg = NULL;struct List* mid = head;struct List* end = head->next;//一直遍历while (1){//mid指针指向节点的指针域要与beg指针指向一样mid->next = beg;//判断 end 是否为 NULL,如果成立则已经找到原链表尾,退出循环if (end == NULL)break;// beg,mid,end三个指针都向后移动一个节点准备逆置下一个节点beg = mid;mid = end;end = end->next;}//最后head头指针的指向改为和mid指针相同。head = mid;return head;}
}

2.递归逆置链表
递归逆置法和迭代逆置法的思想恰好相反,递归逆置法的实现思想是从链表的尾节点开始,依次向前遍历,遍历过程依次改变各节点的指向,即另其指向前一个节点。
递归理解起来要比迭代难一点,我们先附上实现代码,然后一一讲解。
样例代码(C语言):

struct List* recursion_reverseList(struct List* head)
{if (head == NULL || head->next == NULL)  //空链表或者只有一个节点的时候直接返回头指针就好了,因为逆置没有意义。/*当然这个也是我们递归的出口,如果找到最后一个节点的时候开始向外层层退出*/return head;else{//递归内入,原链表被分成多个子链表,直到最后一个节点。最后一个节点也会被分成只有一个链表头的子链表struct List* new_head = recursion_reverseList(head->next);/*在每一层递归中head指针指向的节点的下一个节点的指针域要与head指针指向要相同,这也就是在从子链表拆卸一个节点,接到正在逆置的链表后面。,例如head指向原链表的第二节点,此时第二节点接在原链表的第一节点,经过上面操作以后,原链表第二节点会被接在原链表第三节点后面,实现部分逆置。*///做完上述操作后把当前head指针指向节点的指针域改为null,因为这个是当前我们已经逆置完的节点组成的子链表的链表尾。head->next->next = head;head->next = NULL;return new_head;/*new_head指针保存最后一个节点,也就是原链表尾,并一直向上一层返回,逆置后我们的原链表尾会变成逆置后的链表头,这个就是逆置后的链表头,一直向上返回能保证链表逆置完还能找到新的链表头*/}
}

接下来我们用图去一一分析递归逆置链表的过程。
刚开始函数向内递归链表被切成很多子链表。

现在开始递归向外层,一层一层退出。并进行子链表的逆置衔接。完成逆置。

3头插法逆置链表
头插法比较好理解。在原有链表的基础上,依次将位于链表头部的节点摘下,然后采用从头部插入的方式生成一个新链表,则此链表即为原链表的逆置版。
具体操作如图

代码实现:
样例代码(C语言):

struct List* head_reverse(struct List* head)
{struct List* new_head = NULL;struct List* temp = NULL;//用于临时存储节点if (head == NULL || head->next == NULL)return head;while (head != NULL){temp = head;//将 temp 从 head 中摘除head = head->next;//将 temp 插入到 new_head 的头部temp->next = new_head;new_head = temp;}return new_head;
}

4就地逆置法逆置链表
就地逆置法和头插法的实现思想类似,唯一的区别在于,头插法是通过建立一个新链表实现的,而就地逆置法则是直接对原链表做修改,从而实现将原链表反转。在原链表的基础上做修改,需要额外借助 2 个指针(假设分别为 beg 和 end)。
初始状态下, beg指针 指向第一个节点,end 指针指向 beg->next,也就是原链表的第二节点。如下图:

接下来将 end 所指节点 2 从链表上摘除,然后再添加至当前链表的头部。如图所示。

我们继续上面的操作。

再来一次我们就完成逆置了。

最后我们就完成了链表的逆置。

代码实现:
样例代码(C语言):

struct List* local_reverse(struct List* head)
{struct List* beg = NULL;struct List* end = NULL;if (head == NULL || head->next == NULL)return head;beg = head;end = head->next;while (end != NULL){//将 end 从链表中摘除beg->next = end->next;//将 end 移动至链表头end->next = head;head = end;//调整 end 的指向,另其指向 beg 后的一个节点,为反转下一个节点做准备end = beg->next;}return head;
}

C语言 链表逆置四种方法 超详细相关推荐

  1. 链表逆置(三种方法详解)

    @Achievek 6-1 单链表逆转 (20 point(s)) 本题要求实现一个函数,将给定的单链表逆转. ##函数接口定义: List Reverse( List L ); 其中List结构定义 ...

  2. Python 导入模块的四种方法(超详细)

    使用import调用模块 可以调用第三方库和标准库,以及自己做的,自己做的import+py文件名就可以了,我们使用requests第三方库举例: import requests# #导入reques ...

  3. 链表反转的四种方法(栈、头插法、三指针法、递归法)

    单链表反转或转置的四种方法 链表的反转实质上是反转链表上的内容: 若链表存储的数据是:1->2->3->4->5; 那么反转后则是:5->4->3->2-&g ...

  4. 【51单片机入门】实现流水灯的原理及四种方法(详细易上手型)

    初学单片机,流水灯的实现是必不可少的,下面将介绍流水灯的原理及使用STC-ISP软件延时计算器生成的延时代码实现流水灯的四种方法,最后介绍如何将延时函数模块化. 目录 一.流水灯原理 二.循环 三.移 ...

  5. 无头结点单链表的逆置_解析单链表逆置的多种方法 | 术与道的分享

    单链表的逆置还是很重要的,不过第一次写逆置的时候程序就直接奔溃了,因为解决与链表相关的问题总是有大量的指针操作,而指针操作的代码总是容易出错的,因此这也就成就了单链表在面试中的地位. 1.普通循环逆置 ...

  6. 用C语言求平均数的四种方法

    1. 常规操作 两个数的平均数等于两数之和除以二 int main() {int a = 10;int b = 5;int c = a + b;printf("%d\n", c); ...

  7. Java 实现多线程的四种方式 超详细

    Java 实现多线程的四种方式 文章目录 Java 实现多线程的四种方式 一.继承 Thread 类 二.实现 Runnable 接口 三.实现 Callable 接口 四.线程池 1,Executo ...

  8. CSS清除浮动的五种方法(超详细)

    1.为什么要清除浮动? 浮动的原理是让图片脱离文档流,直接浮在桌面上.我们一般布局的时候都是只设置宽度不设置高度,让内容来自动填充高度.但使用浮动后会让原本填充的高度消失,父元素高度为0,后续添加内容 ...

  9. vue-router传参的四种方式超详细

    vue路由传参的四种方式 一.router-link路由导航方式传参 父组件:<router-link to="/跳转到的路径/传入的参数"></router-l ...

最新文章

  1. 使用OpenCV实现道路车辆计数
  2. 每天学一点flash(71)折纸
  3. 算法每日学打卡:java语言基础题目打卡(01-10)
  4. 让PHP程序永远在后台运行
  5. 轻量级ORM框架 【Dapper】 的使用
  6. 这篇被引用近4k次的论文教你如何正确的理解和使用相关系数!
  7. 维基解密曝CIA 入侵苹果、安卓机、电视,快来围观8761份泄密文
  8. 日志存储 elasticsearch vs clickhouse
  9. pycharm主题设置
  10. go模板引擎生成html,goweb-模板引擎
  11. TensorFlow2.0 学习笔记(四):迁移学习(MobileNetV2)
  12. 3.2-点云配准原理概述
  13. android手写输入法开发,基于Android平台的云计算手写输入法
  14. 潮流能模型matlab,基于matlab的yalmip最优潮流建模的Infeasible problem
  15. 【pyTranscriber】开源免费语音转字幕软件及替代方案
  16. 不使用setPositiveButton 如何让alertdialog消失
  17. 关于阿里云对象存储OSS流量包说明
  18. python画小动物_三分钟识别所有小动物!
  19. 谷歌大牛Jeff Dean是如何成为互联网战神的
  20. Windows无法格式化改卷,改卷已脱机, 请尝试首先向改卷分配驱动器号或路径使其联机

热门文章

  1. 2018年数学建模比赛 智能RGV的动态调度策略思路
  2. 八、SWING程序设计(2)
  3. Pycharm专业版详细安装教程
  4. 中国各省市自治区简称都是什么?_百度知道
  5. 切比雪夫中值定理验证联合概率的收敛性质
  6. SpringBoot具有不受支持的返回值类型
  7. DC-3靶场实战详解
  8. 如何快速的学习一门新的语言
  9. Guitar Pro吉他指弹入门——美式指弹
  10. 阿里云免费ssl证书申请与部署