归并排序 - acgtyrant/Algorithm-and-Data-Structure GitHub Wiki
其实很早就写好了,但一直有奇怪的 bug, 最近才扒出并捏死。
其实其实我感觉归并排序的代码复杂度要比快速排序复杂多了。
其一,首先得实现两种子函数,一是 Sort
, 二是 Merge
, 至于实现就不哆嗦了。
其二,我实现的归并排序并不是 in-place 算法,而且由于模板的限制,我不得不引入一个额外的第三参数 temporary_iterator
, 用来代表临时空间 temporary_vector
的迭代器:
template <typename RandomIterator>
void MergeSort(
RandomIterator first,
RandomIterator last,
RandomIterator temporary_first) {
...
};
其三,为了避免递归 Sort
中不停地把 temporary_vector 中的值赋值到本体上,我们可以干脆在递归之递归中交换参数的位置,实现轮流倒排。说实话这蛮考验脑力的,我想了半天,最后还是被一开始的
mergesort::Sort(first, last, temporary_first);
std::copy(temporary_first, temporary_first + (last - first), first);
所启发:既然我写了这两个语句,就说明我在假定这个算法对 [first, last) 的排序结果会被储存到 temprary_first
所指向的容器上。所以就在它里面的两个 Sort
递归函数中把迭代器参数位置颠倒过来,至于 Merge
则不用,毕竟 Merge
的实现说得很清楚了,既然 mergesort::Sort(first, last, temporary_first)
要把排序结果储存到 temporary_first
上,那么 Merge
的迭代器参数位置毋庸置疑地与它一致。此外,我还从中学到,迭代器运算可以很好地代替传统的索引值,比如 last - first
就等于其 size, 且 temporary + (last - first)
一样也做到了出色的同・步长索引。
其四,当迭代器范围很小时,可以直接上 InsertionSort
, 不过别忘了这时我们无法确定所用的迭代器范围 [first, last) 是来自正体还是 temporary_vector. 其实没必要判断,直接把它们 std::copy
复制到 temporary_first
所指的容器即可,这么一来在递归函数的终点里,正体与 temporary_vector 的值就完全一致,自然免去鸡生蛋蛋生鸡之恼:
if (last - first < mergesort::cutoff) {
InsertionSort(first, last);
std::copy(first, last, temporary_iterator);
return;
}