147.对链表进行插入排序
1.题目介绍
给定单个链表的头 head ,使用 插入排序 对链表进行排序,并返回 排序后链表的头 。
插入排序 算法的步骤:
1.插入排序是迭代的,每次只移动一个元素,直到所有元素可以形成一个有序的输出列表。
2.每次迭代中,插入排序只从输入数据中移除一个待排序的元素,找到它在序列中适当的位置,并将其插入。
3.重复直到所有输入数据插入完为止。
下面是插入排序算法的一个图形示例。部分排序的列表(黑色)最初只包含列表中的第一个元素。每次迭代时,从输入数据中删除一个元素(红色),并就地插入已排序的列表中。
对链表进行插入排序。
示例 1:
输入: head = [4,2,1,3]
输出: [1,2,3,4]
示例 2:
输入: head = [-1,5,3,4,0]
输出: [-1,0,3,4,5]
2.题解
2.1 插入排序
思路
首先要理解插入排序,冒泡排序,选择排序的区别,这里请移步排序算法
插入排序总之就是维护一个有序数列,每次从数列外部取一个进入数列,同时完成排序。
对于链表也是一样,不过要维护的是指针,来区分有序数列和待排序数列。
这里我们维护一个lastSorted作为有序数列的尾结点,curr指向第一个待排序的数,即lastSorted->next
这里有两种情况:1.待排序的数就是最大的,直接lastSorted=lastSorted->next;即可
2.有序数列中有比待排序数更大的,这时候就要遍历有序链表,查看插入位置
遍历途中使用一个指针pre,通过判断pre->next->val是否大于curr->val,判断具体插入位置,链表插入就是三指针插入法即可
这里dummyHead很好的维护了头节点的位置,因为由于不断地插入排序,实际的头节点是在不断地变化的,有着dummyHead这个虚拟头结点,能帮我们很快定位头结点。
代码
/**
* 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) {}
* };
*/
class Solution {
public:
ListNode* insertionSortList(ListNode* head) {
if (head == nullptr)
return head;
ListNode* dummyHead = new ListNode(0,head);
ListNode* lastNode = head;
ListNode* curr = head->next;
while(curr != nullptr){
if (lastNode->val <= curr->val) lastNode = lastNode->next;
else{
ListNode* pre= dummyhead;
while(pre->next->val <= curr->val) pre = pre->next;
lastNode->next = curr->next;
curr->next = pre->next;
pre->next = curr;
}
curr = lastNode->next;
}
ListNode* ans = dummyHead->next;
delete dummyHead;
return ans;
}
};