Python 向未加权有向图添加边的效率?

Python 向未加权有向图添加边的效率?,python,algorithm,data-structures,Python,Algorithm,Data Structures,我有三个用python字典表示的图 A: {1:[2], 2:[1,3], 3:[]}. B: {1: {neighbours:[2]}, 2: {neighbours:[1,3]}, 3: {neighbours:[]}} C: {1: {2:None}, 2: {1:None, 3:None}, 3: {}} 我有一个hasEdge和addEdge函数 def addEdge(self, source, target): assert self.hasNode(source) an

我有三个用python字典表示的图

A: {1:[2], 2:[1,3], 3:[]}. 

B: {1: {neighbours:[2]}, 2: {neighbours:[1,3]}, 3: {neighbours:[]}}

C: {1: {2:None}, 2: {1:None, 3:None}, 3: {}}
我有一个hasEdge和addEdge函数

def addEdge(self, source, target):

assert self.hasNode(source) and self.hasNode(target)
if not self.hasEdge(source, target):
    self.graph[source][target] = None

def hasEdge(self, source, target):

    assert self.hasNode(source) and self.hasNode(target)
    return target in self.graph[source]

我不确定哪种结构对于每个函数都最有效,我的直接想法是,第一种结构对于添加边最有效,而C对于返回边最有效,如果它有边的话

C对我来说似乎是最有效的,因为你所做的查找平均为O(1)。(注意这是平均情况,不是最坏情况。)使用邻接列表,可以进行最坏情况线性搜索

对于稀疏图,您可能希望使用邻接列表(a),因为它们将占用更少的空间。然而,对于稠密图,选项C应该是最有效的

A和B将有非常相似的运行时——渐近相同。除非您希望将邻居之外的数据添加到这些节点,否则我将选择A

我不熟悉python;但是,对于Java,可以通过使用HashSet(set)来改进选项C,这将减少您的空间需求。运行时与使用HashMap相同,但集合不存储值-仅存储键,这是检查两个节点之间是否存在边所需的

因此,澄清一下:

对于运行时,选择C。您将得到平均情况O(1)边添加。为了改进C语言以减少内存消耗,可以使用集合而不是映射,这样就不必为值分配空间


对于内存,如果有稀疏图,请选择一个。您将节省大量内存,并且在运行时方面不会损失太多。作为参考,稀疏是指节点没有太多邻居的情况;例如,在一个有20个节点的图中,每个节点大约有2个邻居。

C对我来说似乎是最有效的,因为您所做的查找平均为O(1)。(注意这是平均情况,不是最坏情况。)使用邻接列表,可以进行最坏情况线性搜索

对于稀疏图,您可能希望使用邻接列表(a),因为它们将占用更少的空间。然而,对于稠密图,选项C应该是最有效的

A和B将有非常相似的运行时——渐近相同。除非您希望将邻居之外的数据添加到这些节点,否则我将选择A

我不熟悉python;但是,对于Java,可以通过使用HashSet(set)来改进选项C,这将减少您的空间需求。运行时与使用HashMap相同,但集合不存储值-仅存储键,这是检查两个节点之间是否存在边所需的

因此,澄清一下:

对于运行时,选择C。您将得到平均情况O(1)边添加。为了改进C语言以减少内存消耗,可以使用集合而不是映射,这样就不必为值分配空间


对于内存,如果有稀疏图,请选择一个。您将节省大量内存,并且在运行时方面不会损失太多。作为参考,稀疏是指节点没有太多邻居的情况;例如,在一个有20个节点的图中,每个节点大约有2个邻居。

a
B
是典型的邻接列表
C
是一个邻接列表,但对列表使用
O(1)
结构而不是
O(N)
结构。但实际上,您应该使用邻接集
D

在Python中,set.contains(s)是一个
O(1)
操作

所以我们可以

graph = { 1: set([2]), 2: set([1, 3], 3: set() }
然后我们的
addEdge(from,to)

graph[from].add(to)
graph[to].add(from)
而我们的hasEdge(from,to)只是

to in graph[from]

A
B
是经典的邻接列表
C
是一个邻接列表,但对列表使用
O(1)
结构而不是
O(N)
结构。但实际上,您应该使用邻接集
D

在Python中,set.contains(s)是一个
O(1)
操作

所以我们可以

graph = { 1: set([2]), 2: set([1, 3], 3: set() }
然后我们的
addEdge(from,to)

graph[from].add(to)
graph[to].add(from)
而我们的hasEdge(from,to)只是

to in graph[from]


你想解决什么问题?addEdge和hasEdgeOption D:使用集合而不是列表来表示邻居。我没有选项D不幸的是为什么不实现这三个版本并对它们计时?你想解决什么问题?addEdge和hasEdgeOption D:使用集合而不是列表来表示邻居。我没有选项不幸的是,为什么不实现这三个版本并对它们计时?您会选择A作为每个函数最有效的一个吗?这就是你的意思吗?不,我会选择A而不是B。真正的问题是你应该选择A而不是C,还是C而不是A。对于节点之间有很多边的图,C应该更有益,因为你的运行时间会提高。对于稀疏图,a会更有用,因为它需要更少的空间,而C不会提高足够的效率来抵消a的内存优势。如果您选择a,尤其是Python,您就错了。即使是树映射/树集也比邻接列表好<代码>O(N)邻接列表从来都不是正确答案。在一个完整的或非常密集的图中,如果约束是内存,邻接矩阵有时可能是正确的选择。是否关注空间或时间的问题与图的稀疏性无关。问题在于约束是什么。如果限制是时间,那么O(1)列表是获得格式不好的结果的方法。。。无论如何,这似乎是一个4-6倍的差异。IMO还不错,但显然这取决于约束条件。然而,考虑到约束是关于
hasEdge
addEdge
的,我希望老师期望
C
作为答案。公平点。我确实同意你所说的一切,我只是想指出,在这种情况下,根据你在回答问题时使用的数据,可以进行真正的权衡。运行时thoug的最佳答案