Python数据结构之图基础

Python数据结构之图基础

什么是图?

  • 表示多对多的关系
  • 一组顶点,通常用V(Vertex)表示顶点集合
  • 一组边,通常用E(Edge)表示边的集合,边是顶点对,分为有向边和无向边

图的创建

邻接矩阵
  • 代码

    class Graph:
        """创建图"""
    
        def __init__(self, n):
            
            self.vertex_list = []
            self.edges = [[0 for i in range(n)] for j in range(n)]  # 初始化图
            self.num_of_edges = 0  # 记录有效边数目
    
        def get_num_of_vertex(self):
            """获取顶点数目"""
            return len(self.vertex_list)
    
        def get_val_by_index(self, index):
            """返回结点的下标"""
            return self.vertex_list[index]
    
        def get_wight(self, v1, v2):
            """获取边的权重"""
            return self.edges[v1][v2]
    
        def show_graph(self):
    
            for col in self.edges:
                print(col)
    
        def insert_edge(self, v1, v2, weight):
            """插入边"""
    
            self.edges[v1][v2] = weight
            self.edges[v2][v1] = weight
            self.num_of_edges += 1
    
        def insert_vertex(self, vertex):
            """插入顶点"""
            
            self.vertex_list.append(vertex)
            
            
    if __name__ == "__main__":
        graph = Graph(5)
        print("原始图结构:")
        vertex_val = ["A", "B", "C", "D", "E"]
        for vertex in vertex_val:
            graph.insert_vertex(vertex)
        graph.show_graph()
        graph.insert_edge(1, 2, 5)
        graph.insert_edge(2, 4, 6)
        graph.insert_edge(3, 1, 4)
        graph.insert_edge(2, 2, 5)
        print("增加边的结构:")
        graph.show_graph()
    
  • 结果

    原始图结构:
    [0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0]
    [0, 0, 0, 0, 0]
    增加边的结构:
    [0, 0, 0, 0, 0]
    [0, 0, 5, 4, 0]
    [0, 5, 5, 0, 6]
    [0, 4, 0, 0, 0]
    [0, 0, 6, 0, 0]
    
  • 结论

    ​   使用邻接矩阵的形式实现图结构,能够更加直观的理解顶点之间的关系,也能够很好的计算相应顶点的出度和入度,但是,对于无向图而言,邻接矩阵的使用,会同时保存两个顶点之间的的两条边关系,造成存储浪费,所以,可以使用一维列表之间进行存储,减少一半的存储关系或者使用邻接表的方式。

邻接表
  • 代码

    class Vertex:
        """创建顶点类"""
    
        def __init__(self, key):
            self.id = key
            self.connectedTo = {}
    
        def add_neighbor(self, nbr, weight):
            self.connectedTo[nbr] = weight
    
        def __str__(self):
            return str(self.id) + " connected to " + str([x.id for x in self.connectedTo])
    
        def get_connections(self):
            return self.connectedTo.keys()
    
        def get_id(self):
            return self.id
    
        def get_weight(self, nbr):
            return self.connectedTo[nbr]
    
    
    class Graph:
    	"""创建图"""
        
        def __init__(self):
            self.vertList = {}
            self.numVertice = 0
    
        def add_vertex(self, key):
            self.numVertice += 1
            newVertex = Vertex(key)
            self.vertList[key] = newVertex  # 添加新的顶点
            return newVertex
    
        def get_vertex(self, n):
            if n in self.vertList:
                return self.vertList
            else:
                return None
    
        def __contains__(self, item):
            return n in self.vertList
    
        def add_edge(self, f, t, cost=0):
            if f not in self.vertList:
                nv = self.add_vertex(f)
                
            if t not in self.vertList:
                nv = self.add_vertex(t)
                
            self.vertList[f].add_neighbor(self.vertList[t], cost)
    
        def get_vertics(self):
            return self.vertList.keys()
    
        def __iter__(self):
            return iter(self.vertList.values())
    
    
    if __name__ == "__main__":
        g = Graph()
        for i in range(6):
            g.add_vertex(i)
    
        g.add_edge(0,1,5)
        g.add_edge(0,5,2)
        g.add_edge(1,2,4)
        g.add_edge(2,3,9)
        g.add_edge(3,4,7)
        g.add_edge(3,5,3)
        g.add_edge(4,0,1)
        g.add_edge(5,4,8)
        g.add_edge(5,2,1)
    
        for x in g:
            print(x)
    
  • 结果

    0 connected to [1, 5]
    1 connected to [2]
    2 connected to [3]
    3 connected to [4, 5]
    4 connected to [0]
    5 connected to [4, 2]
    
  • 结论

    ​   在python中可以使用字典来实现图邻接表的形式,对其而言,能较为方便的查找任一顶点的所有邻接点,减少了稀疏图(点多边少)占存储空间的麻烦,可以直观的计算出任一顶点的出度(有向图),但是,入度无法很好计算得出。

