当前位置: 首页 > java >正文

Day107 | 147.对链表进行插入排序 | 简单选择、冒泡、直接插入

Day107 | 147.对链表进行插入排序 | 简单选择、冒泡、直接插入

147. 对链表进行插入排序 - 力扣(LeetCode)

147题直接用插入排序就可以解决,只是想着顺手总结一下

文章目录

  • Day107 | 147.对链表进行插入排序 | 简单选择、冒泡、直接插入
    • 简单选择排序
    • 冒泡排序
    • 直接插入排序

简单选择排序

思路:

笔者的思路:比较简单粗暴,我新建一个链表res,然后遍历原来的链表head,找到一个最大值的结点的前驱结点p,就保存到temp中,然后把p->next节点删掉,然后就用头插法把temp->next插入新的链表res中

简单排序得知道已经排序过的序列的位置,而笔者用的是新创建的连接的虚拟头结点的res来表示已经排序好的序列的位置

也可以不用新的链表直接在原地修改,基本思路:

用sortedTail指针标记已经排序好的序列的最后一个节点

用四个指针进行标记,min标记最小值的节点,premin表示pre的前驱结点

cur用来遍历找最小值,precur表示cur的前驱结点和更新premin(有前驱结点好进行修改)

遍历过程中,如果cur的值比min的值小的话,就把min更新为cur

然后利用premin把min给删掉,把min给接到已排序链表的末尾,也就是sortedTail的后面

最后把sortedTail指针更新为min即可

完整代码:

笔者第一次写的代码

//简单选择排序
class Solution {
public:ListNode* sortList(ListNode* head) {//虚拟头结点ListNode *t=new ListNode;//用来返回的链表的虚拟头结点ListNode *res=new ListNode;t->next=head;//原来链表全都删除完毕代表排序结束while(t->next!=nullptr){int maxVal=INT_MIN;ListNode *p=t;//temp保存有最大值的节点,因为这个结点要从原来的链表中删除掉ListNode *temp=new ListNode;//找最大值while(p->next!=nullptr){if(p->next->val>maxVal){maxVal=p->next->val;temp=p;}p=p->next;}//删除原来的节点ListNode *add=temp->next;temp->next=temp->next->next;//插入到新的链表中add->next=res->next;res->next=add;}return res->next;}
};

在原地进行修改的代码

ListNode* selectionSort(ListNode* head) {ListNode dummy(0);                // 虚拟头节点dummy.next = head;ListNode *sortedTail = &dummy;   // 维护已排序部分的尾指针while (sortedTail->next) {        // 遍历未排序部分//这两个一个指向最小值节点,一个指向最小值节点的前驱结点ListNode *preMin = sortedTail, *minNode = sortedTail->next;//cur是用来遍历的指针,pre是cur的前驱节点,这两个是一起的ListNode *curr = minNode->next, *preCurr = minNode;// 寻找最小值节点及其前驱(时间复杂度O(n))while (curr) {                // 遍历剩余未排序节点if (curr->val < minNode->val) {preMin = preCurr;     // 更新最小值前驱指针minNode = curr;       // 更新最小值节点指针}preCurr = curr;           // 前驱指针跟随移动curr = curr->next;        // 当前指针后移}// 将最小节点从原链表中移除preMin->next = minNode->next; // 断开原链// 将最小节点插入已排序链表的尾部minNode->next = sortedTail->next; // 保持未排序部分连接sortedTail->next = minNode;    // 插入到已排序末尾sortedTail = minNode;          // 更新尾指针}return dummy.next;
}

冒泡排序

太麻烦了不说了,大家自己看吧

ListNode* bubbleSort(ListNode* head) {if (!head || !head->next) return head;ListNode dummy(0);                // 虚拟头节点处理头指针变化dummy.next = head;bool swapped = true;ListNode* end = nullptr;          // 记录每轮冒泡的终止边界while (swapped) {swapped = false;ListNode *prev = &dummy;      // 前驱指针(关键修正点)ListNode *curr = prev->next;  // 当前指针while (curr->next != end) {   // 遍历至已排序边界前ListNode *next = curr->next;if (curr->val > next->val) {// 交换相邻节点(调整指针而非数据域)prev->next = next;     // 前驱连接下一节点curr->next = next->next;next->next = curr;// 更新标记和指针swapped = true;prev = next;          // 前驱指针后移} else {prev = curr;          // 无需交换则正常后移curr = curr->next;}}end = curr;                   // 更新排序边界}return dummy.next;
}

直接插入排序

这个比较好理解一些,直接插入排序就是先找插入位置,也就是下一次处理节点要插入到我们已经排序的子序列的哪里

用cur遍历要处理的结点,而因为我们要把cur所指向的结点插入到已经排好序的子序列中,所以要有一个next保存cur的next结点,否则处理完一个节点直接找不到后续节点了。而我们要找插入位置,那就是要在排好序的子序列中找到最后一个小于cur的结点,然后把cur插入到该节点的后面。

我们用pre表示这个结点,那么比较的时候就是pre->next->val和cur->val进行比较了,只有满足这个条件的时候pre才会往后移动,否则不移动

而while条件里面的pre->next不为nullptr对应的是cur的节点值大于已经排好序的子序列的全部的值

其余情况对应的是pre->next->val < curr->val

ListNode* insertionSort(ListNode* head) {ListNode dummy(0);                // 虚拟头节点ListNode *curr = head;            // 遍历原链表的指针while (curr) {                     // 逐个处理未排序节点ListNode *next = curr->next;   // 保存下一个待处理节点ListNode *pre = &dummy;        // 从虚拟头开始寻找插入位置// 寻找插入位置(时间复杂度O(n))while (pre->next && pre->next->val < curr->val) {pre = pre->next;           // 移动至最后一个小于curr的节点}// 插入操作curr->next = pre->next;        // 将curr插入pre之后pre->next = curr;              // 更新前驱指针curr = next;                   // 处理下一个节点}return dummy.next;
}
http://www.xdnf.cn/news/3408.html

相关文章:

