• python数据结构之图论


    本篇学习笔记内容为图的各项性质、图的表示方法、图ADT的python实现

    图(Graph)

    是数据结构和算法学中最强大的框架之一(或许没有之一)。图几乎可以用来表现所有类型的结构或系统,从交通网络到通信网络,从下棋游戏到最优流程,从任务分配到人际交互网络,图都有广阔的用武之地。

    我们会把图视为一种由“顶点”组成的抽象网络,网络中的各顶点可以通过“边”实现彼此的连接,表示两顶点有关联。我们要知道最基础最基本的2个概念,顶点(vertex)和边(edge)。

    图可以分为有向图和无向图,一般用G=(V,E)来表示图。经常用邻接矩阵或者邻接表来描述一副图。

    首先是链表、树与图的对比图:

    圆为顶点、线为边

    图的术语

    图 G 是顶点V 和边 E的集合 

    两个顶点之间:边 

    如果顶点 x 和 y 共享边,则它们相邻,或者它们是相邻的 

    无向图 :无向图中的一个边可以在任一方向上遍历 

    路径::通过边连接的顶点序列 

    周期:第一个和最后一个顶点相同的路径 

    入度::顶点的度数V是以V为端点的边数 

    出度: 顶点的出度v是以v为起点的边的数量 

    度:顶点的度数是其入度和出度的总和

    图的ADT

    数据成员 :

    顶点 (vertex)

    边缘 (edge)

    操作 :

    有多少顶点?

    有多少个边缘?

    添加一个新的顶点 

    添加一个新的边缘 

    获取所有邻居? (进出)

    U,V连接吗?

    反转所有边缘?

    获取2跳邻居

    图表示法:邻接矩阵

    class Vertex:
        def __init__(self, node):
            self.id = node
            # Mark all nodes unvisited        
            self.visited = False  
    
        def addNeighbor(self, neighbor, G):
            G.addEdge(self.id, neighbor)
    
        def getConnections(self, G):
            return G.adjMatrix[self.id]
    
        def getVertexID(self):
            return self.id
    
        def setVertexID(self, id):
            self.id = id
    
        def setVisited(self):
            self.visited = True
    
        def __str__(self):
            return str(self.id)
    
    class Graph:
        def __init__(self, numVertices=10, directed=False):
            self.adjMatrix = [[None] * numVertices for _ in range(numVertices)]
            self.numVertices = numVertices
            self.vertices = []
            self.directed = directed
            for i in range(0, numVertices):
                newVertex = Vertex(i)
                self.vertices.append(newVertex)
    
        def addVertex(self, vtx, id):  #增加点,这个function没有扩展功能
            if 0 <= vtx < self.numVertices:
                self.vertices[vtx].setVertexID(id)
    
        def getVertex(self, n):
            for vertxin in range(0, self.numVertices):
                if n == self.vertices[vertxin].getVertexID():
                    return vertxin
            return None
    
        def addEdge(self, frm, to, cost=0): #返回全部连线/航线
            #print("from",frm, self.getVertex(frm))
            #print("to",to, self.getVertex(to))
            if self.getVertex(frm) is not None and self.getVertex(to) is not None:
                self.adjMatrix[self.getVertex(frm)][self.getVertex(to)] = cost
                if not self.directed:
                    # For directed graph do not add this
                    self.adjMatrix[self.getVertex(to)][self.getVertex(frm)] = cost  
    
        def getVertices(self):
            vertices = []
            for vertxin in range(0, self.numVertices):
                vertices.append(self.vertices[vertxin].getVertexID())
            return vertices
    
        def printMatrix(self):
            for u in range(0, self.numVertices):
                row = []
                for v in range(0, self.numVertices):
                    row.append(str(self.adjMatrix[u][v]) if self.adjMatrix[u][v] is not None else '/')
                print(row)
    
        def getEdges(self):
            edges = []
            for v in range(0, self.numVertices):
                for u in range(0, self.numVertices):
                    if self.adjMatrix[u][v] is not None:
                        vid = self.vertices[v].getVertexID()
                        wid = self.vertices[u].getVertexID()
                        edges.append((vid, wid, self.adjMatrix[u][v]))
            return edges
        
        def getNeighbors(self, n):
            neighbors = []
            for vertxin in range(0, self.numVertices):
                if n == self.vertices[vertxin].getVertexID():
                    for neighbor in range(0, self.numVertices):
                        if (self.adjMatrix[vertxin][neighbor] is not None):
                            neighbors.append(self.vertices[neighbor].getVertexID())
            return neighbors
        
        def isConnected(self, u, v):
            uidx = self.getVertex(u) 
            vidx = self.getVertex(v)
            return self.adjMatrix[uidx][vidx] is not None
        
        def get2Hops(self, u): #转一次机可以到达哪里
            neighbors = self.getNeighbors(u)
            print(neighbors)
            hopset = set()
            for v in neighbors:
                hops = self.getNeighbors(v)
                hopset |= set(hops)
            return list(hopset)

    图表示法:邻接表

    用邻接矩阵来表示,每一行表示一个节点与其他所有节点是否相连,但对于邻接表来说,一行只代表和他相连的节点:

    可见邻接表在空间上是更省资源的。 
    邻接表适合表示稀疏图,邻接矩阵适合表示稠密图。

    import sys
    class Vertex:
        def __init__(self, node):
            self.id = node
            self.adjacent = {}
            #为所有节点设置距离无穷大
            self.distance = sys.maxsize
            # 标记未访问的所有节点     
            self.visited = False  
            # Predecessor
            self.previous = None
    
        def addNeighbor(self, neighbor, weight=0):
            self.adjacent[neighbor] = weight
    
        # returns a list 
        def getConnections(self): # neighbor keys
            return self.adjacent.keys()  
    
        def getVertexID(self):
            return self.id
    
        def getWeight(self, neighbor):
            return self.adjacent[neighbor]
    
        def setDistance(self, dist):
            self.distance = dist
    
        def getDistance(self):
            return self.distance
    
        def setPrevious(self, prev):
            self.previous = prev
    
        def setVisited(self):
            self.visited = True
    
        def __str__(self):
            return str(self.id) + ' adjacent: ' + str([x.id for x in self.adjacent])
        
        def __lt__(self, other):
            return self.distance < other.distance and self.id < other.id    
    
    class Graph:
        def __init__(self, directed=False):
            # key is string, vertex id
            # value is Vertex
            self.vertDictionary = {}
            self.numVertices = 0
            self.directed = directed
            
        def __iter__(self):
            return iter(self.vertDictionary.values())
    
        def isDirected(self):
            return self.directed
        
        def vectexCount(self):
            return self.numVertices
    
        def addVertex(self, node):
            self.numVertices = self.numVertices + 1
            newVertex = Vertex(node)
            self.vertDictionary[node] = newVertex
            return newVertex
    
        def getVertex(self, n):
            if n in self.vertDictionary:
                return self.vertDictionary[n]
            else:
                return None
    
        def addEdge(self, frm, to, cost=0):
            if frm not in self.vertDictionary:
                self.addVertex(frm)
            if to not in self.vertDictionary:
                self.addVertex(to)
    
            self.vertDictionary[frm].addNeighbor(self.vertDictionary[to], cost)
            if not self.directed:
                # For directed graph do not add this
                self.vertDictionary[to].addNeighbor(self.vertDictionary[frm], cost)
    
        def getVertices(self):
            return self.vertDictionary.keys()
    
        def setPrevious(self, current):
            self.previous = current
    
        def getPrevious(self, current):
            return self.previous
    
        def getEdges(self):
            edges = []
            for key, currentVert in self.vertDictionary.items():
                for nbr in currentVert.getConnections():
                    currentVertID = currentVert.getVertexID()
                    nbrID = nbr.getVertexID()
                    edges.append((currentVertID, nbrID, currentVert.getWeight(nbr))) # tuple
            return edges
        
        def getNeighbors(self, v):
            vertex = self.vertDictionary[v]
            return vertex.getConnections()

    学习资料参考:图论算法初步python算法图论

  • 相关阅读:
    C语言之内存分配函数
    C语言const
    【Hihocoder 1167】 高等理论计算机科学 (树链的交,线段树或树状数组维护区间和)
    【HDU 1828】 Picture (矩阵周长并,线段树,扫描法)
    【 HDU 1255】 覆盖的面积(矩阵面积交,线段树,扫描法)
    【HDU 1542】Atlantis 矩形面积并(线段树,扫描法)
    【BZOJ 2333 】[SCOI2011]棘手的操作(离线+线段树|可并堆-左偏树)
    【20161108】总结
    【BZOJ 3110】 [Zjoi2013]K大数查询(整体二分)
    【Bzoj 3295】 动态逆序对(树套树|CDQ分治)
  • 原文地址:https://www.cnblogs.com/kumata/p/9246502.html
Copyright © 2020-2023  润新知