归并排序算法
思想
- 将n个元素从中间切开,分成两部分。
- 将步骤1分成的两部分,再分别进行递归分解,直到所有部分的元素个数都为1。
- 从最底层开始逐步合并两个排好序的数列。
有两种方法,一种是自顶向下(递归分治)来做,另一种是自底向上(迭代),核心归并代码一样的
可以看这个博客加深理解
代码如下:
空间复杂度 O ( n l o g ( n ) ) O(nlog(n)) O(nlog(n))(这样写好看点)
void Merge(int *arr, int begin, int mid, int end)
{
int temp = [end-begin+1];
int k = 0,i = begin, j = mid + 1;
while(i <= mid && j <= end)
{
if(arr[i] <= arr[j])
temp[k++] = arr[i++];
else
temp[k++] = arr[j++];
}
while(i <= mid)
temp[k++] = arr[i++];
while(j <= end)
temp[k++] = arr[j++];
for(int i = 0; i < k; i++)
arr[begin+i] = temp[i];
}
void Sort(int *arr, int begin, int end)
{
if(begin >= end)
return;
int mid = begin + end >> 1;
Sort(arr, begin, mid);
Sort(arr, mid+1, end);
Merge(arr, begin, mid, end);
}
空间复杂度 O ( l o g n ) O(log n) O(logn)(数组)
- 对于两个数 a a a和 b b b,取 c = m a x ( a , b ) + 1 c = max(a,b) +1 c=max(a,b)+1。
- 那么令 d = a + b ∗ c d = a + b * c d=a+b∗c,有 a = d % c a = d \%c a=d%c, b = d / c b = d /c b=d/c。
- 利用此技巧可以将 a r r [ k ] arr[k] arr[k]存储原数值和排序后的数值。
- 就实现了 O ( l o g n ) O(log n) O(logn)空间复杂度。(递归栈的空间)
void Merge(int *arr, int begin, int mid, int end)
{
int m = max(arr[mid], arr[end]) + 1;
int i = begin, j = mid + 1, k = begin;
while(i <= mid && j <= end)
{
if(arr[i] % m <= arr[j] % m)
{
arr[k] = arr[k] + (arr[i] % m) * m;
i++;
}
else
{
arr[k] = arr[k] + (arr[j] % m) * m;
j++;
}
k++;
}
while(i <= mid)
{
arr[k] = arr[k] + (arr[i] % m) * m;
i++;
k++;
}
while(j <= end)
{
arr[k] = arr[k] + (arr[j] % m) * m;
j++;
k++;
}
for(int i = begin; i <= end; i++)
arr[i] = arr[i] / m;
}
void Sort(int *arr, int begin, int end)
{
if(begin >= end)
return;
int mid = begin + end >> 1;
Sort(arr, begin, mid);
Sort(arr, mid+1, end);
Merge(arr, begin, mid, end);
}
空间复杂度 O ( 1 ) O(1) O(1)(链表)
见例题LeetCode-148