/*** 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)

插入排序算法:

  1. 插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
  2. 每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
  3. 重复直到所有输入数据插入完为止。
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) 的空间复杂度,则需要使用自底向上的实现方式。
对链表自顶向下归并排序的过程如下。

  1. 找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 22 步,慢指针每次移动 11 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。
  2. 对两个子链表分别排序。
  3. 将两个排序后的子链表合并,得到完整的排序后的链表。
    上述过程可以通过递归实现。递归的终止条件是链表的节点个数小于或等于 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,然后将链表拆分成子链表进行合并。
具体做法如下。

  1. 用subLength 表示每次需要排序的子链表的长度,初始时subLength=1。
  2. 每次将链表拆分成若干个长度为subLength 的子链表(最后一个子链表的长度可以小于
  3. subLength),按照每两个子链表一组进行合并,合并后即可得到若干个长度为 subLength×2 的有序子链表(最后一个子链表的长度可以小于 subLength×2)。
  4. 将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;}

使用插入排序、归并排序对链表进行排序相关推荐

  1. 【练习】c++删除链表倒数第K个结点和 插入排序算法将单链表递增排序

    删除单链表倒数第K个结点 运行结果: 代码: struct node {int data;node* next;}; //删除链表的倒数第k个结点 bool delet(node*& L, i ...

  2. 掌握常见的内部排序方法(插入排序,冒泡排序,选择排序,快速排序,堆排序,希尔排序,归并排序,基数排序等)...

    掌握常见的内部排序方法(插入排序,冒泡排序,选择排序,快速排序,堆排序,希尔排序,归并排序,基数排序等). 数组高级以及Arrays(掌握) 排序方法 空间复杂度 时间复杂度 稳定性 插 入 排 序 ...

  3. ❤️万字总结八大排序:冒泡排序,选择排序,插入排序,堆排序,希尔排序,归并排序,计数排序❤️

    目录 主要排序算法性能对比 冒泡排序 选择排序 插入排序 堆排序 希尔排序 快速排序 Hoare版 挖坑版 前后指针法 归并排序 计数排序 海量数据的排序问题 主要排序算法性能对比 冒泡排序 各位同学 ...

  4. 【Java】八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序 、快速排序、归并排序、堆排序和LST基数排序

    这篇文章主要介绍了Java如何实现八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序,需要的朋友可以参考下 本文实现了八个常用的排序算法:插入排序 ...

  5. C++链表的排序实现

    对于链表的排序算法,除了希尔排序之外,且堆排序不建议,其他排序方法都是支持的,如下: 冒泡排序,选择排序,插入排序,归并排序,快速排序,计数排序,桶排序和基数排序. 下面废话不多说,直接开始排序 定义 ...

  6. 【数据结构----笔记5】插入排序算法之【希尔排序算法】

    /*__________________________________________________________________________________________________ ...

  7. 链表14:单链表的排序

    前面我们连续多节分析了链表反转的问题,你有没有注意到最大的问题都是指针要进行调整时的指向问题?具体又体现在两个方面,一个是反转相关的问题,一个是合并相关的问题,有些算法还是两个的结合.LeetCode ...

  8. java语言冒泡排序法_Java实现八个常用的排序算法:插入排序、冒泡排序、选择排序、希尔排序等...

    本文实现了八个常用的排序算法:插入排序.冒泡排序.选择排序.希尔排序 .快速排序.归并排序.堆排序和LST基数排序 首先是EightAlgorithms.java文件,代码如下: import jav ...

  9. 两个无序单链表,排序后合并成一个有序链表

    两个无序单链表,排序后合并成一个有序链表 算法思想:用冒泡法,对链表1和2进行排序,对排序后的两个链表,从小到大进行循环,装入链表3中. #include<stdio.h> #includ ...

最新文章

  1. 机器人动力学建模实例(二):三连杆机械臂
  2. UA STAT687 线性模型II 最小二乘理论3 广义最小二乘
  3. 【全0、全1的地址干嘛用的】几类特殊的IP地址,网络号全0,主机号全1等
  4. oracle改了包怎么保存,Oracle存储过程、包、方法使用总结(推荐)
  5. OpenCV图像的轮廓的匹配
  6. 爬虫之Requests库
  7. 为什么其他计算机连接需要密码是什么东西,连接其他电脑需要密码怎么处理
  8. Matlab信号提取、频谱分析、滤波、阈值设定、寻找极值点
  9. VS中Windows界面开发
  10. 信息系统项目管理师自学笔记(二十二)—— 网络应用与管理
  11. java全栈工程师培训,分享面经
  12. HDU6070 Dirt Ratio
  13. PHP操作redis详细讲解
  14. 【论文笔记】From the Detection of Toxic Spans in Online Discuss to the Analysis of Toxic-to-Civil Transfer
  15. 扫雷代码java_JAVA实现扫雷游戏
  16. Microsoft Excel 教程:如何在 Excel 中使用切片器筛选数据?
  17. 【Matlab学习手记】csv和xlsx格式互转
  18. 【MTK官方工具】最好用的MTK官方工具
  19. Lua党看过来|Cocos Creator 即将支持Lua!
  20. 『算法』.Net 字符串计算算法

热门文章

  1. NOIP2018 NearlyAFO
  2. windows7远程桌面
  3. 移卡参投的乐享互动首日破发:旗下乐刷罚单不断,逾期率高居不下
  4. 主成分分析(Principal Component Analysis)原理
  5. 使用mars3d时第二次进行hls视频融合报错
  6. 国泰君安国际助力智加科技加速全球商业化布局
  7. StatQuest系列之t-SNE
  8. mysql+纵表和横表_mysql 横表和纵表转换
  9. 【报告分享】2020小红书年中美妆洞察报告.pdf(附下载链接)
  10. 守望先锋,工坊规则封禁源式利用表情卡原地小跳