C++ 递归合并排序算法的实现

C++ 递归合并排序算法的实现,c++,algorithm,sorting,mergesort,C++,Algorithm,Sorting,Mergesort,我是算法的新手。我尝试使用std::vector实现递归合并排序。但是我被卡住了。代码不起作用 我已经从《算法导论》(Cormen/Leiserson/Rivest/Stein第三版)中了解了算法。我试图实现的伪代码 这里是我的合并功能: void merge(std::vector<int>& vec, size_t vec_init, size_t vec_mid, size_t vec_size) { int leftLoop = 0; int rightLoo

我是算法的新手。我尝试使用
std::vector
实现递归合并排序。但是我被卡住了。代码不起作用

我已经从《算法导论》(Cormen/Leiserson/Rivest/Stein第三版)中了解了算法。我试图实现的伪代码

这里是我的合并功能:

void merge(std::vector<int>& vec, size_t vec_init, size_t vec_mid, size_t vec_size) {
  int leftLoop = 0;
  int rightLoop = 0;
  int vecLoop = 0;
  size_t mid = vec_mid - vec_init + 1;

  std::vector<int> Left_Vec(std::begin(vec), std::begin(vec) + mid);
  std::vector<int> Right_Vec(std::begin(vec) + mid, std::end(vec));

  for (size_t vecLoop = vec_init; vecLoop<vec_size; ++vecLoop) {
      vec[vecLoop] = (Left_Vec[leftLoop] <= Right_Vec[rightLoop]) ? Left_Vec[leftLoop++] : Right_Vec[rightLoop++];
  }
}

关于算法或代码,我的错误在哪里?

有几个问题。这些更改将修复代码:

void merge(std::vector<int>& vec, size_t vec_start, size_t vec_mid, size_t vec_end) {
  size_t leftLoop = 0;
  size_t rightLoop = 0;
  size_t vecLoop = 0;
  // Not needed, much simpler if mid is relative to vec.begin()
  //size_t mid = vec_mid - vec_init + 1;

  // You didn't take vec_init and vec_size into account when calculating the ranges.
  std::vector<int> Left_Vec(std::begin(vec) + vec_start, std::begin(vec) + vec_mid);
  std::vector<int> Right_Vec(std::begin(vec) + vec_mid, std::begin(vec) + vec_end);

  // Values are not uniformly distributed in the left and right vec. You have to check for
  // running out of elements in any of them.
  for (/*size_t*/ vecLoop = vec_start; leftLoop < Left_Vec.size() && rightLoop < Right_Vec.size(); ++vecLoop) {
    //   ^~~~~ shadowed outer vecLoop  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    vec[vecLoop] = Left_Vec[leftLoop] <= Right_Vec[rightLoop] ? Left_Vec[leftLoop++] : Right_Vec[rightLoop++];
  }

  // Copy the rest of the values into vec.
  if (leftLoop == Left_Vec.size())
    std::copy(Right_Vec.begin() + rightLoop, Right_Vec.end(), vec.begin() + vecLoop);
  else
    std::copy(Left_Vec.begin() + leftLoop, Left_Vec.end(), vec.begin() + vecLoop);
}

void merge_sort(std::vector<int>& vec, size_t vec_start, size_t vec_end) {
  // Should only run the function if there are at least 2 elements, otherwise vec_mid
  // would be always at least vec_start + 1 and the recursion would never stop.
  if (vec_end - vec_start >= 2) {
    size_t vec_mid = (vec_start + vec_end) / 2;
    merge_sort(vec, vec_start, vec_mid);
    merge_sort(vec, vec_mid /* + 1 */, vec_end);
    //                         ^~~ + 1 here would skip an element
    merge(vec, vec_start, vec_mid, vec_end);
  }
}
void合并(标准::向量和向量,大小向量开始,大小向量中间,大小向量结束){
大小\u t leftLoop=0;
大小\u t rightLoop=0;
大小=0;
//不需要,如果mid相对于vec.begin()更简单
//size_t mid=vec_mid-vec_init+1;
//在计算范围时,您没有考虑vec_init和vec_size。
标准::向量左向量(标准::开始(向量)+向量开始,标准::开始(向量)+向量中间);
std::vector Right\u Vec(std::begin(Vec)+Vec\u mid,std::begin(Vec)+Vec\u end);
//值在左右vec中的分布不均匀。您必须检查
//它们中的任何元素都已用完。
对于(/*size\u t*/vecLoop=vec\u start;leftLoop
有几个问题。这些更改将修复代码:

void merge(std::vector<int>& vec, size_t vec_start, size_t vec_mid, size_t vec_end) {
  size_t leftLoop = 0;
  size_t rightLoop = 0;
  size_t vecLoop = 0;
  // Not needed, much simpler if mid is relative to vec.begin()
  //size_t mid = vec_mid - vec_init + 1;

  // You didn't take vec_init and vec_size into account when calculating the ranges.
  std::vector<int> Left_Vec(std::begin(vec) + vec_start, std::begin(vec) + vec_mid);
  std::vector<int> Right_Vec(std::begin(vec) + vec_mid, std::begin(vec) + vec_end);

  // Values are not uniformly distributed in the left and right vec. You have to check for
  // running out of elements in any of them.
  for (/*size_t*/ vecLoop = vec_start; leftLoop < Left_Vec.size() && rightLoop < Right_Vec.size(); ++vecLoop) {
    //   ^~~~~ shadowed outer vecLoop  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    vec[vecLoop] = Left_Vec[leftLoop] <= Right_Vec[rightLoop] ? Left_Vec[leftLoop++] : Right_Vec[rightLoop++];
  }

  // Copy the rest of the values into vec.
  if (leftLoop == Left_Vec.size())
    std::copy(Right_Vec.begin() + rightLoop, Right_Vec.end(), vec.begin() + vecLoop);
  else
    std::copy(Left_Vec.begin() + leftLoop, Left_Vec.end(), vec.begin() + vecLoop);
}

void merge_sort(std::vector<int>& vec, size_t vec_start, size_t vec_end) {
  // Should only run the function if there are at least 2 elements, otherwise vec_mid
  // would be always at least vec_start + 1 and the recursion would never stop.
  if (vec_end - vec_start >= 2) {
    size_t vec_mid = (vec_start + vec_end) / 2;
    merge_sort(vec, vec_start, vec_mid);
    merge_sort(vec, vec_mid /* + 1 */, vec_end);
    //                         ^~~ + 1 here would skip an element
    merge(vec, vec_start, vec_mid, vec_end);
  }
}
void合并(标准::向量和向量,大小向量开始,大小向量中间,大小向量结束){
大小\u t leftLoop=0;
大小\u t rightLoop=0;
大小=0;
//不需要,如果mid相对于vec.begin()更简单
//size_t mid=vec_mid-vec_init+1;
//在计算范围时,您没有考虑vec_init和vec_size。
标准::向量左向量(标准::开始(向量)+向量开始,标准::开始(向量)+向量中间);
std::vector Right\u Vec(std::begin(Vec)+Vec\u mid,std::begin(Vec)+Vec\u end);
//值在左右vec中的分布不均匀。您必须检查
//它们中的任何元素都已用完。
对于(/*size\u t*/vecLoop=vec\u start;leftLoop
如果删除合并排序中的+1(vec、vec\u mid+1、vec\u size),会发生什么情况;你的
merge
函数坏得很厉害。你访问的内存超出了你分配的向量的范围。我将在线查看一些正在工作的合并函数。你试图在循环中太聪明。你需要至少两个单独的循环才能使该函数工作。初始化
Right\u Vec
时,你复制
vec
upto
std::end(vec)
,即使在对一部分进行排序时也是如此。更有效的方法是一次性分配一个完整大小的工作向量,然后根据递归级别在两个向量之间进行合并,类似于中的示例,但合并效率更高。使用一对相互递归的函数可以避免临时向量的初始副本函数(一个将原始文件合并回原始文件,一个将原始文件合并到临时文件,每个函数调用另一个)。如果删除合并排序中的+1(vec,vec\u mid+1,vec\u size),会发生什么情况;你的
merge
函数坏得很厉害。你访问的内存超出了你分配的向量的范围。我将在线查看一些正在工作的合并函数。你试图在循环中太聪明。你需要至少两个单独的循环才能使该函数工作。初始化
Right\u Vec
时,你复制
vec
upto
std::end(vec)
,即使在对一部分进行排序时也是如此。更有效的方法是一次性分配一个完整大小的工作向量,然后根据递归级别在两个向量之间进行合并,类似于中的示例,但合并效率更高。使用一对相互递归的函数可以避免临时向量的初始副本函数(一个将原始文件合并回原始文件,一个将原始文件合并到临时文件,每个函数调用另一个)。
void merge(std::vector<int>& vec, size_t vec_start, size_t vec_mid, size_t vec_end) {
  size_t leftLoop = 0;
  size_t rightLoop = 0;
  size_t vecLoop = 0;
  // Not needed, much simpler if mid is relative to vec.begin()
  //size_t mid = vec_mid - vec_init + 1;

  // You didn't take vec_init and vec_size into account when calculating the ranges.
  std::vector<int> Left_Vec(std::begin(vec) + vec_start, std::begin(vec) + vec_mid);
  std::vector<int> Right_Vec(std::begin(vec) + vec_mid, std::begin(vec) + vec_end);

  // Values are not uniformly distributed in the left and right vec. You have to check for
  // running out of elements in any of them.
  for (/*size_t*/ vecLoop = vec_start; leftLoop < Left_Vec.size() && rightLoop < Right_Vec.size(); ++vecLoop) {
    //   ^~~~~ shadowed outer vecLoop  ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    vec[vecLoop] = Left_Vec[leftLoop] <= Right_Vec[rightLoop] ? Left_Vec[leftLoop++] : Right_Vec[rightLoop++];
  }

  // Copy the rest of the values into vec.
  if (leftLoop == Left_Vec.size())
    std::copy(Right_Vec.begin() + rightLoop, Right_Vec.end(), vec.begin() + vecLoop);
  else
    std::copy(Left_Vec.begin() + leftLoop, Left_Vec.end(), vec.begin() + vecLoop);
}

void merge_sort(std::vector<int>& vec, size_t vec_start, size_t vec_end) {
  // Should only run the function if there are at least 2 elements, otherwise vec_mid
  // would be always at least vec_start + 1 and the recursion would never stop.
  if (vec_end - vec_start >= 2) {
    size_t vec_mid = (vec_start + vec_end) / 2;
    merge_sort(vec, vec_start, vec_mid);
    merge_sort(vec, vec_mid /* + 1 */, vec_end);
    //                         ^~~ + 1 here would skip an element
    merge(vec, vec_start, vec_mid, vec_end);
  }
}