mirror of
https://github.com/chefyuan/algorithm-base.git
synced 2024-11-01 09:43:38 +00:00
122 lines
4.8 KiB
Markdown
122 lines
4.8 KiB
Markdown
|
有的老哥说链表的排序搞不明白,让我写一下,一不小心给忘记了,今天咱们就安排上。没有学过数据结构的同学可以先看下这个文章
|
|||
|
|
|||
|
[【绘图解析】链表详解](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%85%B3%E4%BA%8E%E9%93%BE%E8%A1%A8%E7%9A%84%E9%82%A3%E4%BA%9B%E4%BA%8B.md)
|
|||
|
|
|||
|
另外大家如果忘记了[【动画模拟】插入排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E7%9B%B4%E6%8E%A5%E6%8F%92%E5%85%A5%E6%8E%92%E5%BA%8F.md)和[【动画模拟】归并排序](https://github.com/chefyuan/algorithm-base/blob/main/animation-simulation/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E5%92%8C%E7%AE%97%E6%B3%95/%E5%BD%92%E5%B9%B6%E6%8E%92%E5%BA%8F.md)思想的话,可以先复习一下,不然这两道题目会看的云里雾里。
|
|||
|
|
|||
|
#### [147. 对链表进行插入排序](https://leetcode-cn.com/problems/insertion-sort-list/)
|
|||
|
|
|||
|
**示例 1:**
|
|||
|
|
|||
|
> 输入: 4->2->1->3
|
|||
|
> 输出: 1->2->3->4
|
|||
|
|
|||
|
**示例 2:**
|
|||
|
|
|||
|
> 输入: -1->5->3->4->0
|
|||
|
> 输出: -1->0->3->4->5
|
|||
|
|
|||
|
下面咱们先来看个动画回忆一下插入排序的具体执行步骤,然后我们再来说下面的题目。
|
|||
|
|
|||
|
![直接插入排序](https://cdn.jsdelivr.net/gh/tan45du/test1@master/20210122/直接插入排序.2marc4epuzy0.gif)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
我们的指针在数组时,可以随意的前后移动,将指针指向值和新元素的值比较后,将新元素插入到合适的位置。
|
|||
|
|
|||
|
我们知道链表查询元素的时间复杂度为 O(n),我们只能够通过遍历链表查询元素。
|
|||
|
|
|||
|
那么我们怎么才能将新元素放到合适的位置呢?
|
|||
|
|
|||
|
**见下图**
|
|||
|
|
|||
|
![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210325113449.75knzw7zmyg0.png)
|
|||
|
|
|||
|
此时我们不能通过移动绿色指针来寻找 5 的合适位置,那么我们应该怎么做呢?见下图
|
|||
|
|
|||
|
![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210325131349.14mi2ap89uxs.png)
|
|||
|
|
|||
|
当我们发现绿色指针的值大于新元素时(7 > 5),我们则可以定义一个新指针,让其从哑节点开始遍历,直到找到新元素(5)的位置,(4 和 7 之间),然后再将新元素插入即可。
|
|||
|
|
|||
|
我们是通过下面这行代码来找到插入位置的, temphead 则代表我们的紫色指针。
|
|||
|
|
|||
|
```java
|
|||
|
while (temphead.next.val <= pre.val) {
|
|||
|
temphead = temphead.next;
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
下面我们再来看动画模拟具体过程。
|
|||
|
|
|||
|
**注:为了更好的表达算法思想,让过程更流畅,特省略了指针的移动细节,直接插入到合适位置,后面会详细说明插入操作的具体步骤**
|
|||
|
|
|||
|
![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/链表的插入排序.4hnc4shp5le0.gif)
|
|||
|
|
|||
|
我们通过上面的动画知道了大致过程,那么我们的是如何将新元素插入到指定位置的呢?
|
|||
|
|
|||
|
见下图
|
|||
|
|
|||
|
|
|||
|
|
|||
|
![插入排序](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210325132359.1hc2axzks3k0.png)
|
|||
|
|
|||
|
|
|||
|
|
|||
|
我们想要将 3 插入到 2 和 4 的中间,此时我们三个指针分别指向 2,4,3
|
|||
|
|
|||
|
我们共分 4 步,来完成这个操作,见下图
|
|||
|
|
|||
|
![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/44444444.29mvcvs4yrms.png)
|
|||
|
|
|||
|
我们来把上图中的最后结果来捋一下看看最后结果是不是完成了插入操作。
|
|||
|
|
|||
|
![](https://cdn.jsdelivr.net/gh/tan45du/photobed@master/微信截图_20210325134022.w5nnr1spyps.png)
|
|||
|
|
|||
|
这样我们就完成了链表的插入排序。下面我们来看下题目代码吧。
|
|||
|
|
|||
|
**题目代码**
|
|||
|
|
|||
|
```java
|
|||
|
class Solution {
|
|||
|
public ListNode insertionSortList(ListNode head) {
|
|||
|
|
|||
|
if (head == null && head.next == null) {
|
|||
|
return head;
|
|||
|
}
|
|||
|
//哑节点
|
|||
|
ListNode dummyNode = new ListNode(-1);
|
|||
|
dummyNode.next = head;
|
|||
|
//pre负责指向新元素,last 负责指向新元素的前一元素
|
|||
|
//判断是否需要执行插入操作
|
|||
|
ListNode pre = head.next;
|
|||
|
ListNode last = head;
|
|||
|
ListNode temphead = dummyNode;
|
|||
|
while (pre != null) {
|
|||
|
//不需要插入到合适位置,则继续往下移动
|
|||
|
if (last.val <= pre.val) {
|
|||
|
pre = pre.next;
|
|||
|
last = last.next;
|
|||
|
continue;
|
|||
|
}
|
|||
|
//开始出发,查找新元素的合适位置
|
|||
|
temphead = dummyNode;
|
|||
|
while (temphead.next.val <= pre.val) {
|
|||
|
temphead = temphead.next;
|
|||
|
}
|
|||
|
//此时我们已经找到了合适位置,我们需要进行插入,大家可以画一画
|
|||
|
last.next = pre.next;
|
|||
|
pre.next = temphead.next;
|
|||
|
temphead.next = pre;
|
|||
|
pre = last.next;
|
|||
|
}
|
|||
|
return dummyNode.next;
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|