【问题标题】:Make undirected graph from adjacency list从邻接表制作无向图
【发布时间】:2016-07-29 13:18:59
【问题描述】:

我正在尝试从邻接表中创建一个无向图来练习 Karger 的 Min Cut 算法。以下是我的代码

class Vertex(object):
    '''Represents a vertex, with the indices of edges
       incident on it'''
    def __init__(self,name,edgeIndices=[]):
        self.name = name
        self.edgeIndices = edgeIndices
    def getName(self):
        return self.name
    def addEdge(self,ind):
        self.edgeIndices.append(ind)
    def getEdges(self):
        return self.edgeIndices
    def __eq__(self,other):
        return self.name == other.name

class Edge(object):
    '''Represents an edge with the indices of its endpoints''' 
    def __init__(self,ends):
        self.ends = ends
    def getEnds(self):
        return self.ends
    def __eq__(self,other):
        return (self.ends == other.ends)\
               or ((self.ends[1],self.ends[0]) == other.ends)

class Graph(object):
    def __init__(self,vertices,edges):
        self.edges = edges
        self.vertices = vertices

def createGraph(filename):
    '''Input: Adjacency list
       Output: Graph object'''
    vertices = []
    edges = []
    with open(filename) as f:
        for line in f:
            elements = line.split()
            newVert = Vertex(elements[0])
            if newVert not in vertices:
                vertices.append(newVert)

            for verts in elements[1:]:
                otherVert = Vertex(verts)
                if otherVert not in vertices:
                    vertices.append(otherVert)
                end1 = vertices.index(newVert)
                end2 = vertices.index(otherVert)
                newEdge = Edge((end1,end2))
                if newEdge not in edges:
                    edges.append(newEdge)
                newVert.addEdge(edges.index(newEdge))
    return Graph(vertices,edges)

假设邻接表如下,顶点用整数表示

1 -> 2,3,4
2 -> 1,3
3 -> 1,2,4
4 -> 1,3

该图总共有 5 条边,因此包含与顶点关联的边的索引的列表长度不能超过 5 条。

例如,我希望顶点“2”只有两条边的索引,即顶点 1 和 3 的边。相反,我得到的是[0, 1, 2, 3, 0, 2, 1, 3]。 我需要帮助找出问题所在。

【问题讨论】:

    标签: python graph undirected-graph


    【解决方案1】:

    第一个错误来自 Vertex init。当传递一个列表作为默认参数时,Python 将它实例化一次,并与所有未来的 Vertex 实例共享这个实例。 传递 None,如果没有给出列表,则使用本地列表。

    class Vertex(object):
        def __init__(self,name,edgeIndices=None):
            self.name = name
            self.edgeIndices = edgeIndices if edgeIndices else []
    

    在createGraph方法中,当顶点已经存在于图中时,需要使用它。请参阅添加的else: newVert = ... 您似乎也有关于木质分裂的问题。查看elements[2].split(',') 的迭代。

    def createGraph(filename):
        '''Input: Adjacency list
           Output: Graph object'''
        vertices = []
        edges = []
        with open(filename) as f:
            for line in f:
                elements = line.split()
                newVert = Vertex(elements[0])
                if newVert not in vertices:
                    vertices.append(newVert)
                else:
                    newVert = vertices[vertices.index(newVert)]
    
                for verts in elements[2].split(','):
                    otherVert = Vertex(verts)
                    if otherVert not in vertices:
                        vertices.append(otherVert)
                    end1 = vertices.index(newVert)
                    end2 = vertices.index(otherVert)
                    newEdge = Edge((end1,end2))
                    if newEdge not in edges:
                        edges.append(newEdge)
                    newVert.addEdge(edges.index(newEdge))
        return Graph(vertices,edges)
    

    作为旁注,我会尝试使用 dict 来存储顶点(和边)并进行查找。 List.index 用的比较多,你可能会白白创建很多对象。

    【讨论】:

    • 我将顶点和边作为数组存储在图形对象中,然后交叉引用这两个数组。是否可以对 dicts 做同样的事情,因为它们是使用键访问的,而且,dict 中的条目可能与我们输入的顺序不同。
    • 嗯,dict 的真正目的是加快图形加载并简化代码。如果您的顶点标签不连续并且需要存储一些映射,那么字典和键会派上用场。
    • 如果您打算对图形进行大量计算,那么数组应该可以让您更快地访问并最终变得更好。如果您的顶点在文件中标记为从 1 到 n,我将按排序顺序用 (n+1) 个顶点填充一个数组,然后添加边。或者标记从 0 到 (n-1) 的顶点。当您使用索引而不是实际对象时,创建边不需要实际顶点,只需从其标签中扣除其索引即可。
    【解决方案2】:

    我建议看一下基于 Dict、OrderedDict、Linked List 的图形实现。比基于列表和索引更有效。 为了让您的代码工作,您可以执行以下操作:

    更改顶点以避免上一个答案中描述的问题:

    class Vertex(object):
        def __init__(self,name, edgeIndices=None):
            self.name = name
            self.edgeIndices = edgeIndices or []     
    

    让图表做一些工作:

    class Graph(object):
        def __init__(self):
            self.edges = []
            self.vertices = []
    
        def add_vertex(self, name):
            vertex = Vertex(name)
            if vertex not in self.vertices:
                self.vertices.append(vertex)
    
        def add_edge(self, *names):
            self._add_vertices(names)
            edge = self._add_edge(names)
            self._update_vertices_links(edge, names)
    
        def get_vertex_index(self, name):
            vertex = Vertex(name)
            return self.vertices.index(vertex)
    
        def get_vertex(self, name):
            return self.vertices[self.get_vertex_index(name)]
    
        def _update_vertices_links(self, edge, names):
            for name in names:
                vertex = self.get_vertex(name)
                vertex.addEdge(self.edges.index(edge))
    
        def _add_edge(self, names):
            edge = Edge((self.get_vertex_index(names[0]), self.get_vertex_index(names[1])))
            if edge not in self.edges:
                self.edges.append(edge)
            return edge
    
        def _add_vertices(self, names):
            for name in names:
                self.add_vertex(name)
    
        def __repr__(self):
            return "Vertices: %s\nEdges: %s" % (self.vertices, self.edges)
    

    创建图表:

    def createGraph(filename):
        with open(filename) as f:
            graph = Graph()
            for line in f:
                elements = line.strip().split()
                graph.add_vertex(elements[0])
                for element in elements[2].split(","):
                    graph.add_edge(elements[0], element)
        return graph
    

    运行它:

    graph = createGraph('input.txt')
    print graph
    

    输入的输出:

    Vertices: [<Name:1 Edges:[0, 1, 2]>, <Name:2 Edges:[0, 3]>, <Name:3 Edges:[1, 3, 4]>, <Name:4 Edges:[2, 4]>]
    Edges: [(0, 1), (0, 2), (0, 3), (1, 2), (2, 3)]
    

    【讨论】:

      猜你喜欢
      • 2018-07-14
      • 2014-04-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多