归并排序
归并排序的思想是基于分治法,其思路是:
- 将待排序区间平分成左右两半,左右两侧分别递归地做归并排序。
- 将这两个有序的区间合并(每次落一个较小的下来),就将这个区间排好序了。
归并排序相比快速排序,几乎没有什么难理解的边界问题。要注意代码中的q[i] <= q[j]
时从左半边落下元素,如果改成q[i] < q[j]
也是能正确排序的,但是这样会丢失【归并排序是稳定的】这个特性。要保持这个特性,在排序字段相等的时候,应该落下来自左侧区间的元素,所以这里用<=
。
我们知道,归并排序的过程中,需要对当前区间进行对半划分,直到区间的长度为1
。也就是说,每一层的子区间,长度都是上一层的1/2
。这也就意味着,当划分到第 \(\log n\) 层的时候,子区间的长度就是1
了。
而归并排序的merge
操作,则是从最底层开始(子区间为1的层),对相邻的两个子区间进行合并,对于每一层来说,在合并所有子区间的过程中,\(n\) 个元素都会被操作一次,所以每一层的时间复杂度都是 \(O(n)\)。而之前我们说过,归并排序划分子区间,将子区间划分为只剩 \(1\) 个元素,需要划分 \(\log n\) 次。每一层的时间复杂度为 \(O(n)\),共有 \(\log n\) 层,所以归并排序的时间复杂度就是\(O(n\log n)\)。
#include <iostream>
using namespace std;
const int N = 100010;
int n;
int q[N], tmp[N];
void merge_sort(int q[], int l, int r)
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid), merge_sort(q, mid + 1, r);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r) {
if (q[i] < q[j]) tmp[k ++] = q[i ++];
else tmp[k ++] = q[j ++];
}
while (i <= mid) tmp[k ++] = q[i ++];
while (j <= r) tmp[k ++] = q[j ++];
for (int i = l, j = 0; i <= r; i ++, j ++ ) q[i] = tmp[j];
}
int main()
{
cin >> n;
for (int i = 0; i < n; i ++ ) cin >> q[i];
merge_sort(q, 0, n - 1);
for (int i = 0; i < n; i ++ ) cout << q[i] << ' ';
return 0;
}
标签:归并,log,int,merge,算法,区间,排序
From: https://www.cnblogs.com/I-am-Sino/p/16970097.html