我正在研究递归mergesort算法,并且一个迭代器超出范围。我很肯定我的问题的根源是我的算法存在缺陷,但是我已经花了几天时间倾倒它,我只是没有看到我的错误。我不知道要采取什么方向。有人比我看一看更有经验/更聪明吗? (Github here上提供了带驱动程序的完整程序。)
输出是:
before: 50 5 40 10 30 15 20 20 10 25
after : -1808873259 5 10 10 15 20 20 25 30 40 50
/* ^
* Extra recursive call, and out-of-bounds.
*/
要清楚,我被限制返回类型为T的向量,在本例中为int,但我从this post知道使用void函数更好。
template <typename T>
vector<T> mergesort(typename vector<T>::iterator begin, typename vector<T>::iterator end){
vector<T> newVector;
if (begin!=end){
vector<T> tmp1;
vector<T> tmp2;
typename vector<T>::iterator mid1 = begin;
typename vector<T>::iterator mid2 = begin;
long origDistance = distance(begin,end);
long endOfRange1 = origDistance/2;
long begOfRange2 = endOfRange1+1;
advance(mid1,endOfRange1);
advance(mid2,begOfRange2);
tmp1 = mergesort<T>(begin,mid1);
tmp2 = mergesort<T>(mid2,end);
//"merge()" is from the STL, link in comments.
merge(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end(), back_inserter(newVector));
} else {
newVector.push_back(*begin);
}
return newVector;
}
答案 0 :(得分:2)
begin
时取消引用begin == end
。这是未定义的行为。可能你想要if (origDistance == 1)
然后push_back单个元素并返回。
答案 1 :(得分:1)
如果end
指向向量的最后一个元素,那么您的函数看起来可以正常工作。但是在您的示例程序中,您可以这样称呼它:
newVector = mergesort<int>(vec.begin(), vec.end());
vec.end()
点超过向量的末尾,它不指向最后一个元素。所以你的函数会搞砸,因为它最终会尝试访问你传入的第二个迭代器所指向的元素。
你可以调用你的函数,如:mergesort<int>(vec.begin(), vec.end() - 1);
。
然而,这会让其他人阅读您的代码感到惊讶。重写mergesort
函数以遵循正常的C ++范围约定会更好,也就是说,名为end
的参数应该是过去的。 mid1
应该等于mid2
。
答案 2 :(得分:0)
好的 - 如果没有弄清楚这一点就无法进入睡眠状态,John Zwinck和M.M可以获得巨大的荣誉,让我朝着正确的方向前进 - 这里的代码是得到了正确的输出:
template <typename T>
vector<T> mergesort(typename vector<T>::iterator begin, typename vector<T>::iterator end){
vector<T> newVector;
long origDistance = distance(begin,end); /*Get distance first.*/
if (origDistance==1){ /*Added better anchor case checking for distance.*/
newVector.push_back(*begin);
return newVector;
}
vector<T> tmp1;
vector<T> tmp2;
typename vector<T>::iterator mid1 = begin;
typename vector<T>::iterator mid2 = begin;
long endOfRange1 = origDistance/2;
long begOfRange2 = endOfRange1;/*Edited from: endOfRange+1*/
advance(mid1,endOfRange1);
advance(mid2,begOfRange2);
tmp1 = mergesort<T>(begin,mid1);
tmp2 = mergesort<T>(mid2,end);
merge(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end(), back_inserter(newVector));
return newVector;
}
答案 3 :(得分:-3)
我将在此向您展示如何操作。
template <typename T>
void mergesort(typename vector<T>::iterator, typename vector<T>::iterator);
// ...
mergesort<int>(vec.begin(), vec.end());
newVector = vec;
// ...
template <typename T>
void mergesort(typename vector<T>::iterator begin, typename vector<T>::iterator end){
auto const N = std::distance(begin, end);
if (N <= 1) return;
auto const middle = std::next(begin, N / 2);
mergesort<T>(begin, middle);
mergesort<T>(middle, end);
std::inplace_merge(begin, middle, end);
}
正确输出:
before: 50 5 40 10 30 15 20 20 10 25
after : 5 10 10 15 20 20 25 30 40 50
STL已经有inplace_merge,为什么要重新实现呢?通过这种方法,你不必认为边界很难。