图的生成树算法

代码来自《数据结构与算法Python语言实现》裘宗燕著

# 图的生成树#----------图的邻接矩阵实现--------------------class Graph:    def __init__(self,mat,unconn = 0):        # 顶点个数        vnum = len(mat)        # 检查是否为方阵        for x in mat:            if len(x) != vnum:                raise ValueError("Argument for 'Graph'.")                # 拷贝        self._mat = [mat[i][:] for i in range(vnum)]        self._unconn = unconn        self._vnum = vnum    # 返回顶点个数    def vertex_num(self):        return self._vnum    # 验证序号v是否有效    def _invalid(self,v):        return 0>v or v>=self._vnum                        # 添加顶点    def add_vertex(self):        raise ValueError("Adj-Matrix does not support 'add_vertex'.")    # 添加边,即添加两个点之间的关联线段    def add_edge(self,vi,vj,val=1):        # 先检查vi和vj是否有效        if self._invalid(vi) or self._invalid(vj):            raise ValueError(str(vi) + 'or' + str(vj) + 'is not a valid vertex.')        # 为线段附加权重        self._mat[vi][vj] = val    # 获取边的权重    def get_edge(self,vi,vj):        if self._invalid(vi) or self._invalid(vj):            raise ValueError(str(vi) + 'or' + str(vj) + 'is not valid vertex.')        return self._mat[vi][vj]    # 获取指定结点的所有相连边    def out_edges(self,vi):        if self._invalid(vi):            raise ValueError(str(vi) + 'is not a valid vertex.')        return self._out_edges(self._mat[vi],self._unconn)        @staticmethod # 静态方法,无需实例化即可调用    def _out_edges(row,unconn):        edges = []        for i in range(len(row)):            if row[i] != unconn:                edges.append((i,row[i]))        return edges        # 将矩阵转化为字符串模式    def __str__(self):        return "[\n" + ".\n".join(map(str,self._mat)) + "\n]" + "\nUnconnected:" + str(self._unconn)#----------图的邻接矩阵实现--------------------#----------图的压缩邻接矩阵实现-----------------class GraphAL(Graph):    # GraphAL继承自Graph            def __init__(self,mat = [],unconn = 0):        vnum = len(mat)        # 检查是否为方阵        for x in mat:            if len(x) != vnum:                raise ValueError("Argument for 'Graph'.")        # 只复制带有权重的边        self._mat = [Graph._out_edges(mat[i],unconn) for i in range(vnum)]        self._vnum = vnum        self._unconn = unconn    # 添加一个顶点    def add_vertex(self):        self._mat.append([])        self._vnum += 1        return self._vnum - 1    # 添加一个边    def add_edge(self,vi,vj,val=1):        if self._vnum == 0:            raise ValueError("Cannot add edge to an empty Graph!")        if self._invalid(vi) or self._invalid(vj):            raise ValueError(str(vi) + 'or' + str(vj) + 'is not valid vertex!')        row = self._mat[vi]        i = 0        while i < len(row):            # 寻找vj对应的权重            if row[i][0] == vj:                self._mat[vi][i] = [vj,val]                return None             # 如果没有找到vj对应的值,说明vi和vj不相连            # 则退出循环,添加vi与vj的关联边            if row[i][0] > vj:                break            i += 1        # 添加vi与vj的关联边        self._mat[vi].insert(i,(vj,val))    def get_edge(self,vi,vj):        if self._invalid(vi) or self._invalid(vj):            raise ValueError(str(vi) + 'or' + str(vj) + 'is not valid vertex!')                # 寻找对应vi和vj的边的权重        if i,val in self._mat[vi]:            if i == vj:                return val                # 如果没有匹配到,则返回0        return self._unconn#----------图的压缩邻接矩阵实现-----------------#----------栈的实现---------------------------class Node:    def __init__(self):        self.val = val        self.next = Noneclass SStack:    def __init__(self):        self.top = None    # 获取栈顶的元素    def peek(self):        if self.top != None:            return self.top.val        else:            return None    # 将新元素压入到栈中    def push(self,n):        n = Node(n)        n.next = self.top        self.top = n        return n.val    # 退出栈    def pop(self):        if self.top == None:            return None        else:            tmp = self.top.val            self.top = self.top.next            return tmp#----------栈的实现---------------------------#----------1. 非递归DFS遍历--------------------def DFS_graph(graph,v0):    # 顶点个数    vnum = graph.vertex_num()    # 为每个顶点打上未访问的标记    visited = [0] * vnum    # 遍历序列    DFS_seq = [v0]    # 栈、用于存储每个顶点的边信息    st = SStack()    st.push((0,graph.out_edges(v0))) # 压入与起始结点相连的边中的第一条    while not st.is_empty():        # 取出顶点序号i与边列表        i,edges = st.pop()        if i < len(edges):            # v是顶点,e是边            v,e = edges[i]                        # 压入与该顶点相连的下一个边            # 待前一个边下面的所有结点都访问完了之后再访问            st.push((i+1,edges))                        # 如果没有访问过这个顶点            if not visited[v]:                # 将顶点加入列表中                DFS_seq.append(v)                # 访问过之后将标记置为1                visited[v] = 1                # 将与搜索到的顶点相连的顶点压入栈中,以备下次访问,这个比163行的更先访问到                st.push((0,graph.out_edges(v)))    return DFS_seq#----------1. 非递归DFS遍历--------------------#---------2. DFS生成树-------------------------def DFS_span_forest(graph):    # 顶点个数    vnum = graph.vertex_num()    # 记录路径信息    span_forest = [None] * vnum    def dfs(graph,v):        # 需要修改非局部变量,所以将之声明为nonlocal        nonlocal span_forest        # 遍历顶点v连接的所有路径,u是顶点,w是权重        for u,w in graph.out_edges(v):            # 如果这个顶点尚未加入span_forest            if span_forest[u] is None:                # 将结点u的上一结点和连接权重记录下来                span_forest[u] = (v,w)                dfs(graph,u)        # 避免还有不连通的点,所以要遍历到每个顶点    for v in range(vnum):        if span_forest[v] is None:            span_forest[v] = [v,0]            dfs(graph,v)    return span_forest            #---------2. DFS生成树-------------------------#---------3. Kruskal最小生成树-----------------def Kruskal(graph):    # 基本思路:设G = (V,E) 是一个网络,其中|V|(顶点数量)为n,则Kruskal的基本思路为:    # (1)取包含G的所有n个顶点但是没有任何边的孤立点子图T = (V,{})    #     T中的每个顶点自称一个连通分量,下面将通过不断扩充T的方式构造G的最小生成树;    # (2)将边集E按照权值递增的顺序排序,在构造中的每一步按顺序地检查这个边序列    #     找到最短的且两端位于T的两个不同的连通分量的边e,将e加入T,这样两个连通分量    #     就在e的作用下连接成了一个连通分量;    # (3)每次操作使T减少一个连通分量。不断重复这个动作,往T中加入新边,直到T中所有顶点    #     都包含在一个连通分量为止,这个连通分量就是G的一棵最小生成树。    # 获取顶点个数    vnum = graph.vertex_num()    # 将各顶点的代表元初始化,代表元代表了顶点所属的连通分量    reps = [i for i in range(vnum)]    # mst记录最小生成树的边,edges记录graph所有的边    mst,edges = [],[]    # 将所有的边加入edges    for vi in range(vnum):        for v,w in graph.out_edges(vi):            edges.append((w,vi,v))    # 按权重排列    edges.sort()    for w,vi,vj in edges:        # 如果vi和vj属于两个不同的连通分量        if reps[vi] != reps[vj]:            mst.append(((vi,vj),w))                        # 如果有n-1条边代表已经构造完成            if len(mst) == vnum - 1:                break            # 修改代表元,将所有与vj在同一连通分量的顶点归入vi所在的连通分量中                        rep,orep = reps[vi],reps[vj]            for i in range(vnum):                if reps[i] == orep:                    reps[i] = rep    return mst#---------3. Kruskal最小生成树-----------------
文章链接:https://www.sbkko.com/ganhuo-383.html
文章标题:图的生成树算法
文章版权:SBKKO 所发布的内容,部分为原创文章,转载请注明来源,网络转载文章如有侵权请联系我们!

给TA打赏
共{{data.count}}人
人已打赏
干货分享

淘宝使用selenium扫码登录

2018-8-9 11:56:00

干货分享

想通过社交学习外语?这款APP轻松让你和世界各地的母语者交谈

2018-8-9 15:13:00

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索