簡體   English   中英

在C#,C ++和Java中創建python弱類型結構的強類型版本

[英]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 ++中,您可能會使用前者的unionBoost::Variant (類型安全且易於處理)。 您可能需要向前聲明該類,以便在定義它時可以看到它。 聯合提供了足夠的位置來存儲任一類型的值,並且(可以在Boost::Variant隱式地使用普通的舊union顯式地存儲)一個“標簽”,以指示哪種情況。 然后,您可以查看任何存儲的值,並判斷它是另一個圖形還是終端值,然后提取關聯的值。

在Java和C#中,您對直接聯合類型沒有太多的支持,因此可以使用第二種選擇。 有一個接口(或抽象)類IGraph ,其中一個用於圖形的實現(指IGraph ),一個用於將非圖形值包裝在另一個IGraph子類型中。 基本上,您使用子類型多態性。 這在C ++中也是可能的,但是我給人的印象是,如果事先知道可能的類型,不可能改變並且數量很少,那么聯合是一個更好的主意。 它還允許您避免使用某些指針/引用unionBoost::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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM