Day107 | 147.对链表进行插入排序 | 简单选择、冒泡、直接插入
147. 对链表进行插入排序 - 力扣(LeetCode)
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即可
完整代码:
笔者第一次写的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| 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; 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; } };
|
在原地进行修改的代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| ListNode* selectionSort(ListNode* head) { ListNode dummy(0); dummy.next = head; ListNode *sortedTail = &dummy;
while (sortedTail->next) { ListNode *preMin = sortedTail, *minNode = sortedTail->next; ListNode *curr = minNode->next, *preCurr = minNode;
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; }
|
冒泡排序
太麻烦了不说了,大家自己看吧
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| ListNode* insertionSort(ListNode* head) { ListNode dummy(0); ListNode *curr = head;
while (curr) { ListNode *next = curr->next; ListNode *pre = &dummy;
while (pre->next && pre->next->val < curr->val) { pre = pre->next; }
curr->next = pre->next; pre->next = curr; curr = next; } return dummy.next; }
|