《算法(第4版)》笔记
归并
归并排序基于“归并”这个简单的操作,即将两个有序的数组归并成一个更大的有序数组。
要将一个数组排序,可以先(递归地)将它分成两半分别排序,然后将结果归并起来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| template<class T> void merge(T& a, int lo, int mid, int hi, T& aux) { int i = lo; int j = mid + 1;
for (int k=lo; k<=hi; ++k) aux[k] = a[k];
for (int k=lo; k<=hi; ++k) { if (i > mid) a[k] = aux[j++]; else if (j > hi) a[k] = aux[i++]; else if (aux[j] < aux[i]) a[k] = aux[j++]; else a[k] = aux[i++]; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| def merge(a, lo, mid, hi, aux): i = lo j = mid + 1
for k in range(lo, hi + 1): aux[k] = a[k]
for k in range(lo, hi + 1): if i > mid: a[k] = aux[j] j += 1 elif j > hi: a[k] = aux[i] i += 1 elif aux[j] < aux[i]: a[k] = aux[j] j += 1 else: a[k] = aux[i] i += 1
|
自顶向下的归并排序(递归)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| template<class T> void merge_sort(T& a, int lo, int hi, T& aux) { if (hi <= lo) return;
int mid = lo + (hi - lo) / 2; merge_sort(a, lo, mid, aux); merge_sort(a, mid + 1, hi, aux); merge(a, lo, mid, hi, aux); }
template<class T> void merge_sort(T& a) { T aux; aux.resize(a.size()); merge_sort(a, 0, a.size() - 1, aux); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| def merge_sort_p(a, lo, hi, aux): if hi <= lo: return
mid = lo + (hi - lo) // 2 merge_sort_p(a, lo, mid, aux) merge_sort_p(a, mid + 1, hi, aux) merge(a, lo, mid, hi, aux)
def merge_sort(a): aux = [None] * len(a) merge_sort_p(a, 0, len(a) - 1, aux)
|
归并排序所需的时间和NlogN成正比。
可以用归并排序处理数百万甚至更大规模的数组,这是插入排序或者选择排序做不到的。归并排序的主要缺点是辅助数组所使用的额外空间和N的大小成正比。
通过一些细致的思考我们还能够大幅度缩短归并排序的运行时间,比如对小规模子数组使用插入排序。使用插入排序处理小规模的子数组(比如长度小于15)一般可以将归并排序的运行时间缩短10%~15%。
自底向上的归并排序
实现归并排序的另一种方法是先归并那些微型数组,然后再成对归并得到的子数组,如此这般,直到我们将整个数组归并在一起。这种实现方法比标准递归方法所需要的代码量更少。首先我们进行两两归并(把每个元素想象成一个大小为1的数组),然后是四四归并(将两个大小为2的数组归并成一个有4个元素的数组),然后是八八归并,一直下去。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
template<class T> void mergeBU_sort(T& a) { int n = a.size();
T aux; aux.resize(n);
for (int sz = 1; sz < n; sz += sz) for (int lo = 0; lo < n - sz; lo += sz + sz) merge(a, lo, lo + sz - 1, std::min(lo + sz + sz - 1, n - 1), aux); }
|
1 2 3 4 5 6 7 8 9 10 11
|
def mergeBU_sort(a) n = len(a) aux = [None] * n
sz = 1 while sz < n: for lo in range(0, n - sz, sz + sz): merge(a, lo, lo + sz -1, min(lo + sz + sz - 1, n - 1), aux) sz += sz
|