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

时间:2017-07-07 14:49:30

标签: c++ sorting merge

我已经使用矢量作为函数在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;

}

2 个答案:

答案 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)中完成),但您应该记住分配内存如果您不使用自定义分配器,则堆是昂贵的操作。分配内存可能会发出系统调用,可能会使用复杂的算法来查找连续的内存以满足您的要求。它甚至可能需要在其他地方移动已分配的内存块。因此,如果您只需要一次分配就可以多次分配内存。