链表的一些辅助函数
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) {}
};
ListNode* createLinkedList(int arr[],int n){
if( n == 0 )
return NULL;
ListNode* head = new ListNode(arr[0]);
ListNode* curNode = head;
for(int i = 1; i < n; i++){
curNode->next = new ListNode(arr[i]);
curNode = curNode->next;
}
return head;
}
void deleteLinkedList(ListNode* head){
ListNode* curNode = head;
while( curNode != NULL ){
ListNode* delNode = curNode;
curNode = curNode->next;
delete delNode;
}
}
void printLinkedList(ListNode* head){
ListNode* curNode = head;
while( curNode != NULL ){
cout << curNode->val << " -> ";
curNode = curNode->next;
}
cout << "NULL" << endl;
}
自顶向下的递归
对链表自顶向下归并排序的过程如下:
-
1
找到链表的中点,以中点为分界,将链表拆分成两个子链表。寻找链表的中点可以使用快慢指针的做法,快指针每次移动 2 步,慢指针每次移动 1 步,当快指针到达链表末尾时,慢指针指向的链表节点即为链表的中点。
-
2
对两个子链表分别排序。将两个排序后的子链表合并,得到完整的排序后的链表(另开辟一个新的节点来保存排序后的链表)
-
3
上述过程可以通过递归实现。递归的终止条件是链表的节点个数小于或等于 1,即当链表为空或者链表只包含 1个节点时,不需要对链表进行拆分和排序。
class Solution {
private:
ListNode* sortList(ListNode* head, ListNode* tail){
if( !head )
return head;
// 这里用head->next == tail 比 head == tail 好在不用遍历链表去找tail了,直接设置为nullptr就可以了
if( head->next == tail ){ //只有一个节点的时候
head->next = nullptr;
return head;
}
ListNode* slow = head, *fast = head;
//使用快慢指针找中间位置
while( fast != tail ){
slow = slow->next;
fast = fast->next;
if( fast != tail )
fast = fast -> next;
}
ListNode* mid = slow;
return merge( sortList(head, mid), sortList(mid, tail) );
}
ListNode* merge( ListNode* head1, ListNode* head2 ){
ListNode* dummyhead = new ListNode(0);
ListNode* temp = dummyhead, *temp1 = head1, *temp2 = head2;
while( temp1 != nullptr && temp2 != nullptr ){
if( temp1->val <= temp2->val ){
temp->next = temp1;
temp1 = temp1->next;
}else{
temp-> next = temp2;
temp2 = temp2->next;
}
temp = temp -> next;
}
if( temp1 != nullptr )
temp -> next = temp1;
else if( temp2 != nullptr )
temp->next = temp2;
return dummyhead->next;
}
public:
ListNode* sortList(ListNode* head) {
return sortList(head, nullptr);
}
};
自底向上的迭代方法
可以类比于数组的写法
template <typename T>
void mergeSortBU( T arr[], int n ){
for( int sz = 1; sz <= n; sz += sz ){ //步劲从1->2->4->8等等
for( int i = 0; i + sz < n; i += sz + sz ){
//对arr[i...i+sz-1] 和 arr[i+sz....i+2*sz-1]进行归并排序
//这里 i + sz - 1 和 i + sz + sz - 1可能已经超过了n的大小 所以要在循环中限制🚫
__merge( arr, i , i + sz - 1, min(i + sz + sz - 1, n-1) );
}
}
}
链表的迭代方法更多的是需要将指针每次移动相应的步伐(每次移动就是一个for循环遍历)
class Solution {
private:
ListNode* merge( ListNode* head1, ListNode* head2 ){
ListNode* dummyhead = new ListNode(0);
ListNode* temp = dummyhead, *temp1 = head1, *temp2 = head2;
while( temp1 != nullptr && temp2 != nullptr ){
if( temp1->val <= temp2->val ){
temp->next = temp1;
temp1 = temp1->next;
}else{
temp-> next = temp2;
temp2 = temp2->next;
}
temp = temp -> next;
}
if( temp1 != nullptr )
temp -> next = temp1;
else if( temp2 != nullptr )
temp->next = temp2;
return dummyhead->next;
}
public:
ListNode* sortList(ListNode* head) {
if( head == nullptr )
return head;
int length = 0;
ListNode* node = head;
while(node != nullptr){
length ++;
node = node->next;
}
ListNode* dummyHead = new ListNode(0 , head);
for( int subLength = 1; subLength < length; subLength <<= 1 ){ //步长从1 -> 2 -> 4 这样逐渐累加
ListNode* prev = dummyHead, *cur = dummyHead -> next;
while( cur != nullptr ){
ListNode* head1 = cur;
for(int i = 1; i < subLength && cur->next != nullptr; i ++ )
cur = cur -> next;
ListNode* head2 = cur -> next;
cur -> next = nullptr;
cur = head2;
for (int i = 1; i < subLength && cur != nullptr && cur->next != nullptr; i++)
cur = cur->next;
ListNode* next = nullptr;
if( cur != nullptr ){
next = cur -> next;
cur -> next = nullptr;
}
ListNode* merged = merge(head1, head2);
prev -> next = merged;
while( prev -> next != nullptr )
prev = prev -> next;
cur = next;
}
}
return dummyHead->next;
}
};