Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Algorithm 如何存储Euler图结构?_Algorithm_Graph_Graph Algorithm - Fatal编程技术网

Algorithm 如何存储Euler图结构?

Algorithm 如何存储Euler图结构?,algorithm,graph,graph-algorithm,Algorithm,Graph,Graph Algorithm,我正在研究Euler路径问题,发现了一个问题:如何定义或存储Euler图结构 通常的方法是使用“伴随矩阵”,定义C[i][j]来存储i-j之间的边。它简洁有效!但这种矩阵受到两个节点之间的边唯一的情况的限制(图1) 如果有多个边(图2)会怎样?我的解决方案可能是使用自定义类,如“Graph”、“Node”、“Edge”来存储图形,但将图形划分为一些离散的结构,这意味着我们必须考虑更多的类细节,这可能会影响效率和简洁性。所以我非常渴望听到你的建议!非常感谢 class EulerPath {

我正在研究Euler路径问题,发现了一个问题:如何定义或存储Euler图结构

通常的方法是使用“伴随矩阵”,定义C[i][j]来存储i-j之间的边。它简洁有效!但这种矩阵受到两个节点之间的边唯一的情况的限制(图1)

如果有多个边(图2)会怎样?我的解决方案可能是使用自定义类,如“Graph”、“Node”、“Edge”来存储图形,但将图形划分为一些离散的结构,这意味着我们必须考虑更多的类细节,这可能会影响效率和简洁性。所以我非常渴望听到你的建议!非常感谢

class EulerPath
{
   class Graph
   {
      Node[] Nodes;
      Edge[] Edges;
   }
   class Node{...}
   class Edge{...}
}

您可以使用邻接矩阵来存储具有多条边的图形。只需将
c[i][j]
的值设为顶点
i
与顶点
j
相邻的次数。第一种情况是1,第二种情况是3。另请参见——邻接矩阵并不是仅由1和0组成的,这只是简单图的邻接矩阵的特例

编辑:可以在邻接矩阵中表示第二个图形,如下所示:

  1 2 3 4
1 0 3 1 1
2 3 0 1 1
3 1 1 0 0
4 1 1 0 0
0 [1]
1 [2,3]
2 [1,3]
3 [1,2]

您至少可以通过三种方式执行此操作:

邻接列表

这意味着您有一个名为al[N][N]的2D数组

al[N][N]这N是节点索引

al[N][N]这N是邻居节点索引

例如,具有此输入的图形:

0 => 1
1 => 2
2 => 3
3 => 1
邻接列表如下所示:

  1 2 3 4
1 0 3 1 1
2 3 0 1 1
3 1 1 0 0
4 1 1 0 0
0 [1]
1 [2,3]
2 [1,3]
3 [1,2]
PS:由于这是一个2D数组,并且不会使用所有水平单元格,因此需要跟踪每个图形索引的连接邻居数,因为某些编程语言使用零初始化数组值,零是图形中的节点索引。这可以通过创建另一个数组来轻松完成,该数组将计算每个图索引的邻居数。本例示例:
numLinks:[1,2,2,2]

矩阵

使用矩阵,您可以创建一个nx2d数组,并将一个
1
值放置在行/列neighobor节点的交点处:

具有上述相同输入的示例:

  0 1 2 3
0 0 1 0 0
1 1 0 1 1
2 0 1 0 1
3 0 1 1 0
类节点


最后一个方法是创建一个名为
Node
的类,该类包含Node类型的动态数组。您可以将连接的其他节点存储在该数组中

考虑使用链表向量。添加一个类,该类将为
顶点
以及
权重
(命名为
条目
)。您的权重最好是另一个向量或链表(最好是ll),它将包含相应
顶点的所有可能权重。您的主类将有一个向量向量,或者一个链表向量(我更喜欢链表,因为在执行任何操作时,您很可能不需要随机访问,被迫遍历每个
条目)。主类将有一个包含所有顶点的向量。在C++中,这看起来是这样的:

class Graph{
    std::vector<std::forward_list<Entry>> adj_list;
    std::vector<Vertex> vertices;
};
类图{
std::向量调整列表;
向量顶点;
};

其中对应于
顶点[i]
顶点
adj_list[i]
中有相应的列表。由于每个
条目
都包含与您所连接的
顶点
相关的信息和相应的权重,因此您的图形将由此类表示。

什么类型的操作的效率

如果你想在互联网上的两个IP地址之间找到一条路由,那么你的邻接矩阵可能是一百万个节点的平方,即十亿字节的条目。当查找连接到一个给定节点的所有节点上升为n时,您可以查找每个节点一百万次的查找,以查找连接到该节点的节点。效率极低

如果您的问题只涉及几个节点,并且很少运行,那么邻接矩阵是简单直观的

对于大多数涉及遍历图的问题,更好的解决方案可能是创建一个名为node的类,该类具有一个属性,即它所连接的所有节点的集合(比如列表)。对于大多数现实世界的应用程序,连接节点的列表远小于所有节点的总数,因此计算起来更加紧凑。此外,它在查找边方面非常高效-您可以在每个节点的固定时间内获得所有连接节点的列表

如果使用此结构,其中有一个节点类,该节点类将其连接到的所有节点的集合作为属性,然后在创建新边(例如,在节点a和节点B之间)时,将B添加到a连接到的节点集合中,将a添加到B连接到的节点集合中。请原谅我的Java/C#,类似

class Node{
Arraylist<Node> connectedNodes;

public Node()  // initializer
{
connectedNodes = new ArrayList<Node>;
}
}

// and somewhere else you have this definition:
public addEdgeBetween(Node firstNode, Node secondNode) {
firstNode.connectedNodes.Add(secondNode);
secondNode.connectedNodes.Add(firstNode);
}
类节点{
Arraylist连接节点;
public Node()//初始值设定项
{
connectedNodes=新的ArrayList;
}
}
//在其他地方你有这样的定义:
公共addEdgeBetween(节点firstNode、节点secondNode){
firstNode.connectedNodes.Add(第二个节点);
secondNode.connectedNodes.Add(第一个节点);
}
与删除边类似,删除A到B集合中的引用,反之亦然。无需定义单独的边类,边在交叉链接两个节点的结构中是隐式的

这就是实现这种结构所需要做的一切,它(对于大多数现实世界的问题)使用的内存比邻接矩阵少得多,对于大多数问题来说,对于大量的节点来说速度要快得多,并且最终要灵活得多

定义一个节点类也为添加各种增强打开了一个逻辑空间。例如,您可能会决定为每个节点生成两步之外的所有节点的列表,因为这样可以改进路径查找。您可以轻松地将其添加为另一个集合