我有一个结构作为键的地图,我已经重载了<
运算符,但是地图将每个条目存储为单独的键,即使它们是相同的。代码如下:
#include <iostream>
#include <vector>
#include <map>
using namespace std;
struct vertex
{
int color;
vertex *pi;
int index;
bool operator<(const vertex & v ) const {
return this->index < v.index;
}
bool operator==(const vertex & v) const {
return this->index == v.index;
}
};
int main()
{
int x, y, num_edges;
vector<vertex* > v;
vertex *temp1, *temp2, *temp;
map<vertex*, vector<vertex*> > m;
map<vertex*, vector<vertex*> >::iterator it;
cout << "\nEnter no. of edges: ";
cin >> num_edges;
for( int i = 0; i < num_edges; i++ )
{
cout << "\nEnter source: ";
cin >> x;
cout << "\nEnter dest: ";
cin >> y;
temp1 = new vertex;
temp2 = new vertex;
temp1->index = x;
temp2->index = y;
m[temp1].push_back(temp2);
m[temp2].push_back(temp1);
}
temp1 = new vertex;
temp2 = new vertex;
cout << "\nPrinting map: " << endl;
for( it = m.begin(); it != m.end(); it++ )
{
temp = (*it).first;
cout << temp->index << "\t";
v = (*it).second;
for( int i = 0; i < v.size(); i++ )
{
temp1 = v[i];
cout << temp1->index << "\t";
}
cout << "\n";
v.clear();
}
for( it = m.begin(); it != m.end(); it++ )
{
temp = (*it).first;
v.push_back(temp);
}
return 0;
}
我现在得到的输出是:
Enter no. of edges: 4
Enter source: 1
Enter dest: 3
Enter source: 4
Enter dest: 3
Enter source: 4
Enter dest: 2
Enter source: 2
Enter dest: 1
Printing map:
1 3
3 1
4 3
3 4
4 2
2 4
2 1
1 2
但它应该是:
1 3 2
2 4 1
3 1 4
4 3 2
我哪里错了?
答案 0 :(得分:2)
std :: map会将你给它的类型作为键(vertex*
)进行比较,但你在顶点定义<
运算符。
您可以将结构本身用作键,或者 - 如果必须使用指针 - 您必须为地图提供比较指针的方法。
现在,std::map
使用std::less
作为比较谓词,在<
的therm中定义(这就是为什么使用struct本身,你可以通过重载来实现结果{{ 1}})。
你可以:
o)定义一个比较顶点*的谓词:它可以是
<
然后将地图定义为
template <class T> //assume T is a pointer or pointer-like class
struct redirected_less : public std::binary_function <T,T,bool>
{
bool operator() (const T& x, const T& y) const {return *x < *y;}
};
o)将std :: less for vertex *专门化为
std::map<vertex*, vector<vertex*>, redirected_less<vertex*> >
并将您的地图声明为
namespace std
{
template <>
struct less<vertex*> : binary_function <vertex*,vertex*,bool>
{
bool operator() (vertex* x, vertex* y) const {return *x < *y; }
};
}
像往常一样。
我个人更喜欢第一个(提供更本地化的代码,在未来的读数中减少“奥术”)
答案 1 :(得分:1)
您不能将指针用作键。如果你有结构,根据你的规则是“相同的”,但是用new
分配堆,那么它们的指针将永远不会相同。
使用结构而不是指针作为关键。
答案 2 :(得分:1)
map<vertex*, vector<vertex*> > m;// its key type vertex*
m使用
bool operator < (vertex * const, vertex* const) ;
订购时
所以你需要重载
bool operator < (vertex * const, vertex* const);
我们这里有一个问题。我们不能重载指针。我们可以像这样提供我们自己的比较函数:
struct cmp{
bool operator ()(vertex * const first, vertex* const second)
{ return first.index < second->index;}
};
cmp _cmp;
map<vertex*, vector<vertex*>, cmp> m(_cmp);
答案 3 :(得分:0)
Emilio Garavaglia analyzed the problem with your code and how to fix it很好。但是,如果可以使用C++11功能,则可以稍微现代化解决方案。例如,您可以使用lambda expression而不是为结构定义operator<
,并将其传递给地图的构造函数。如果您无法修改要存储在地图中的结构,或者要为不同的地图提供不同的比较功能,则此方法很有用。 Range-based for
loops使您不必处理迭代器,而占位符auto
使您不必指定冗长的容器元素类型。我还要提及的是,您无需指定operator==
即可使用地图。
vertex
为键的解决方案为清楚起见,我将用户输入替换为硬编码值:
struct vertex {
int color;
vertex *pi;
int index;
};
int main() {
auto comp = [](const vertex& v1, const vertex& v2) { return v1.index < v2.index; };
std::map<vertex, std::vector<vertex>, decltype(comp)> m(comp);
// Replace user input.
std::vector<std::pair<int, int>> edges = { {1, 3}, {4, 3}, {4, 2}, {2, 1} };
// Fill the map.
for(auto const &e : edges) {
vertex temp1;
vertex temp2;
temp1.index = e.first;
temp2.index = e.second;
m[temp1].push_back(temp2);
m[temp2].push_back(temp1);
}
// Print the map.
std::cout << "Printing map:" << std::endl;
for (auto const &kv : m) {
std::cout << kv.first.index << " =>";
for (auto const &v : kv.second)
std::cout << " " << v.index;
std::cout << std::endl;
}
return 0;
}
输出:
打印地图:
1 => 3 2
2 => 4 1
3 => 1 4
4 => 3 2
注意:如果可以使用C++17,则可以进一步使用structured binding缩短用于打印地图的代码,如here on Coliru所示。 / p>
vertex*
为键的解决方案基本上,您必须将以上代码中所有出现的vertex
替换为vertex*
。另外,您必须确保lambda表达式不比较给定的指针,而是比较指针所引用的结构的内容:
auto comp = [](const vertex* pv1, const vertex* pv2) { return pv1->index < pv2->index; };
std::map<vertex*, std::vector<vertex*>, decltype(comp)> m(comp);
还必须确保最后删除所有动态分配的顶点。例如,您可以通过以下方式正确清空地图:
for (auto const &kv : m)
for (auto const pv : kv.second)
delete pv;
m.clear();
注意:为了简化内存管理,您应该更喜欢在地图中存储smart pointers,例如std::unique_ptr
或std::shared_ptr
。