我正在尝试使用另一个向量v2对向量v1进行排序。我无法解决这个错误:
运行此代码时在抛出'std :: out_of_range'实例后终止调用 what():vector :: _ M_range_check
中止陷阱
:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
class Comp
{
public:
Comp(vector<double>& inVec): _V(inVec) {}
bool operator()(int i, int j) {return (_V.at(i)<_V.at(j));}
private:
vector<double> _V;
};
int main(int argc, char** argv)
{
double x1[] = {90.0, 100.0, 80.0};
double x2[] = {9.0, 3.0, 1.0};
vector<double> v1(x1,x1+3);
vector<double> v2(x2,x2+3);
sort(v1.begin(), v1.end(), Comp(v2)); // sort v1 according to v2
for(unsigned int i=0; i<v1.size(); i++)
{
cout << v1.at(i) << " " << v2.at(i) << endl;
}
return 0;
}
v1
和v2
的大小相同。为什么out_of_range
错误?
提前感谢任何指示。
答案 0 :(得分:9)
我相信你的问题就在这一行:
bool operator()(int i, int j) {return (_V.at(i)<_V.at(j));}
问题是当std::sort
算法使用自定义回调时,它会传递存储在vector
特定位置的实际值,而不是那些索引 vector
内的位置。结果,当你打电话
sort(v1.begin(), v1.end(), Comp(v2)); // sort v1 according to v2
您编写的Comp
比较器将作为参数传递给存储在v1
向量中的值,然后尝试将这些位置索引到v2
向量中。由于v1
中的值大于v2
的大小,因此对_V.at(i)
的调用将导致抛出out_of_range
异常。
如果要相对于彼此对两个范围进行排序,则需要采用不同的方法。我不知道这样做的直接方式,但如果我想到一个,我会告诉你的。
答案 1 :(得分:6)
v1
的大小仅为3
,但您使用v2
的每个值作为v1
的索引。由于v2
的一个值9
大于v1
的大小,因此这里会出现std::out_of_range
错误:
bool operator()(int i, int j) {return (_V.at(i)<_V.at(j));}
std::vector::at
函数给传递给它的索引的std::out_of_range
异常,因为参数大于向量的大小。也就是说,索引必须小于vector::size()
。
答案 2 :(得分:4)
与其他答案中的说法一样,问题是排序算法将实际值传递给比较而不是索引。
以下是解决问题的方法:
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
typedef pair<double, double> Zipped; // Represent an element of two lists
// "zipped" together
// Compare the second values of two pairs
bool compareSeconds ( Zipped i, Zipped j )
{
return i.second < j.second;
}
int main ( int argc, char **argv )
{
double x1[] = { 90, 100, 80 };
double x2[] = { 9, 3, 1 };
vector<double> v1(x1, x1 + 3);
vector<double> v2(x2, x2 + 3);
vector<Zipped> zipped(v1.size()); // This will be the zipped form of v1
// and v2
for ( int i = 0; i < zipped.size(); ++i )
{
zipped[i] = Zipped(v1[i], v2[i]);
}
sort(zipped.begin(), zipped.end(), &compareSeconds);
for ( int i = 0; i < zipped.size(); ++i )
{
cout << zipped[i].first << " " << zipped[i].second << endl;
}
for ( int i = 0; i < v1.size(); ++i )
{
v1[i] = zipped[i].first;
}
// At this point, v1 is sorted according to v2
return 0;
}
答案 3 :(得分:4)
好的,现在您可能已经意识到这样一个事实,即i
和j
是vector
中保留的实际值而不是索引。有一个很好的理由:排序完全是关于值,而不是索引。请注意,您将迭代器传递给sort
方法,因此无法为您提取索引。当然,您可以获得相对于第一个迭代器的索引,但没有理由这样做。
然而,让我们疯狂一段时间,并想象你会在比较器中得到指数而不是值。假设您的代码符合您的要求,让我们考虑以下场景:
v1 = {20,10}; v2 = {2,1}
我暗地里假设你想要以下输出:
v1 = {10, 20}
正确?现在假设我是一个你正在调用的排序函数,我按照以下步骤操作:
v2[0] < v2[1]
为false,因此swap(&v1[0], &v1[1])
它已经分类了,不是吗?但是等等,我是一个疯狂的排序函数,所以我想确保它已经排序,所以我做了以下几点:
v2[0] < v2[1]
为false,swap(&v1[0], &v1[1])
再次:
v2[0] < v2[1]
为false,swap(&v1[0], &v1[1])
再一次又一次......
你能看到问题吗?排序功能有一些要求,并且肯定会打破基本功能。
我怀疑你需要完全不同的容器(可能std::map
使用来自vec1
的键和来自vec2
的值)或至少类似vector< pair<double, double> >
的容器,因此您可以轻松排序通过第一或第二值。如果没有,请考虑使用范围vector
中的值创建[0, v2.size())
,使用比较器对其进行排序(值等于索引,这样就可以了),然后从v1
打印正确的值。这段代码工作正常:
vector<size_t> indices;
for(size_t i =0; i < v1.size(); ++i)
{
indices.push_back(i);
}
// yes, it works using your original comparator
sort(indices.begin(), indices.end(), Comp(v2));
for(size_t i =0; i < indices.size(); ++i)
{
cout << v1.at(indices[i]) << " " << v2.at(indices[i]) << endl;
}