图的遍历

DFS(深度优先搜索)

​   DFS的实现过程与树的先序号遍历相同,DFS的实现过程中要设置相应的顶点访问标识,已经访问过的结点不在访问,实现过程最重要的是状态的回溯,可以使用递归。算法通俗理解:一条道走到黑(选择),不行就撤(回溯),已走过不在重复(状态标识)。

  • 代码

      def get_first_neighbor(self, index):
            """查询第一关系边顶点"""
            
            for j in range(self.get_num_of_vertexs()):
                if self.edges[index][j] > 0:
                    return j
    
            return -1
    
        def get_next_neighbor(self, v1, v2):
            """查询第二个结点"""
    
            for j in range(v2 + 1, self.get_num_of_vertexs()):
                if self.edges[v1][j] > 0:
                    return j
    
            return -1
        
        def dfs(self, is_visited, i):
            """深度优先查找"""
    
            print(self.get_val_by_index(i), "->", end=" ")
            self.is_visited[i] = True
    
            first = self.get_first_neighbor(i)
    
            while first != -1:
                if not self.is_visited[first]:
                    self.dfs(is_visited, first)  # 递归遍历
         			
                first = self.get_next_neighbor(i, first)
    
        def dfs_override(self):
            """遍历每一个子图"""
            
            for i in range(self.get_num_of_vertexs()):
                if not self.is_visited[i]:
                    self.dfs(self.is_visited, i)
    
BFS(广度优先搜素)

​   BFS相当于树的层序遍历,可以使用队列对顶点进行存储搜索,让后先进后出的对顶点的有效边顶点进行搜索,已搜索过的便不再搜素,所以,要标识顶点的搜索状态。

  • 代码

      def get_first_neighbor(self, index):
            """查询第一关系边顶点"""
            
            for j in range(self.get_num_of_vertexs()):
                if self.edges[index][j] > 0:
                    return j
    
            return -1
    
        def get_next_neighbor(self, v1, v2):
            """查询第二个结点"""
    
            for j in range(v2 + 1, self.get_num_of_vertexs()):
                if self.edges[v1][j] > 0:
                    return j
    
            return -1
    
        def bfs(self, is_visited, i):
            """宽度优先搜索"""
    
            queue = []
            print(self.get_val_by_index(i) + "->", end=" ")
            self.is_visited[i] = True
            queue.append(i)
    
            while queue:
                u = queue.pop(0)
                w = self.get_first_neighbor(u)
    
                while w != -1:
                    if not is_visited[w]:
                        print(self.get_val_by_index(w), "->", end=" ")
                        self.is_visited[w] = True
                        queue.append(w)
                    w = self.get_next_neighbor(u, w)
    
        def bsf_override(self):
    
            for j in range(self.get_num_of_vertexs()):
                if not self.is_visited[j]:
                    self.bfs(self.is_visited, j)
    

参考

搜索思想——DFS & BFS(基础基础篇

邻接表

数据结构与算法–图 一步一步带你用Python实现图的深度遍历和广度优先遍历 Python实现图的深度遍历和广度优先遍历 Python详解DFS和BFS过程

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值