对于数组的各种经典排序方法,请参看常用的7种排序算法——以leetcode 75. Sort Colors为例,该博客该出了7种方法分析。
一、题目
Sort a linked list in O(n log n) time using constant space complexity.
Example 1:
Input: 4->2->1->3 Output: 1->2->3->4
Example 2:
Input: -1->5->3->4->0 Output: -1->0->3->4->5
本篇主要讲解链表的快速排序方法:冒泡,简单选择,插入排序,归并,快排。各种方法的主要代码如下:详见的注释见代码。
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* sortList(ListNode* head) { if(head == nullptr || head->next == nullptr) return head; //方法一:冒泡排序:交换节点的值 算法交换链表节点val值,时间复杂度O(n^2),空间复杂度O(1) // bubble_sort(head); // return head; //方法二:简单选择排序 交换节点的值 算法中只是交换节点的val值,时间复杂度O(n^2),空间复杂度O(1) //return select_sort(head); //方法三:直接插入排序 算法中是直接交换节点,时间复杂度O(n^2),空间复杂度O(1) //return insert_sort(head); //方法四:归并排序 算法交换链表节点,时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1) return merge_sort(head); //方法x: 快排:交换节点的值 时间复杂度O(nlogn) 空间复杂度是O(logn)- o(n) 不考虑递归的话是O(1) //quick_sort(head, nullptr); //return head; } //METHOD4:the subfunction of merge sort1: merge sort ListNode* merge_sort(ListNode* head) { //当每次拆分后的前半边(或者后半边)仅有一个元素,此时应该返回merge_sort()为其本身,也即是序列的首元素 if(head->next == nullptr) return head; //首先找到中间节点的位置。利用fast slow 指针 ListNode* fast = head; ListNode* slow = head; while(fast->next != nullptr && fast->next->next != nullptr) { fast = fast->next->next; slow = slow->next; } //slow指向了中间节点的元素 fast = slow;//fast指向前半边序列的末尾 slow = slow -> next;//slow指向后半边序列的开始 fast -> next = nullptr; //divide fast = merge_sort(head);//前半边,fast指的是前半边的序列的首元素,由merge_sort返回。 slow = merge_sort(slow);//后半边,merge_sort()返回的是后面的半边序列的起始节点指针 //agency return merge(fast, slow); } //METHOD4:the subfunction of merge sort2: merge ListNode* merge(ListNode* head1, ListNode* head2) { //当head1或者head2为空时候,返回另外一个即可 if(head1 == nullptr) return head2; else if(head2 == nullptr) return head1; ListNode* res, * p;//res表示最终结果的第一个节点指针,p是新的合并后指针,其保存最小的值的节点指针,要随着合并往后移动,head1 和head2都是要随着往后移动 if(head1->val > head2->val) { p = head2;//p保存最小值节点指针 head2 = head2->next;//head2要往后移动 } else { p = head1; head1 = head1->next; } res = p; while(head1 != nullptr && head2 != nullptr) { if(head1->val > head2->val)//若是head2小的话,head2要接上p,同时head2要往后移动 { p->next = head2; head2 = head2->next;// } else { p->next = head1; head1 = head1->next; } p = p->next; } if(head1 == nullptr) p->next = head2; else p->next = head1; return res; } /* //METHOD1: the function of bubble sort void bubble_sort(ListNode* head) { ListNode* p = nullptr; bool flag = true; while(p != head->next && flag)//这里p会遍历所有的节点。p每次都舍弃一个节点,也就是每次都会向前移动一个节点,截止条件是不等于head->next { flag = false; ListNode* q = head;//q每次都从开始的head节点开始遍历,直到不等于p为止 for( ; q->next && q->next != p; q = q->next) { if(q->val > q->next->val)//大的值往后移动 { swap(q->val, q->next->val); flag = true; } } p = q;//p每次都会舍弃掉最后一个节点 } } //METHOD2:the function of select sort ListNode* select_sort(ListNode* head) { ListNode* dump = new ListNode(0); dump->next = head; ListNode* sortedTail = dump;//排好序的末尾 while(sortedTail ->next != nullptr) { ListNode* minNode = sortedTail->next; ListNode* p = sortedTail->next->next; while(p != nullptr) { if(p->val < minNode->val) minNode = p; p = p->next; } if(sortedTail ->next != minNode) swap(sortedTail->next->val, minNode->val); sortedTail = sortedTail->next; } return dump->next; } //METHOD3:the function of insert sort ListNode* insert_sort(ListNode* head) { ListNode* dump = new ListNode(0); dump->next = head; ListNode* sortedTail = dump->next;//每次的末尾元素,首先是赋值为head ListNode* p = dump->next->next; //p首先指向head->next while(p != nullptr) { ListNode* tmp = dump->next; ListNode* pre = dump;//每一趟插入排序,tmp都从开始dump->next出发,直至到tmp=p或者找到某个tmp->val <= p->val(也就是找到插入位置) while(tmp != p && tmp->val <= p->val) { tmp = tmp->next; pre = pre->next; } if(tmp == p)//若到了tmp==p.说明p之前的元素都是有序的,不用处理,此时sortedTail = p; sortedTail = p; else//交换节点 { sortedTail ->next = p->next; p->next = tmp; pre->next = p; } p = sortedTail->next;//sortedTail } return dump->next; } //METHOD4:the subfunction of merge sort1: merge sort ListNode* merge_sort(ListNode* head) { //当每次拆分后的前半边(或者后半边)仅有一个元素,此时应该返回merge_sort()为其本身,也即是序列的首元素 if(head->next == nullptr) return head; //首先找到中间节点的位置。利用fast slow 指针 ListNode* fast = head; ListNode* slow = head; while(fast->next != nullptr && fast->next->next != nullptr) { fast = fast->next->next; slow = slow->next; } //slow指向了中间节点的元素 fast = slow;//fast指向前半边序列的末尾 slow = slow -> next;//slow指向后半边序列的开始 fast -> next = nullptr; //divide fast = merge_sort(head);//前半边,fast指的是前半边的序列的首元素,由merge_sort返回。 slow = merge_sort(slow);//后半边,merge_sort()返回的是后面的半边序列的起始节点指针 //agency return merge(fast, slow); } //METHOD4:the subfunction of merge sort2: merge ListNode* merge(ListNode* head1, ListNode* head2) { //当head1或者head2为空时候,返回另外一个即可 if(head1 == nullptr) return head2; else if(head2 == nullptr) return head1; ListNode* res, * p;//res表示最终结果的第一个节点指针,p是新的合并后指针,其保存最小的值的节点指针,要随着合并往后移动,head1 和head2都是要随着往后移动 if(head1->val > head2->val) { p = head2;//p保存最小值节点指针 head2 = head2->next;//head2要往后移动 } else { p = head1; head1 = head1->next; } res = p; while(head1 != nullptr && head2 != nullptr) { if(head1->val > head2->val)//若是head2小的话,head2要接上p,同时head2要往后移动 { p->next = head2; head2 = head2->next;// } else { p->next = head1; head1 = head1->next; } p = p->next; } if(head1 == nullptr) p->next = head2; else p->next = head1; return res; } //METHODx: the subfunction of quick sort 1: quick sort // 与数组的快排相比,这里是[low, high) 前闭后开,不包括后面的tail void quick_sort(ListNode* head, ListNode* tail) { ListNode * pivot; if(head != tail && head->next != tail) { pivot = findPivot(head, tail); quick_sort(head, pivot); quick_sort(pivot->next, tail); } } //METHODx: the subfunction of quick sort 2: quick sort find pivot ListNode* findPivot(ListNode* low, ListNode* high) { int key = low -> val; ListNode* loc = low; for(ListNode* i = low->next; i != high; i = i->next)//这里是 != , 因为[low, high)前闭后开。 这里是所有小于pivot的元素放到最前面 { if(i->val < key) { loc = loc -> next; swap(i->val, loc->val); } } swap(low->val, loc->val);//piovt放到所有小于pivot的元素段的末尾 pivot就是这里的key return loc; } */ };
以上。
推荐使用归并排序,原来归并排序的数组的空间复杂度O(n),而在链表上并不用开辟空间存储元素,因而空间复杂度是O(1),所以链表排序推荐归并排序,时间复杂度O(nlogn),空间复杂度O(1)。
参考:https://www.cnblogs.com/TenosDoIt/p/3666585.html