单链表的归并算法思路总结
刚在练习的时候需要将两个递增有序的单链表进行归并处理,之前碰到这种问题,心里总是有些害怕,害怕自己不能完全考虑到所有的情况,怕自己想不明白里面的流程,怕自己做不到。。。
但是,我慢慢理解并深以为然的是:越动手去做,越得心应手。
好像应了那句,越努力越幸运。
很多情况下,生活中的其他场景里,我能够很自然,自信的去思考,去行动,但是对应到程序世界里来,就有些畏手畏脚。明明背后的逻辑,需要的领域知识,自己全都能够灵活应用,却偏偏不敢动手写代码。
我不知道你是不是曾经或者现在也有这样的困惑。这花费了我许久的时间去想通。
OK,我们还是主要聊这段代码如何从自然的归并思路平滑转换到代码中。
先看题目:
假设两个递增有序的线性表,均以单链表形式存储。将两个单链表归并为按元素递减次序排列的单链表,并要求:利用原来的结点存储。
#include <iostream>
#include <ctime>
#include <vector>
#include <algorithm>using namespace std;
typedef int ElemType;
#define MAX 100typedef struct Node
{ElemType data;struct Node *next;
}Node, *List;
// 生成一个链表,数值随机生成
// 返回指向生成链表的头结点指针
List generateList(int n)
{srand(n);// 定义头结点List Head = (List)malloc(sizeof(Node));Head->next = NULL;Node *temp = Head; //使用temp拿着L的位置,为的是不改变L的数值// 先通过vector建立一个递增有序的数列vector<int> ins;for(int i = 0; i < n; i++){int x = rand() % MAX;ins.push_back(x);}sort(ins.begin(), ins.end()); //尾插法建立链表for(int i = 0; i < n; i++){Node *s = (Node*)malloc(sizeof(Node));s->data = ins[i];s->next = NULL;temp->next = s; temp = s;}return Head;
}
void mergeList(List &H1, List &H2)
{// 两个递增 ==》 一个递减// 思路:采用头插法进行// 用两个指针p,q分别跟踪// 如果p指向的结点较小,就插入并将p往后移动,否则将q插入并移动// 当一方结点为空了,就将对方的结点依次头插法插入链表直到结束List m = (List)malloc(sizeof(Node));m->next = NULL;Node *p = H1->next;Node *q = H2->next;while(p && q){if(p->data <= q->data){Node *temp = p->next;// 暂存p->next = m->next;m->next = p;p = temp;}else{Node *temp = q->next;q->next = m->next;m->next = q;q = temp;}}while(p){Node *temp = p->next; // 注意一定要用temp暂存,总是会不注意p->next 已经被更改了,从而陷入死循环p->next = m->next;m->next = p;p = temp;}while(q){Node *temp = q->next;q->next = m->next;m->next = q;q = temp;}H1 = m;
}
int main()
{// 两个递增的单链表// 合并成一个递减的单链表// 且为了节省空间,只是修改链接int n,m;cout << "Input two numbers of nodes: ";cin >> n >> m;List H1 = generateList(n);List H2 = generateList(m);Node *p = H1->next; //指向第一个结点while(p){cout << p->data << " ";p = p->next;}cout << endl;Node *q = H2->next; //指向第一个结点while(q){cout << q->data << " ";q = q->next;}cout << endl;// 题目的主要逻辑mergeList(H1,H2); // 返回的是H1指向的合并好的链表// 输出合并后的结果p = H1->next;while(p){cout << p->data << " ";p = p->next;}cout << endl;return 0;
}
如何构建一个单链表这里不会再详细解释,假设已经建好,且如题要求的递增顺序。
这里主要关注的是如何归并。
// 思路:采用头插法进行// 用两个指针p,q分别跟踪// 如果p指向的结点较小,就插入并将p往后移动,否则将q插入并移动// 当一方结点为空了,就将对方的结点依次头插法插入链表直到结束
这段注释其实就完全阐述了如何归并。所以思路非常清晰,转换为代码的过程,就个人体会而言,重点是记住要暂存结点,这是导致写出死循环的一大原因。
首先是:我们新建个头部用于导航合并的链表,结束后把值给H1.
List m = (List)malloc(sizeof(Node));m->next = NULL;Node *p = H1->next;//指向工作结点Node *q = H2->next; //指向工作结点
头插法中p和q都不空的情况:
while(p && q){if(p->data <= q->data){Node *temp = p->next;// 暂存p->next = m->next;m->next = p;p = temp;}else{Node *temp = q->next;q->next = m->next;m->next = q;q = temp;}}
用temp暂存的原因是,,头插法时当前结点p或者q的next域要指向头指向的那个结点。因此,p或q的下一个结点就要被p或q放下了,这个不能忽视,因此,需要暂时存着,p和q跟踪的就是工作结点,他们后面的结点在下一轮就是工作结点了!
而当p或者q其中一个已经为空后,对方还拿着那个没插入的结点,因此在下面的后续处理中,我们只看一种p还没空的状态:
while(p)
{Node *temp = p->next; // 注意一定要用temp暂存,总是会不注意p->next 已经被更改了,从而陷入死循环p->next = m->next;m->next = p;p = temp;
}
此时从p指向的结点开始,一个一个往头结点后面插入即可。注意仍然需要暂存p之后的结点,解释和上面的相同。
到这里,可见归并单链表并不难理解,甚至非常简单自然。
但是,只有当你自己动手做到而不只是看懂然后默念,哦原来这么简单的时候,才是你真正理解掌握的时候。
对,还想分享一段我读来差点哭泣的话,以缅怀那些烦恼的日子,告诫我:烦恼即菩提,心无挂碍,才会安然活在当下,不惊不怖不畏。
“世界上在忧虑的人永远不会是天才或者是庸人,而是介于这两者之间的人。这些人有点儿小聪明,却又不够聪明。不懒,但也不够勤奋。他们就这样在自己的位置上来回走动。这样的人是痛苦的,一生都会活在某种无形的枷锁之中。”
“行动其实就是打开枷锁的钥匙。”
以上,愿有同感的人共勉。
单链表的归并算法思路总结相关推荐
- 有序单链表的归并算法
本算法没有利用L1,L2链表的结点,而是通过复制方式新建L3的所有结点,这样没有破坏原有的L1 和L2单链表. 本算法的实质就是尾插法建立单链表 思路: 1.让两个指针p.q 先指向两个单链表的首结点 ...
- 小白算法积累——单链表13#带头结点单链表+就地归并+改序
题目:假设有两个按元素值递增次序排列的线性表,均以单链表的形式存储.请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来两个单链表的结点存放归并后的单链表. 关键字:带头结点 ...
- c语言递增20,2020-07-20(C语言)数据结构-在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素...
//在一个递增有序的线性表中,有数值相同的元素存在.若存储方式为单链表,设计算法去掉数值相同的元素,使表中不再有重复的元素,例如:(7,10,10,21,30,42,42,51,70)将变为(7,10 ...
- c语言用单链表实现lru算法,利用单链表实现LRU算法
利用单链表实现LRU算法 首先,我们先看下对于Node的定义: package datastructure.linklist.node; import lombok.Data; /** * 单链表节点 ...
- 在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,设计算法,去掉数值相同的元素,使得表中不再有重复的元素。
在一个递增有序的线性表中,有数值相同的元素存在.若存储方式为单链表,设计算法,去掉数值相同的元素,使得表中不再有重复的元素.例如(7,10,10,21,30,42,42,42,51,70)将变为(7, ...
- java数据结构之单链表逆置算法
单链表逆置算法1 设计思想:在链表类中新加成员方法getNode(int i),用来获取指定位置的节点,新建一个空单链表,将原链表的每个节点按照从后往前的顺序依次取出,再把节点的数据依次添加到新的链表 ...
- C语言单链表实现FCFS算法,2014腾讯实习笔试题
2014腾讯实习笔试题 1. 关于二叉树,下面说法正确的是() A. 对于N个节点的二叉树,其高度为nlog2n; B. 一个具有1025个节点的二叉树,其高度范围在11~1025之间 C. 二叉树的 ...
- 单链表的合并算法_图解算法:单链表两两反转 | 眼睛会了手就会系列
一. 序 链表作为一种基本的数据结构,本身理解起来,很简单.它通过指针或者叫引用,将一组零散的内存空间(结点),串联起来组成一个数据存储结构. 链表根据其指针的指向和丰富程度,可以分为单链表.双向链表 ...
- 给定两个单链表,编写算法找出两个单链表的公共结点(暴力解题,优化解题)
算法思想一:暴力解题,设置两个指针p,q,其中q遍历一次单链表,q向后移动一位,直到两个指针指向同一个结点为止. void search(LinkList L, LinkList S){ LNode ...
最新文章
- 怎样实现前端裁剪上传图片功能
- Analysis of the Clustering Properties of the Hilbert Space-Filling Curve 论文笔记
- jwt:token的解析
- Linux时间date与timedatectl
- 14.面向对象-----UML类图
- 通过判断流的头 判断文件类型
- maven 压缩html,使用YUI Compressor Maven插件压缩 js,css 输出war包
- 状态分布函数 详细介绍
- kali linux无线驱动安装,Kali Linux安装 WIFI无线网卡驱动 教程
- 淘宝七天自动确认收货,可以怎么实现?
- 软件版本GA、RC、beta等含义
- rabbit 消息丢失
- TinyOS数据帧与CC2420 Radio Stack解读
- 一句话讲清种子轮、天使轮、ABC轮的区别
- SS14 SS34如何区分正负极
- 【FFmpeg】flv转码测试2: 24fps gop为24 恒定码率
- 「 机器人学 」“Human-aware机器人导航技术”浅谈
- 怎样把ogg格式转换mp3
- Android百度地图屏蔽油站,怎么用android百度地图api获取离当前位置最近的加油站...
- leetcode 分治 beautiful array
热门文章
- 【学习OpenCV4】几何图形的绘制方法
- who i am !
- php ext_skel,用ext_skel为php开发扩展|待更
- php dsn port,PHP的InfluxDB客户端库使用
- 格式notepad自动对齐_6.2 对齐设置
- java有没有友元函数_c++中友元函数理解与使用
- sql 视图不排序_算法工程师SQL进阶:神奇的自连接与子查询
- linux 安装mysql 云盘_linux下 安装mysql教程
- sql关键字_SQL关键字
- 自定义iOS UIPickerView