[英]Creating in c#,c++ and java a strong typed version of a python weak typed structure
在python中,我有以下内容:
graph = {}
graph[1] = {}
graph[2] = {}
graph[3] = {}
graph[1][3] = graph[3]
graph[2][1] = graph[1]
graph[2][3] = graph[3]
graph[3][2] = graph[2]
这是一种表示图的结构,我发现很好,因为它的结构与其节点之一相同,因此我可以直接使用它来发起搜索(如深度优先)。 它的印刷版本是:
{1: {3: {2: {1: {...}, 3: {...}}}}, 2: {1: {3: {2: {...}}}, 3: {2: {...}}}, 3: {
2: {1: {3: {...}}, 3: {...}}}}
它可以像这样使用:
graph[1][3][2][3][2][1][3][2][1][3][2].keys()
现在,我很好奇知道如何在不使用“对象”技巧的情况下用C ++,C#和Java来实现它,而这些技巧将用丑陋的演员表填充代码。 对于C ++,我一直在考虑templatemeta编程,但是当需要的东西像这样时,它将生成“有限数据类型”
map<int,map<int,...>> or map<int,...>
在Java中,我将使用Node类来表示图形的任何节点。
public class Node<T> {
private List<Node<T>> children = new ArrayList<Node<T>>();
private T value;
public Node(T value) {
this.value = value;
}
public void addChild(Node<T> child) {
this.children.add(child);
}
public Node<T> getChild(int index) {
return this.children.get(index);
}
public List<Node<T>> getChildren() {
return this.children;
}
public T getValue() {
return this.value;
}
}
如果您想要一个包含int值的图,则可以实例化它,并将其用于:
Node<Integer> graph = new Node<Integer>(10); //value of the first node is 10
graph.addChild(new Node<Integer>(-3));
graph.getChild(0).addChild(new Node<Integer>(5));
System.out.println(graph.getChild(0).getChild(0).getValue()); //prints 5
为了存储其他图形或“终端”值(实际上,只要可以在编译时将它们枚举,这两种方法都可以概括为任意类型的任意类型的任意解释):
在任何一种情况下,您都有一个Graph
类型,可以在其后隐藏嵌套的图形和存储的值。
具体来说,在C ++中,您可能会使用前者的union
或Boost::Variant
(类型安全且易于处理)。 您可能需要向前声明该类,以便在定义它时可以看到它。 联合提供了足够的位置来存储任一类型的值,并且(可以在Boost::Variant
隐式地使用普通的旧union
显式地存储)一个“标签”,以指示哪种情况。 然后,您可以查看任何存储的值,并判断它是另一个图形还是终端值,然后提取关联的值。
在Java和C#中,您对直接联合类型没有太多的支持,因此可以使用第二种选择。 有一个接口(或抽象)类IGraph
,其中一个用于图形的实现(指IGraph
),一个用于将非图形值包装在另一个IGraph
子类型中。 基本上,您使用子类型多态性。 这在C ++中也是可能的,但是我给人的印象是,如果事先知道可能的类型,不可能改变并且数量很少,那么联合是一个更好的主意。 它还允许您避免使用某些指针/引用union
和Boost::Variant
都可以存储在堆栈中,而多态性则需要间接的。
这是一个简单的技巧:
#include <map>
#include <memory>
struct GraphNode
{
std::map<std::size_t, std::unique_ptr<GraphNode>> m;
GraphNode & operator[](std::size_t i)
{
if (!m[i]) { m[i].reset(new GraphNode); }
return *m[i];
}
};
我们为打印添加了一些ostream重载:
#include <prettyprint.hpp>
std::ostream & operator<<(std::ostream & o, GraphNode const & g)
{
if (g.m.empty()) return o << "*";
return o << g.m;
}
std::ostream & operator<<(std::ostream & o, std::unique_ptr<GraphNode> const & p)
{
if (!p) return o << "*";
return o << *p;
}
用法示例:
#include <iostream>
int main()
{
GraphNode n;
n[2] = GraphNode();
n[4] = GraphNode();
n[2][3] = GraphNode();
n[2][8] = GraphNode();
n[2][1] = GraphNode();
std::cout << n << std::endl;
}
打印: [(2, [(1, *), (3, *), (8, *)]), (4, *)]
其他功能很容易添加; 目前,尚不清楚我是否要所有节点也都支持卫星数据(“值”),或者是否只有叶节点可以具有值,或者是否没有任何其他数据。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.