如何使用C++有效地合并排序与向量

How to efficiently merge sort with vectors using C++

本文关键字:排序 向量 合并 有效地 何使用 C++      更新时间:2023-10-16

我通过使用向量作为函数在 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;

}

好吧,不需要在每次调用合并时创建新空间。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);

在Github上,你可以找到我不久前实现的mergesort版本。我想应该足够了。

合并排序唯一需要的额外内存是大小n数组,用于合并算法任何步骤产生的两个排序vector中的任何一个。显然,您的解决方案使用更多。在第一次合并时,它分配两个长度n/2向量,然后它将是四个n/4向量,以此类推,总共给出n * log(n)。这比n略多.

分配vector的成本通常与其长度呈线性关系(如果复制vector的元素可以在 O(1( 中完成(,但您应该记住,如果您不使用自定义分配器,则在堆上分配内存是昂贵的操作。分配内存可能会发出系统调用,系统调用可能会使用复杂的算法来查找连续的内存片段以满足您的要求。它甚至可能需要将已经分配的内存片段移动到其他地方。因此,如果您可以坚持只进行一次分配,那么多次分配内存确实没有意义。