C++ 为什么向量迭代器指向边界之外?
我正在研究一个递归的mergesort算法,一个迭代器出界了。我敢肯定,我的问题的根源是我的算法有缺陷,但我已经花了好几天的时间来研究它,我只是没有看到我的失误。我不知道该往哪个方向走。能找个比我更有经验/更聪明的人看看吗?(Github上提供了带驱动程序的完整程序。) 输出为:C++ 为什么向量迭代器指向边界之外?,c++,algorithm,c++11,recursion,mergesort,C++,Algorithm,C++11,Recursion,Mergesort,我正在研究一个递归的mergesort算法,一个迭代器出界了。我敢肯定,我的问题的根源是我的算法有缺陷,但我已经花了好几天的时间来研究它,我只是没有看到我的失误。我不知道该往哪个方向走。能找个比我更有经验/更聪明的人看看吗?(Github上提供了带驱动程序的完整程序。) 输出为: before: 50 5 40 10 30 15 20 20 10 25 after : -1808873259 5 10 10 15 20 20 25 30 40 50 /* ^ * E
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,但是我知道使用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;
}
模板
向量合并排序(typename向量::迭代器开始,typename向量::迭代器结束){
向量newVector;
如果(开始!=结束){
载体tmp1;
载体tmp2;
typename向量::迭代器mid1=开始;
typename向量::迭代器mid2=开始;
长距离=距离(开始、结束);
长内法兰1=起始距离/2;
长起始范围2=内折1+1;
提前(中期1,中期1);
前进(中段2,起始段2);
tmp1=合并排序(开始,中间1);
tmp2=合并排序(中间2,结束);
//“merge()”来自STL,注释中的链接。
合并(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end(),back_inserter(newVector));
}否则{
newVector.push_back(*开始);
}
返回newVector;
}
当begin==end
时,取消引用begin
。这是未定义的行为。可能您希望如果(origDistance==1)
则将单个元素推回并返回。您在开始==end
时解除对开始的引用。这是未定义的行为。可能您希望如果(origDistance==1)
则将单个元素推回并返回。这里我将向您演示如何执行此操作
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);
}
STL已经就位了,为什么要重新实现它呢?使用这种方法,你不必费心思考,因为它有着难以逾越的界限。在这里,我将向你展示如何做到这一点
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);
}
STL已经就位了,为什么要重新实现它呢?使用这种方法,您不必考虑边界问题。如果end
指向向量的最后一个元素,您的函数看起来可以工作。但是,在示例程序中,您可以这样称呼它:
newVector=mergesort(vec.begin(),vec.end());
vec.end()。因此,您的函数会出错,因为它最终会尝试访问您传入的第二个迭代器所指向的元素
您可以像这样调用函数:mergesort(vec.begin(),vec.end()-1)代码>
但是,这会让阅读您的代码的其他人感到惊讶。重写你的代码>合并代码> >代码>函数,遵循正常的C++范围约定,也就是说,参数<代码>结束>代码>应该结束。code>mid1
应等于mid2
如果end
指向向量的最后一个元素,则函数看起来可以工作。但是,在示例程序中,您可以这样称呼它:
newVector=mergesort(vec.begin(),vec.end());
vec.end()。因此,您的函数会出错,因为它最终会尝试访问您传入的第二个迭代器所指向的元素
您可以像这样调用函数:mergesort(vec.begin(),vec.end()-1)代码>
但是,这会让阅读您的代码的其他人感到惊讶。重写你的代码>合并代码> >代码>函数,遵循正常的C++范围约定,也就是说,参数<代码>结束>代码>应该结束。code>mid1
应该等于mid2
好的-如果不弄清楚这一点,就无法入睡,这是我获得正确方向的巨大功劳-以下是获得正确输出的代码:
before: 50 5 40 10 30 15 20 20 10 25
after : 5 10 10 15 20 20 25 30 40 50
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;
}
模板
向量合并排序(typename向量::迭代器开始,typename向量::迭代器结束){
向量newVector;
long origDistance=距离(开始、结束);/*首先获取距离*/
如果(origDistance==1){/*添加了更好的锚案例检查距离*/
newVector.push_back(*开始);
返回newVector;
}
载体tmp1;
载体tmp2;
typename向量::迭代器mid1=开始;
typename向量::迭代器mid2=开始;
长内法兰1=起始距离/2;
long begOfRange2=endOfRange1;/*编辑自:endOfRange+1*/
提前(中期1,中期1);
前进(中段2,起始段2);
tmp1=合并排序(开始,中间1);
tmp2=合并排序(中间2,结束);
合并(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end(),back_inserter(newVector));
返回newVector;
}
好的-如果不弄清楚这一点,我就无法入睡,这是让我走上正确方向的巨大功劳-以下是获得正确输出的代码:
before: 50 5 40 10 30 15 20 20 10 25
after : 5 10 10 15 20 20 25 30 40 50
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;
}
模板
向量合并排序(typename向量::迭代器开始,typename向量::迭代器结束){
向量newVector;
long origDistance=距离(开始、结束);/*首先获取距离*/
如果(origDistance==1){/*添加了更好的锚案例检查距离*/
newVector.push_back(*开始);
返回newVector;
}
载体tmp1;
载体tmp2;
typename向量::迭代器mid1=开始;
typename向量::迭代器mid2=开始;
长内法兰1=起始距离/2;
long begOfRange2=endOfRange1;/*编辑自:endOfRange+1*/
提前(中期1,中期1);
前进(中段2,起始段2);
tmp1=合并排序(开始,中间1);
tmp2=合并排序(中间2,结束);
合并(tmp1.begin(),tmp1.end(),tmp2.begin(),tmp2.end(),back_inserter(newVector));
返回newVector;
}
例如,将很快更新输出。您是否知道某个向量.end()
不是最后一个元素,而是最后一个元素之后的元素?取消对它的引用是违法的。我不知道这是什么意思