使用插入排序、归并排序对链表进行排序
/*** Definition for singly-linked list.* struct ListNode {* int val;* ListNode *next;* ListNode() : val(0), next(nullptr) {}* ListNode(int x) : val(x), next(nullptr) {}* ListNode(int x, ListNode *next) : val(x), next(next) {}* };*/
插入排序
插入排序的时间复杂度是 O(n^2)
插入排序算法:
- 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
- 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
- 重复直到所有输入数据插入完为止。
ListNode* sortList(ListNode* head) {//使用插入排序if(head == NULL || head->next == NULL) return head;//一个哑结点,方便在head之前插入节点ListNode * dummyHead = new ListNode(0);//哑结点的指向headdummyHead->next = head;//需要排序插入的节点,从第二个节点开始ListNode * curr = head->next;//排好序的最后一个节点,从第一个节点开始ListNode * lastSorted = head;ListNode * prev;while(curr != NULL){//如果需要排序的节点的值大于已经排好序的最后一个值,就指向下一个if(curr->val > lastSorted->val){lastSorted = lastSorted->next;curr = lastSorted->next;}else{//否则就表明当前需要排序的节点需要插入到已经排好序的节点中//需要从头开始,找地方插入prev = dummyHead;//先找到需要插入的地方,需要满足大于等于前一个,小于后一个while(prev->next->val < curr->val){prev = prev->next;}//经过上面的循环,已经找到了一个prev,它满足prev小于curr,并且prev->next大于等于curr,所以curr要插入在prev之后//插入之前要先将curr之后的节点保存起来,存在lastSorted->nextlastSorted->next = curr->next;curr->next = prev->next;prev->next = curr;//lastSorted的下一个节点就是待插入的节点curr = lastSorted->next;} }return dummyHead->next;}
归并排序
时间复杂度是O(nlogn) 的排序算法包括归并排序、堆排序和快速排序(快速排序的最差时间复杂度是 O(n^2),其中最适合链表的排序算法是归并排序。
归并排序基于分治算法。最容易想到的实现方式是自顶向下的递归实现,考虑到递归调用的栈空间,自顶向下归并排序的空间复杂度是O(logn)。如果要达到O(1) 的空间复杂度,则需要使用自底向上的实现方式。
对链表自顶向下归并排序的过程如下。
- 找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 22 步,慢指针每次移动 11 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。
- 对两个子链表分别排序。
- 将两个排序后的子链表合并,得到完整的排序后的链表。
上述过程可以通过递归实现。递归的终止条件是链表的节点个数小于或等于 1,即当链表为空或者链表只包含 1个节点时,不需要对链表进行拆分和排序。
ListNode* sortList(ListNode* head) {return sortList(head, nullptr);}ListNode* sortList(ListNode* head, ListNode* tail) {//如果链表为空,直接返回if (head == nullptr) {return head;}//如果链表只有一个元素,返回该节点,开始融合if (head->next == tail) {head->next = nullptr;return head;}//利用快慢指针找链表的中点,快指针一次跑两步,慢指针一次走一步,当快指针走到尾部时,此时慢指针的位置就是中点ListNode* slow = head, *fast = head;while (fast != tail) {slow = slow->next;fast = fast->next;if (fast != tail) {fast = fast->next;}}ListNode* mid = slow;return merge(sortList(head, mid), sortList(mid, tail));}//合并两个有序链表ListNode* merge(ListNode* head1, ListNode* head2) {ListNode* dummyHead = new ListNode(0);ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;//将两个链表中较小的节点接在哑结点之后while (temp1 != nullptr && temp2 != nullptr) {if (temp1->val <= temp2->val) {temp->next = temp1;temp1 = temp1->next;} else {temp->next = temp2;temp2 = temp2->next;}temp = temp->next;}//接完了较短的链表,较长的链表还有剩余,将剩余的全部接上if (temp1 != nullptr) {temp->next = temp1;} else if (temp2 != nullptr) {temp->next = temp2;}return dummyHead->next;}
使用自底向上的方法实现归并排序,则可以达到 O(1) 的空间复杂度。
首先求得链表的长度}length,然后将链表拆分成子链表进行合并。
具体做法如下。
- 用subLength 表示每次需要排序的子链表的长度,初始时subLength=1。
- 每次将链表拆分成若干个长度为subLength 的子链表(最后一个子链表的长度可以小于
- subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。
- 将subLength 的值加倍,重复第 2 步,对更长的有序子链表进行合并操作,直到有序子链表的长度大于或等于length,整个链表排序完毕。
ListNode* sortList(ListNode* head) {if (head == nullptr) {return head;}int length = 0;ListNode* node = head;//先求出链表有多长while (node != nullptr) {length++;node = node->next;}ListNode* dummyHead = new ListNode(0, head);for (int subLength = 1; subLength < length; subLength <<= 1) {ListNode* prev = dummyHead, *curr = dummyHead->next;while (curr != nullptr) {ListNode* head1 = curr;for (int i = 1; i < subLength && curr->next != nullptr; i++) {curr = curr->next;}ListNode* head2 = curr->next;curr->next = nullptr;curr = head2;for (int i = 1; i < subLength && curr != nullptr && curr->next != nullptr; i++) {curr = curr->next;}ListNode* next = nullptr;if (curr != nullptr) {next = curr->next;curr->next = nullptr;}ListNode* merged = merge(head1, head2);prev->next = merged;while (prev->next != nullptr) {prev = prev->next;}curr = next;}}return dummyHead->next;}ListNode* merge(ListNode* head1, ListNode* head2) {ListNode* dummyHead = new ListNode(0);ListNode* temp = dummyHead, *temp1 = head1, *temp2 = head2;while (temp1 != nullptr && temp2 != nullptr) {if (temp1->val <= temp2->val) {temp->next = temp1;temp1 = temp1->next;} else {temp->next = temp2;temp2 = temp2->next;}temp = temp->next;}if (temp1 != nullptr) {temp->next = temp1;} else if (temp2 != nullptr) {temp->next = temp2;}return dummyHead->next;}
使用插入排序、归并排序对链表进行排序相关推荐
- 【练习】c++删除链表倒数第K个结点和 插入排序算法将单链表递增排序
删除单链表倒数第K个结点 运行结果: 代码: struct node {int data;node* next;}; //删除链表的倒数第k个结点 bool delet(node*& L, i ...
- 掌握常见的内部排序方法(插入排序,冒泡排序,选择排序,快速排序,堆排序,希尔排序,归并排序,基数排序等)...
掌握常见的内部排序方法(插入排序,冒泡排序,选择排序,快速排序,堆排序,希尔排序,归并排序,基数排序等). 数组高级以及Arrays(掌握) 排序方法 空间复杂度 时间复杂度 稳定性 插 入 排 序 ...
- ❤️万字总结八大排序:冒泡排序,选择排序,插入排序,堆排序,希尔排序,归并排序,计数排序❤️
目录 主要排序算法性能对比 冒泡排序 选择排序 插入排序 堆排序 希尔排序 快速排序 Hoare版 挖坑版 前后指针法 归并排序 计数排序 海量数据的排序问题 主要排序算法性能对比 冒泡排序 各位同学 ...
- 【Java】八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序 、快速排序、归并排序、堆排序和LST基数排序
这篇文章主要介绍了Java如何实现八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序,需要的朋友可以参考下 本文实现了八个常用的排序算法:插入排序 ...
- C++链表的排序实现
对于链表的排序算法,除了希尔排序之外,且堆排序不建议,其他排序方法都是支持的,如下: 冒泡排序,选择排序,插入排序,归并排序,快速排序,计数排序,桶排序和基数排序. 下面废话不多说,直接开始排序 定义 ...
- 【数据结构----笔记5】插入排序算法之【希尔排序算法】
/*__________________________________________________________________________________________________ ...
- 链表14:单链表的排序
前面我们连续多节分析了链表反转的问题,你有没有注意到最大的问题都是指针要进行调整时的指向问题?具体又体现在两个方面,一个是反转相关的问题,一个是合并相关的问题,有些算法还是两个的结合.LeetCode ...
- java语言冒泡排序法_Java实现八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序等...
本文实现了八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序 首先是EightAlgorithms.java文件,代码如下: import jav ...
- 两个无序单链表,排序后合并成一个有序链表
两个无序单链表,排序后合并成一个有序链表 算法思想:用冒泡法,对链表1和2进行排序,对排序后的两个链表,从小到大进行循环,装入链表3中. #include<stdio.h> #includ ...
最新文章
- 机器人动力学建模实例(二):三连杆机械臂
- UA STAT687 线性模型II 最小二乘理论3 广义最小二乘
- 【全0、全1的地址干嘛用的】几类特殊的IP地址,网络号全0,主机号全1等
- oracle改了包怎么保存,Oracle存储过程、包、方法使用总结(推荐)
- OpenCV图像的轮廓的匹配
- 爬虫之Requests库
- 为什么其他计算机连接需要密码是什么东西,连接其他电脑需要密码怎么处理
- Matlab信号提取、频谱分析、滤波、阈值设定、寻找极值点
- VS中Windows界面开发
- 信息系统项目管理师自学笔记(二十二)—— 网络应用与管理
- java全栈工程师培训,分享面经
- HDU6070	Dirt Ratio
- PHP操作redis详细讲解
- 【论文笔记】From the Detection of Toxic Spans in Online Discuss to the Analysis of Toxic-to-Civil Transfer
- 扫雷代码java_JAVA实现扫雷游戏
- Microsoft Excel 教程:如何在 Excel 中使用切片器筛选数据?
- 【Matlab学习手记】csv和xlsx格式互转
- 【MTK官方工具】最好用的MTK官方工具
- Lua党看过来|Cocos Creator 即将支持Lua!
- 『算法』.Net 字符串计算算法