  • 【专题五】位运算(2)
  • AXI中的out of order和interleaving的定义和两者的差别?
  • OSPF的路由
  • Go-web开发之社区功能
  • Java 中那些奇怪的空指针报错场景及解决方案NullPointerException
  • 【计算机视觉】语义分割:MMSegmentation:OpenMMLab开源语义分割框架实战指南
  • MySQL数据同步之Canal讲解
  • 2025年- H16-Lc124-169.多数元素(技巧)---java版
  • 7.0/Q1,GBD数据库最新文章解读
  • ClackyAI:下一代智能云开发环境的技术革新与实践价值
  • WPF使用依赖注入框架AutoMapper
  • 仿腾讯会议——服务器结构讲解
  • Matlab/Simulink - BLDC直流无刷电机仿真基础教程(四) - PWM调制模拟
  • 后端工程师需要掌握哪些基础技能
  • 机器人--底盘
  • 人才答辩ppt优化技巧_杰青_优青_万人计划青年拔尖人才_青年长江学者ppt制作案例
  • 2025五一杯A题五一杯数学建模思路代码文章教学:支路车流量推测问题
  • 部署.NET6.0 Web API项目到Docker
  • 实现了一个基于寄存器操作STM32F103C8t6的工程, 并实现对PA1,PA2接LED正极的点灯操作
  • npm宿主依赖、宿主环境依赖(peerDependencies)(指由宿主环境提供的依赖)
  • 网络安全防火墙技术有哪些?网络防火墙的主要作用
  • 在ASP.NET MVC中使用Repeater指南
  • 【浅尝Java】Java简介第一个Java程序(含JDK、JRE与JVM关系、javcdoc的使用)
  • Seata服务端回滚事务核心源码解析
  • springboot中异步接口实现所有方式_20250501
  • 内存 “舞台” 上,进程如何 “翩翩起舞”?(转)
  • idea安装
  • 【Unity】 组件库分类详解
  • RAGFlow报错:ESConnection.sql got exception
  • 【基础算法】插值查找算法 - JAVA