自定义类对象及其<运算符集
Set of custom class objects and their < operator
我正在尝试实现A* algorithm
(在Qt中进行可视化)。我有这样的方法:
result_path astar_algorithm::calculate(mapview* m_view)
{
map_view = m_view;
auto closed_set = std::vector<std::shared_ptr<node>>();
auto start_node = std::make_shared<node>(_start);
auto open_set = std::vector<std::shared_ptr<node>>{start_node};
std::map<node, node> came_from;
std::shared_ptr<node> current;
while (!open_set.empty())
{
current = *std::min_element(open_set.begin(), open_set.end());
if (*current == _end)
{
// TODO: Reconstruct a result path!!!
break;
}
open_set.erase(std::find(open_set.begin(), open_set.end(), current));
closed_set.push_back(current);
auto neighbors = get_neighbors(*current);
for (auto& neighbor : neighbors)
{
if (std::find_if(closed_set.begin(), closed_set.end(),
[&](std::shared_ptr<node> const& p) { return *p == neighbor; }) !=
closed_set.end())
continue;
auto tentative_g_score = current->G + 1;
if (std::find_if(open_set.begin(), open_set.end(), [&](std::shared_ptr<node> const& p) {
return *p == neighbor;
}) == open_set.end())
{
neighbor.G = tentative_g_score;
neighbor.H = heuristic_cost_estimate(neighbor.pos, _end);
neighbor.parent = current;
open_set.push_back(std::make_shared<node>(neighbor));
}
else if (tentative_g_score < neighbor.G)
{
neighbor.parent = current;
neighbor.G = tentative_g_score;
}
}
}
auto result = result_path();
while (*current != *start_node)
{
result.path.push_back(current->pos);
current = current->parent;
}
result.path.push_back(start_node.pos);
std::reverse(result.path.begin(), result.path.end());
return result;
}
它有效,但我有一些问题:
if (std::find_if(closed_set.begin(), closed_set.end(),
[&](std::shared_ptr<node> const& p) { return *p == neighbor; }) !=
closed_set.end())
continue;
这条线检查node
是否存在于std::vector
中,如果存在,则继续循环(然后还有第二条类似的线,它只是检查节点是否实际不存在于向量中)。我想更好的方法是将这些节点存储在向量中,然后搜索和进一步添加会更容易(因为我只需要检查insert
是否成功)。
问题是,为了使这项工作发挥作用,我必须实现<
运算符。我就这么做了。我还制作了==
和!=
:
class node
{
public:
node() {}
node(const QPoint& p) : pos(p) {}
bool operator == (const node& o ) const { return pos == o.pos; }
bool operator == (const QPoint& o ) const { return pos == o; }
bool operator != (const node& o) const {return pos != o.pos; }
bool operator <(const node& o ) const { return G + H < o.G + o.H; }
QPoint pos;
std::shared_ptr<node> parent;
int G = 0;
int H = 0;
};
它非常适合早期搜索std::min_element
(它搜索具有最低F
值(F=G+H
)的节点),它使用<
运算符。但后来我尝试使用集合,所以在方法开始时设置了这两个向量,当我只想insert
,甚至检查一个节点是否已经在集合中,然后insert
时,我遇到了问题。其中许多nodes
将具有相同的G+H
值,因为我使用的迷宫有点简单(即完全没有地形的迷宫)。我在调试器下检查了它,具有唯一.pos
值(QPoint
)的节点并没有被添加到集合中,就像它们不是唯一的一样(但如果该节点的G+H
值与集合中的任何节点都不同,它就会被添加)。对于向量,相同的节点当然可以工作,因为没有进行检查,我在调试器下仔细检查了所有内容。
我不知道我是否搞错了,但我以为它会使用==
或!=
运算符,但正如这个答案所示:链接,它实际上使用了<
运算符,在我的情况下,它不会区分两个节点(因为每个节点的唯一部分是它在网格中的位置(节点表示网格中的一个框,可以表示迷宫或类似的smth)
那么,是我做错了什么,还是我真的做对了,插入(检查元素是否唯一)或检查元素是否存在于集合中使用了<
运算符,而我对此无能为力?(因为我希望我的<
运算符与G+H
进行比较,然后我希望搜索/插入使用==
运算符进行比较)
这是我写的例子(我忘了我在命令行cl.exe
中有Microsoft C++编译器)
#include <algorithm>
#include <iostream>
#include <memory>
#include <set>
class Point
{
public:
int _x, _y;
Point() : _x(0), _y(0) {}
Point(int x, int y) : _x(x), _y(y) {}
bool operator==(const Point& p) const { return _x == p._x && _y == p._y; }
bool operator!=(const Point& p) const { return _x != p._x && _y != p._y; }
};
class node
{
public:
node() {}
node(const Point& p) : pos(p) {}
bool operator==(const node& o) const { return pos == o.pos; }
bool operator==(const Point& o) const { return pos == o; }
bool operator!=(const node& o) const { return pos != o.pos; }
bool operator<(const node& o) const { return G + H < o.G + o.H; }
Point pos;
std::shared_ptr<node> parent;
int G = 0;
int H = 0;
};
int main()
{
node n1(Point(0, 0));
n1.G = 1;
n1.H = 1;
node n2(Point(1, 1));
n2.G = 2;
n2.H = 2;
node n3(Point(2, 2));
n3.G = 1;
n3.H = 1;
std::set<node> nodes;
nodes.insert(n1);
nodes.insert(n2);
nodes.insert(n3);
auto min = (*std::min_element(nodes.begin(), nodes.end())).pos;
std::cout << min._x << " " << min._y << 'n';
std::cout << nodes.size() << 'n';
}
>main.exe
0 0
2
std::min_element
有效,但这对我来说是3个唯一的节点(不同的.pos
值),所以集合中应该有3个节点。这就是我想要实现的
我以为它会使用
==
或!=
运算符
否,std::set
不使用运算符==
和!=
,std::set
只使用一个函数,即比较函数(第二个模板参数,默认为std::less<T>
)。
唯一性基于等价关系,该等价关系是通过两次应用相同的比较函数导出的:!a<b && !b<a
。
似乎您并不真正需要唯一性,在这种情况下,您可以使用std::multiset
。它将维持秩序,但不会强制执行唯一性。
std::set<node> nodes; . . . auto min = (*std::min_element(nodes.begin(), nodes.end())).pos;
std::min_element
总是O(N)。在set
上使用它会破坏拥有set
的目的。只需获取第一个元素,它将是最小的(根据比较函数)。
auto min = begin(nodes)->pos;
- 如何防止clang格式在流运算符调用之间添加换行符<<
- 如何显式调用运算符<<
- 为什么COUT在朋友函数中不起作用,该功能超载了操作员&lt;&lt;这是一个iStream运算符
- C++运算符<<调用::ostream而不是std::osttream
- BOOST ::变体无法解决运算符&lt;&lt;对于STD :: Ostream
- 过载输出<<用于类的运算符,以打印其中的元组
- C++ostream:没有运算符匹配<<&应在'&'代币
- 重载运算符<<:此运算符函数的参数太多
- C++继承运算符<<
- 重载运算符<<用于模板类.即使使用好友关键字也无法获得私人会员
- 如何过载<<用于YAML::Emitter的运算符,以序列化包含另一个自定义类的向量的自定义类
- 为什么字符串流运算符<<擦除原始值
- 关于使用运算符<<为新手提供C++中的模板
- 我已经完成了<<运算符重载,但它'It’不起作用
- 重载运算符<<输出地址而不是数据成员
- 错误:没有匹配'运算符<<"在'std::cout
- 重载运算符<<用于ostream语法
- 当运算符<存在时,为什么要定义 LT?
- log4cxx访问异常,使用<<运算符和宏
- 重载<<运算符错误C2804:二进制'运算符<<'参数太多