我已经使用矢量作为函数在c ++中实现了合并排序 参数而不是索引(开始,结束)。不过,我很乐意 在速度方面,知道这样做是否有任何折衷 和空间复杂性
代码:
void mergeSort(std::vector<int> &array) {
if(array.size() == 1) return;
else {
const unsigned int len = array.size();
const int lo = floor((double)len/2);
const int hi = ceil((double)len/2);
std::vector<int> L(&array[0], &array[lo]);
std::vector<int> R(&array[lo], &array[len]);
mergeSort(L);
mergeSort(R);
merge(array, L, R);
}
return;
}
创建新列表每次调用合并排序可能都不是可行的方法, 但这是合并排序功能的工作原理。此外,有多快/慢:
std::vector<int> L(&array[0], &array[lo]);
然后合并功能如下:
void merge(
std::vector<int> &array,
std::vector<int> &L,
std::vector<int> &R
) {
std::vector<int>::iterator a = array.begin();
std::vector<int>::iterator l = L.begin();
std::vector<int>::iterator r = R.begin();
while(l != L.end() && r != R.end()) {
if (*l <= *r) {
*a = *l;
l++;
}
else {
*a = *r;
r++;
}
a++;
}
while (l != L.end()) {
*a = *l;
a++;
l++;
}
while (r != R.end()) {
*a = *r;
a++;
r++;
}
return;
}
答案 0 :(得分:0)
嗯,每次合并调用都不需要创建新空间。
std::vector<int> L(&array[0], &array[lo]);
实际上会创建空间以容纳lo
个元素,并且还会执行lo
个副本。
您永远不会使用更多O(n)
个额外空间来存储值。所以,为什么不分配足够大的缓冲区来容纳
预先复制整个矢量并使每个递归调用对数据的特定部分进行操作?这样你就不必在每次通话时都创建新的向量。
另外,我还建议您仅在mergesort
上使vector<int>
对迭代器起作用。像下面这样的界面就足够了。
template < typename Iterator, typename Compare>
void mergesort(Iterator s, Iterator e, Compare cmp);
On Github您可以找到我之前实施的mergesort版本。我猜应该够了。
答案 1 :(得分:0)
合并排序所需的唯一额外内存是大小为n
的数组,用于合并在算法的任何步骤中生成的两个排序vector
中的任何一个。显然,您的解决方案使用更多。在第一次合并时,它分配两个n/2
长度的向量,然后它将是n/4
的四个向量,所以全部,总共给出n * log(n)
。这比n
略高。
分配vector
的成本通常与其长度呈线性关系(如果复制vector
的元素可以在O(1)中完成),但您应该记住分配内存如果您不使用自定义分配器,则堆是昂贵的操作。分配内存可能会发出系统调用,可能会使用复杂的算法来查找连续的内存以满足您的要求。它甚至可能需要在其他地方移动已分配的内存块。因此,如果您只需要一次分配就可以多次分配内存。