Sort a linked list in O(n log n) time using constant space complexity.
别人的分析:
能够有O(n*lg(n))时间复杂度的算法为
快速排序,堆排序,归并排序,三者的空间复杂度分别为O(1), O(n),O(n)
通常的,对数组而言,归并排序的空间复杂度为O(n), 你需要开出O(N)的额外空间来容纳数组,来表示归并后的顺序。但是,对于链表,你可以省下这部分空间的开销,你只需要改变节点的next指针的指向,就可以表示新的归并后的顺序了,所以空间复杂度陡然降到了O(1)。
时间复杂度:O(n*lg(n))
空间复杂度:O(1)
/**
* 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 == NULL)
return head;
if(head -> next == NULL)
return head;
//寻找链表中间位置
ListNode* fast = head;
ListNode* slow = head;
while(fast -> next != NULL && fast -> next -> next != NULL)
{
fast = fast -> next;
fast = fast -> next;
slow = slow -> next;
}
ListNode* mid = slow -> next;
slow -> next = NULL;//截断成两段
ListNode* list1 = sortList(head);//再划分
ListNode* list2 = sortList(mid);
ListNode* sorted = merge(list1 , list2);//划分到最底层后在合并
return sorted;
}
//二,合并两个链表再返回其头指针
ListNode* merge(ListNode* list1 , ListNode* list2){
if(list1 == NULL)
return list2;
if(list2 == NULL)
return list1;
ListNode* head;
ListNode* tmp;
if(list1 -> val < list2 -> val){
head = list1;
list1 = list1 -> next;
}else{
head = list2;
list2 = list2 -> next;
}
tmp = head;
while(list1 != NULL && list2 != NULL){
if(list1 -> val < list2 -> val){
tmp -> next = list1;
tmp = list1;
list1 = list1 -> next;
}else{
tmp -> next = list2;
tmp = list2;
list2 = list2 -> next;
}
}
if(list1 != NULL)
tmp -> next = list1;
if(list2 != NULL)
tmp -> next = list2;
return head;
}
};
对比学习数组版本的归并:
时间复杂度:O(n*lg(n))
空间复杂度:O(lg(n))????
#include "windows.h"
#include "vector"
#include <iostream>
#include "fstream"
#include "algorithm"
#include <stdio.h>
#include "string"
#include <cmath>
#include <cstdlib>
#include "map"
using namespace std;
//分治法的合并函数 ,将真正执行排序过程
//将数组A[low.....mid]和A[mid+1.......high]合并
void Merge(vector<int> &a, int low, int mid, int high)
{
int n1 = mid - low + 1;//A[low.....mid]的长度
int n2 = high - mid;//A[mid+1.......high]的长度
long Max = 99999999;//烧饼元素的值
int *L = new int[n1 + 1];//需要开辟额外控件(多申请一个烧饼位置)
int *R = new int[n2 + 1];
if (L == NULL || R == NULL)
exit(1);
int i = 0;
for (; i < n1; i++)
L[i] = a[low + i];
int j = 0;
for (; j < n2; j++)
R[j] = a[mid + j + 1];
i = 0; j = 0;
int k = 0;
L[n1] = Max;//哨兵元素位置
R[n2] = Max;
//合并到数组a中
for (k = low; k <= high; k++)
{
if (L[i] <= R[j])
{
a[k] = L[i];
i++;
}
else
{
a[k] = R[j];
j++;
}
}
delete[] L;
delete[] R;
}
//合并排序法(分治法)
//将数组A[low......high]左排序,再右排序,最后合并成新的有序序列
void MergeSort(vector<int> &a, int low, int high)
{
if (low < high)
{
int mid = (low + high) / 2;
MergeSort(a, low, mid);
MergeSort(a, mid + 1, high);
Merge(a, low, mid, high);//合并成新的有序序列
}
}
int main()
{
int arr[10] = {2,3,6,1,0,2,4,5,6,9};
vector<int> vec(arr,arr+10);
MergeSort(vec,0,9);
for (int i = 0; i <= 9; i++)
cout << vec[i] << " ";
system("pause");
return 0;
}
注:本博文为EbowTang原创,后续可能继续更新本文。如果转载,请务必复制本条信息!
原文地址:http://blog.youkuaiyun.com/ebowtang/article/details/50349562
原作者博客:http://blog.youkuaiyun.com/ebowtang
本博客LeetCode题解索引:http://blog.youkuaiyun.com/ebowtang/article/details/50668895