更多系列博文请点击:0-数据结构与算法链接目录

2-6 链表逆序

我只介绍两种常用方法吧,非递归方法 和 递归 方法 我觉得够用就行

1、非递归方法:

第二个元素后面的元素依次插入到头结点后面,

最后再把原始第一个元素放到原始第二个元素后面,整个链表就能够反转了

这个方法对于带不带头结点的链表都适用:

①不带头结点

原始链表,其中第二个元素是 B

A -> B-> C -> D -> E -> F -> null

先进入循环,不断的把B的后继元素往第一个元素后面插

A -> C -> B -> D -> E -> F -> null    #将上面 B后的C 插入到A后面

A -> D -> C -> B -> E -> F -> null    #将上面 B后的 D 插入到A后面

A -> E -> D -> C -> B -> F -> null   #将上面 B后的 E 插入到A后面

A -> F -> E -> D -> C -> -> null   #将上面 B后的 F 插入到A后面

最后将A放到B后面:

F -> E -> D -> C -> B -> A -> null


void Reverse(node **h) {if ((*h) == nullptr)return;else if ((*h)->next == nullptr)return;else {node *r=nullptr, *p1 = (*h), *p2 = (*h)->next;while (p2->next != nullptr) {//由于p2一直固定在原始的第2个元素//所以r一直都是取紧接着原始的第2个元素右侧的那个元素地址r = p2->next;p2->next = r->next;//将r插入到第1个元素后面,这里因为第1个元素的位置P1也不变,所以也很简单r->next = p1->next;p1->next = r;}//最后再来处理原始的第1个元素P1 和 原始的第2个元素P2的顺序p2->next = p1;(*h) =p1->next;p1->next = nullptr;}
}

②带头结点的链表

可以将头结点视为第一个元素,那么就是直接把 A 的后继元素不断的往head后面插:

带头结点原始链表,将头结点视为第1个元素,那么其中第2个元素是 A

Head -> A -> B -> C -> D -> E -> F -> null

先进入循环,不断的把A的后继元素往头结点后面插

Head -> B -> A -> C -> D -> E -> F -> null

Head -> C -> B -> A -> D -> E -> F -> null

Head -> D -> C -> B -> A -> E -> F -> null

Head -> E -> D -> C -> B -> A -> F -> null

Head -> F -> E -> D -> C -> B -> -> null

只不过最后不用将第一个元素放到A后面,也就是不用修改头指针

void Reverse(node *h) {if (h->next == nullptr) {cout << "这是空表!" << endl;return;}else if (h->next->next == nullptr) {cout << "只有一个元素,无需反转!" << endl;return;}else {node *p2 = h->next;//将头结点视为第1个元素,那么数据首节点就视为第2个元素node *r;/*将第二个元素后面的元素依次插入第一个元素后面*/while (p2->next != nullptr) {//由于p2一直固定在原始的第2个元素//所以r一直都是取紧接着原始的第2个元素右侧的那个元素地址r = p2->next;p2->next = r->next;//将r插入到头结点后面r->next = h->next;h->next = r;}//最后与不带头结点的单链表的区别就是,不用修改头指针了}
}

2、递归方法

①不带头结点

递归其实就是一直要找到最后一个结点,然后每次改一下,

这个时候其实 函数递归的时,函数用栈存储了前面每个结点的信息,所以一步一步从最后面改动到前面去,图我也就不画了,

画起来麻烦,可以参考一下这个博文的图,https://blog.csdn.net/fx677588/article/details/72357389,

node* ReverseList_Recursion(node *p) {/*结束的条件:链表为空或者链表最后一个节点*/if (p == nullptr || p->next == nullptr) {return p;}//递归调用node *NewHead = ReverseList_Recursion(p->next);//每次都把当前结点 重新设置成 当前结点的下一个结点的下一个结点p->next->next = p;//然后再把当前结点的新后继设置为空,相当于当前结点时新链表的尾结点p->next = nullptr;return NewHead;
}

要调用此函数的时候,假设已经存在单链表的头指针:list1_h;

直接:node * list_2 = ReverseList_Recursion( list1_h );

这样新的头指针list_2就是反转后的链表的头指针

②带头结点

其实依然可以用上面的函数,只是,

对于带头结点的链表,直接向上面那样 把 头结点的地址作为参数传递进去 是不行的!

因为头结点其实并不是数据元素,数据域的值是随机的,这样直接操作会把头结点最后当做逆序后的尾结点,

另外①中直接返回一个新的头指针,其实就是原来的尾结点的地址,这样一来①中的函数其实是返回了一个以原始尾结点的地址为头指针的 无头结点单链表!

所以我们改一下调用的那行代码,就可以拿来对带头结点的单链表 进行逆序操作了:

list2->next = ReverseList_DG(list2->next)

上面这行代码,是把带头结点的单链表的下一个元素,也就是数据首元素的地址传入了递归函数中!(其实带头结点的单链表不看头结点就是 一个不带头结点的单链表)

然后把返回的 新的地址,又接入到 头结点的后面!

这样就可以在不改变原来头结点 地址 的情况下, 仅对数据部分进行逆序啦。

若有错误,还请不吝指出,谢谢

更多系列博文请点击:0-数据结构与算法链接目录

2-6 链表逆序及其C++实现相关推荐

  1. C语言的单链表逆序和指定范围逆序

    文章目录 前言 逆序 指定范围逆序 源码实现 前言 关于链表的逆置,是考察对链表指针的理解.知道了如何不实用额外空间,同时使用O(n)复杂度对链表进行逆序之后将会对链表有好理解. 同时关于如何在指定范 ...

  2. 单链表逆序生成及逆置的完整实现

    单链表逆序生成及逆置的完整实现 本例中单链表数据类型定义成int型,可更改 头文件1(1.h) 宏定义及Status类型定义 头文件2(2.h) 单链表基本操作函数与逆置函数 include" ...

  3. c语言将一个已知头结点的单链表逆序_C语言数据结构实现链表逆序并输出

    C语言数据结构实现链表逆序并输出 将一个链表逆序并输出.我用了两种方法来实现,第一种是借助了一个新的空链表:第二种是在原来链表的基础上直接实现逆序. 实例代码: 头文件: #include #incl ...

  4. 链表的各种操作实现 链表逆序 链表排序 有序链表归并 链表存在环的判定

    链表的各种操作实现 链表逆序 链表排序 有序链表归并 链表存在环的判定 链表基本操作实现 c语言版本, 该程序在visual c++ 6.0上调试通过! 本人写该程序完全是为学习交流之用,还望大家多多 ...

  5. c语言单链表_C语言笔试题—单链表逆序

    前情回顾 之前更多的是给大家推荐的是好用的软件,经过反思之后觉得这些东西并不是我想要的,所以从今天开始我要转变方向了,更多的往我的专业方向去发展(虽然我是个小白),当然如果有说的不对的地方,希望大家能 ...

  6. 通过迭代(非递归)及递归将单链表逆序

    通过迭代(非递归)及递归将单链表逆序 老生常谈的问题了,不过很多地方面试还是很喜欢问这个问题.实际工程中感觉用处不大,需要逆序的存储为什么要选择单链表呢?为什么不用list(in c++)或itera ...

  7. c语言将一个已知头结点的单链表逆序_C语言实现单链表逆序与逆序输出实例

    单链表的逆序输出分为两种情况,一种是只逆序输出,实际上不逆序:另一种是把链表逆序.本文就分别实例讲述一下两种方法.具体如下: 1.逆序输出 实例代码如下: #include #include #inc ...

  8. 语言print如何实现连续输出_【每日一题】如何实现一个高效的单向链表逆序输出?...

    今后,动力节点Java学院将每天为大家带来一道大厂面试真题,这些面试题都是大厂技术专家们结合多年的工作.面试经验总结提炼而成的面试真题. 通过这些面试题,还可以间接地了解技术大牛们出题思路与考察要点. ...

  9. 链表逆序的原理及实例

    http://blog.csdn.net/wangqing_12345/article/details/51757294 尾插法建立链表,带头结点 设链表节点为 typedef struct node ...

  10. 自定义链表增,删除,链表逆序

    工作时间长了,经常用框架,感觉真的成了coding,建议有时间可以刷一下lettcode 时间一长就会忘,写了大半天,记录一下,理解后再写特别简单,链表逆序看了很多博客,写法各式各样,但是感觉解释的还 ...

最新文章

  1. hibernate 复合主键 根据主键删除_hibernate封装Utils工具类
  2. 工业相机参数之帧率相关知识详解
  3. 学习shell脚本之乘法口诀
  4. 表单绑定 v-model —— :value @input || v-model原理
  5. NG Ng-template(模板元素)
  6. Java实现N元一次方程组求解
  7. 微信小程序请求接口提示Provisional headers are shown
  8. 锐取电视墙服务器型号,锐取录播系统 CL4000系列多媒体录播一体机--投影时代产品专区...
  9. CSS3nbsp;Transitionnbsp;Transformnbsp;Animat…
  10. PHP explode()和implode()的使用方法
  11. 真实测评vivoY30和红米k30哪个好-vivoY30和红米k30区别
  12. UI自动化的po模型
  13. 前端知识零零散散,如何高效学习?
  14. C#设计程序购买商品总金额
  15. 使用多个磁盘分区创建逻辑卷
  16. 乐高幻影忍者推出十周年复刻经典套装;炸鸡大师Popeyes开设首家南京旗舰店 | 美通企业日报...
  17. 单例模式--vold
  18. 获取ContentProvider来获取手机所有的联系人及联系人信息
  19. 专访《硅谷百年史》作者:AI、基因编辑如何在未来10年重塑人类生命形态?
  20. 安装Mathtype 7 在 word2016中,解决Word闪退问题

热门文章

  1. 模仿成功者,才是最快的成功路径
  2. SQL ordered by Elapsed Time
  3. 【mock】anyproxy
  4. 计算机ct检查,影像学检查之三 CT(计算机体层)
  5. Go-ICP: A Globally Optimal Solutionto 3D ICP Point-Set Registration(2016)
  6. MathType有一些字符无法显示
  7. 微信小程序入门与实战学习(笔记一:第一章)
  8. stream.map 和 stream.foreach 的区别
  9. 校招那些坑,是我走过最长的路
  10. Flink教程(18)- Flink阶段总结