如何解决使用自定义比较器定义映射,其中值数据结构也具有自定义比较器
我想定义一个数据结构,例如:
struct node {
int x_coordinate;
int y_coordinate;
// some variables
};
map<node,priority_queue<node> > M;
// or lets say
map<node,set<node> > M
我面临的问题是我不知道如何编写自定义比较器
您还认为是否有可能根据距关键节点的距离对priority_queue进行排序。例如,假设我的关键节点的x_coordinate = 0和y_coordinate = 0,并且我想插入(8,6),(4,3),(15,9),(0,1)。
所以priority_queue类似于(0,1)(4,3)(8,6)(15,9)
P.S。 :与人讨论后,我使用了以下代码,但仍会给出编译错误
struct Node {
Node (int a,int b) {
x = a;
y = b;
}
int x,y;
};
struct cmp {
Node node(0,0); // this node corresponds to the node that came from map key
cmp(Node node) {
this->node = node;
}
int getdistance (Node a,Node b) {
return abs(a.x - b.x) + abs(a.y - b.y);
}
bool operator () (Node node1,Node node2) {
return (getdistance(node,node1) < getdistance(node,node2));
}
};
int main() {
auto mapCmp = [&] (Node node1,Node node2){
return node1.x < node2.x and (node1.x == node2.x and node1.y < node2.y);
};
map<Node,priority_queue<Node,vector<Node>,cmp(Node)>,decltype(mapCmp)> myMap(mapCmp);
myMap[Node(0,0)].push(Node(2,4));
myMap[Node(0,0)].push(Node(1,3));
myMap[Node(0,1)].push(Node(2,1)].push(Node(1,3));
return 0;
}
错误快照:
解决方法
有趣的问题。后面的部分(基于从映射到的键值的优先级顺序)提出了真正的挑战。
地图自定义键比较
从键比较到映射的三种基本方法是:
- 为地图键类型提供
operator <
成员替代,或 - 提供函子类型作为地图的比较器,或
- 提供免费功能。
最常见的是第一个,仅仅是因为它最容易实现和可视化。映射的默认比较器是std::less<K>
,其中K
是密钥类型。标准库std::less
默认尝试进行operator <
比较,实际上是这样做的:
bool isLess = (a < b)
其中a
和b
都是您的密钥类型。因此,简单的成员const operator <
重载将满足要求并获得您想要的东西:
struct Node {
Node(int a=0,int b=0)
: x(a),y(b)
{
}
int x,y;
// called by default std::less
bool operator <(const Node& rhs) const
{
return (x < rhs.x) || (!(rhs.x < x) && y < rhs.y);
}
// simple distance calculation between two points in 2D space.
double distanceFrom(Node const& node) const
{
return std::sqrt(std::pow((x - node.x),2.0) + std::pow((y - node.y),2.0));
}
friend std::ostream& operator <<(std::ostream& os,Node const& node)
{
return os << '(' << node.x << ',' << node.y << ')';
}
};
这支持严格的弱命令并且足够了。其他选项则稍微复杂一些,但不会太多。我在这里不做介绍,但是关于SO的问题很多。
注意:我添加了distanceFrom
和operator <<
成员和朋友,以供以后在最终样本中使用;您以后再看。
优先级队列实例比较覆盖
以前从未这样做过,但是如果有更简单的方法,我当然可以提出建议。为优先级队列使用模板类型的比较器替代的问题是您实际上无法做到这一点。您希望根据到原点的距离对每个队列进行排序,其中原点是该队列的地图关键字。这意味着必须以某种方式将每个 comparison 对象提供给地图关键字的来源,而您不能使用模板类型的覆盖(即编译时的东西)来做到这一点。
可以执行的操作是提供一个 instance 比较替代。 std::priority_queue
允许您提供一个自定义比较对象创建队列的地方(在我们的示例中,当它作为映射目标插入到地图中时)。进行一些按摩,我们得出以下结论:
首先,一个不包含args或Node的优先函子。
// instance-override type
struct NodePriority
{
NodePriority() = default;
NodePriority(Node node)
: key(std::move(node))
{
}
// compares distance to key of two nodes. We want these in
// reverse order because smaller means closer means higher priority.
bool operator()(const Node& lhs,const Node& rhs) const
{
return rhs.distanceFrom(key) < lhs.distanceFrom(key);
}
private:
Node key;
};
using NodeQueue = std::priority_queue<Node,std::deque<Node>,NodePriority>;
using NodeQueue
将为我们节省大量输入以下示例的代码。
样品
使用以上内容,我们现在可以构建地图和队列了。以下创建了一个随机列表,该列表包含十个节点,每个节点中的进位和x,y在1..9范围内。然后,我们使用这些节点来构建十个优先级队列,对于正在创建的每个映射条目,一个。地图条目是对角线切片(即(1,1),(2,2),(3,3)等)。使用相同的十个随机元素,我们在报告最终结果时应该会看到不同的优先级队列顺序。
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <queue>
#include <map>
#include <random>
struct Node {
Node(int a=0,y;
// called by default std::less
bool operator <(const Node& rhs) const
{
return (x < rhs.x) || (!(rhs.x < x) && y < rhs.y);
}
// simple distance calculation between two points in 2D space.
double distanceFrom(Node const& node) const
{
return std::sqrt(std::pow((x - node.x),' << node.y << ')';
}
};
// instance-override type
struct NodePriority: public std::less<Node>
{
NodePriority() = default;
NodePriority(Node node)
: key(std::move(node))
{
}
// compares distance to key of two nodes. We want these in
// reverse order because smaller means closer means higher priority.
bool operator()(const Node& lhs,NodePriority>;
int main()
{
std::mt19937 rng{ 42 }; // replace with { std::random_device{}() } for random sequencing;
std::uniform_int_distribution<> dist(1,9);
std::map<Node,NodeQueue> myMap;
// generate ten random points
std::vector<Node> pts;
for (int i = 0; i < 10; ++i)
pts.emplace_back(Node(dist(rng),dist(rng)));
for (int i = 0; i < 10; ++i)
{
Node node(i,i);
myMap.insert(std::make_pair(node,NodeQueue(NodePriority(node))));
for (auto const& pt : pts)
myMap[node].emplace(pt);
}
// enumerate the map of nodes and their kids
for (auto& pr : myMap)
{
std::cout << pr.first << " : {";
if (!pr.second.empty())
{
std::cout << pr.second.top();
pr.second.pop();
while (!pr.second.empty())
{
std::cout << ',' << pr.second.top();
pr.second.pop();
}
}
std::cout << "}\n";
}
}
注意:伪随机数生成器总是以42
作为种子,以具有可重复的序列。当您决定通过不可重复的测试来消除这种麻烦时,只需将该声明替换为声明旁边注释中提供的种子即可。
输出(当然,您会有所不同)。
(0,0) : {(3,1),(5,(3,5),3),4),(1,9),(6,7),8),8)}
(1,1) : {(3,8)}
(2,2) : {(3,8)}
(3,3) : {(3,9)}
(4,4) : {(5,9)}
(5,5) : {(5,9)}
(6,6) : {(6,1)}
(7,7) : {(6,1)}
(8,8) : {(6,1)}
(9,9) : {(6,1)}
我让您验证距离计算的准确性,但希望您能理解。
,$routes = json_decode($routes);
echo json_encode(array_merge_recursive($routes));
您可以将地图声明为
struct cmp {
cmp(Node node) { this->node = node; }
bool operator () (const Node& node1,const Node& node2) {
return (getDistance(node,node1) < getDistance(node,node2));
}
Node node; // this node corresponds to the node that came from map key
};
下一行使上面编写的比较器与常规比较器有所不同,因为您想在比较器内部传递映射键。
std::map<Node,priority_queue<Node,vector<Node>,cmp(Node)>> myMap;
我还没有汇编以上内容。如果有任何错误,应使用简单的修复程序。我想我已经给出了足够的代码来解除对您的阻止。作为练习,请尝试使用lambda代替单独的比较器函数。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。