利用归并算法对链表进行排序
/**
* 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* sortList(ListNode* head) {
if(head==nullptr||head->next==nullptr)return head;//对头指针进行判断
//利用快慢指针找到中间值mid
ListNode* slow=head;
ListNode* fast=head->next;
while(fast!=nullptr&&fast->next!=nullptr){
slow=slow->next;
fast=fast->next->next;
}
ListNode *mid=slow->next;
slow->next=nullptr;
//递归算法
ListNode* left=sortList(head);
ListNode* right=sortList(mid);
//将mid左右的链表进行合并
return merge(left,right);
}
private:
ListNode* merge(ListNode* l1,ListNode* l2){
//创建一个哑节点
ListNode dummy(0);//注意:此时dummy用的是栈上对象而不是堆上对象(即用ListNode而不是ListNode* dummy = new ListNode(0);)
/*原因如下:
栈上对象特点:
1.自动内存管理:函数结束时自动销毁,不需要手动释放
2.高效:栈分配比堆分配快得多
3.安全:不会内存泄漏
堆上对象特点:
1.需要手动管理内存:必须用 delete 释放,否则内存泄漏
2.较慢:堆分配比栈分配慢
3.容易出错:忘记释放会导致内存泄漏
*/
ListNode* tail=&dummy;//用tail接收
while(l1!=nullptr&&l2!=nullptr){
if(l1->val<l2->val){
tail->next=l1;
l1=l1->next;
}
else{
tail->next=l2;
l2=l2->next;
}
tail=tail->next;//尾指针后移
}
// 将剩余节点接到新链表尾部
tail->next=(l1!=nullptr)?l1:l2;//将剩余链表部分接上
return dummy.next;//返回头节点
}
/*
递归过程:
sortList(4→2→1→3)
│
├─ 找到中点:slow在2,mid=1→3
├─ left = sortList(4→2) → 返回 2→4
│ │
│ ├─ sortList(4→2)
│ │ ├─ 找到中点:slow在4,mid=2
│ │ ├─ left = sortList(4) → 4
│ │ ├─ right = sortList(2) → 2
│ │ └─ merge(4,2) → 2→4
│ │
├─ right = sortList(1→3) → 返回 1→3
│ │
│ ├─ sortList(1→3)
│ │ ├─ 找到中点:slow在1,mid=3
│ │ ├─ left = sortList(1) → 1
│ │ ├─ right = sortList(3) → 3
│ │ └─ merge(1,3) → 1→3
│ │
└─ merge(2→4, 1→3) → 1→2→3→4
*/
};