大话数据结构-图(持续更新)

简书尽然不支持LaTex公式编辑!!!!

有向图与无向图的区别在于边集合E是否有相,另外表示的区别在于$e = (A, B);e1 = <A, B>$

  • 完全无向图:任意两点之间存在边,n个点的边数$C_n^2$
  • 完全有向图:任意两点之间存在两条方向互反的边
  • 子图:图G1的顶点集合和边集合均为图G2的子集则称G1位G2的子图
  • 无向图顶点的度:顶点关联边的数量记为D(v)
  • 有相图顶点的出度和如度D(v) = ID(v) + OD(v)
  • 回路、环:把所有顶点链接的路径,第一个和最后一个顶点不重复的路径称为简单环。
  • 无向图中连通图:任意两个顶点存在路径连通
  • 极大连通子图
  • 有向图的强连通图:任意两个顶点可达
  • 连通图的生成树:极小连通子图,包含n个顶点只有n-1条边;如果有一个有向图仅有一个顶点入度0,其他顶点入度均为,则为一颗有相树。
  • 图的边上加上权重则为

图的存储结构

  • 邻接矩阵
  • 邻接表:边相对于顶点较少的图用矩阵表示是一种浪费,链式存储。
  • 十字链表:
  • 多重链表

图的遍历

  1. 深度优先
# encoding: utf-8

"""
@version: python3.5.2 
@author: kaenlee  @contact: lichaolfm@163.com
@software: PyCharm Community Edition
@time: 2017/9/28 9:04
purpose:算法复杂度,最坏情况,每个点都不可达,每个点为基础遍历其他点N^2次
"""
import numpy as np

# 有6个顶点的无向图邻接矩阵如下:0-5
graphMat = np.array([[0, 1, 0, 1, 0, 1],
                     [1, 0, 1, 0, 0, 1],
                     [0, 1, 0, 0, 1, 0],
                     [1, 0, 0, 0, 0, 1],
                     [0, 0, 1, 0, 0, 1],
                     [1, 1, 0, 1, 1, 0]])

# 深度优先遍历

def travel(graphMat):
    n = len(graphMat)
    visited = np.zeros(n)
    def DFS(graphMat, startPoint):
        """
        :param graphMat:
        :param startPoint: 开始访问起点
        :return:
        """
        nonlocal visited
        visited[startPoint] = 1  # 用来记录该点是否被访问
        n = len(graphMat[startPoint])
        for i in range(n):
            #  从连通的最右边开始遍历那些没有被访问到的下一个节点
            if (graphMat[startPoint][i] == 1) and (visited[i] == 0):
                # 该点和startpoint为连通且没有被访问到
                print('visited', i)
                DFS(graphMat, i)
                
    for j in range(n):
        # 从0点开始访问, 为连通的图(即任意两点可达,概念与markov的一样),循环之后一次就访问所有的点
        print('visited***', j)
        DFS(graphMat, j)
        if all(visited == 1):
            break

travel(graphMat)

#------------------------------------out put-----------------------------------
visited*** 0
visited 1
visited 2
visited 4
visited 5
visited 3
  1. 广度优先
    如果说深度便是类似于数的前序遍历,那么广度就类似于层次遍历
捕获.JPG

第一层A进栈
第二BF进, A出
第三层CIG进, B出
第三层E进, F出
....

def travel_BFS(graphMat):
    n = len(graphMat)
    visited = np.zeros(n)
    temp = []  # 创建一个空栈
    for i in range(n):
        # 如果连通仅仅在这里循环一遍即可
        temp.append(i)  # 初始进栈
        visited[i] = 1
        print('visited', i)
        while temp:
            root = temp.pop(0)
            for j in range(n):
                if (graphMat[root][j] == 1) and (visited[j] == 0):
                    temp.append(j)
                    visited[j] = 1
                    print('visited', j)
        if all(visited == 1):
            break

travel_BFS(graphMat)

# ---------------------------out---------------------------------
visited 0
visited 1
visited 3
visited 5
visited 2
visited 4

最小生成树

对于一个网的最小生成树:将n个顶点用n-1条边连接,且边的权重之和最小。

  • 谱里姆算法:一种归并点的算法,U为需要生成树的点,在U中随机选取一个点作为初始点v0并从U中剔除v0,搜选v0的邻近点中边权重最小的v1作为最小生成树的一部分,并从U中剔除v1,。然后考虑v1和v0的所有临近点,选取边权重最小点v3并从U中剔除v3,如此下去直到U为空。参考
# encoding: utf-8

"""
@version: python3.5.2 
@author: kaenlee  @contact: lichaolfm@163.com
@software: PyCharm Community Edition
@time: 2017/9/30 10:44
purpose:
"""
import sys
import numpy as np



def prim(graphMat):
    n = len(graphMat)
    U = list(range(n))
    # 以能生成的最下边为起点
    start = None
    value = sys.maxsize
    for i in U:
        for j in U:
            if graphMat[i, j] < value:
                value = graphMat[i][j]
                start = i
    print(start)
    V = [start]
    U.remove(start)
    total = 0  # 总权重
    E = []     # 保存连接点边信息
    while U:
        # 循环直到U为空
        minWay = None
        minE = sys.maxsize
        minV = None
        for v in V:
            for u in U:
                if graphMat[v][u] < minE:
                    minE = graphMat[v][u]
                    minV = u
                    minWay = [u, v]
        E.append(minWay)
        V.append(minV)
        U.remove(minV)
        total += minE
    return total, E

graphMat = np.array([[0, 6, 1, 5, sys.maxsize, sys.maxsize],
                     [6, 0, 5, sys.maxsize, 3, sys.maxsize],
                     [1, 5, 0, 5, 6, 4],
                     [5, sys.maxsize, 5, 0, sys.maxsize, 2],
                     [sys.maxsize, 3, 6, sys.maxsize, 0, 6],
                     [sys.maxsize, sys.maxsize, 4, 2, 6, 0]])

print(prim(graphMat))

-----out
(15, [[2, 0], [5, 2], [3, 5], [1, 2], [4, 1]])


  • 克鲁斯卡尔算法:(1)构造一个只含n个顶点,边集为空的子图。若将图中各个顶点看成一棵树的根节点,则它是一个含有n棵树的森林。(2)从网的边集 E 中选取一条权值最小的边,若该条边的两个顶点分属不同的树,则将其加入子图。也就是说,将这两个顶点分别所在的两棵树合成一棵树;反之,若该条边的两个顶点已落在同一棵树上,则不可取,而应该取下一条权值最小的边再试之(3)依次类推,直至森林中只有一棵树,也即子图中含有 n-1条边为止。参考
import numpy as np
import sys
from itertools import combinations

def kruskal(graphMat):
    # 将矩阵转化为{边:权重, ...}并排序
    n = len(graphMat)
    E = {}
    for i in range(n):
        for j in range(n):
            if (i == j):
                pass
            else:
                E.update({str(i)+str(j): graphMat[i, j]})
    E = sorted(E.items(), key=lambda x: x[1])
    V = []
    U = list(range(n))
    saveEs = []
    totol = 0
    for e, w in E:
        p1, p2 = int(e[0]), int(e[1])
        if (p1 in V) and (p2 in V):
            # 顶点p1 p2都在V中就形成了环路,不可取
            pass
        else:
            V.extend([p1, p2])
            saveEs.append([p1, p2])
            totol += w
        if set(U) == set(V):
            break
    print('return', saveEs)
    # 虽然这样将所有的样本点都取到,但可能并不是一个环,没有形成回路
    numOfGroups = n - len(saveEs)
    # print(numOfGroups)
    if numOfGroups == 1:
        return totol, saveEs
    else:
        # 整理出分组并在每个分组,取一条边作为连接回路
        def findShare(X, tag):
            newtag = tag.copy()
            for i in X:
                if set(i) & set(tag):
                    newtag.extend(list(set(i) - set(tag)))
            if newtag == tag:
                return newtag
            else:
                return findShare(X, newtag)
        groups = []
        for i in saveEs:
            if groups:
                flag = 0
                # 如果改点已经存在groups中不在计算
                for j in groups:
                    if set(j) & set(i):
                        flag = 1
                        break
                if flag:
                    continue
            one = findShare(saveEs, i)
            groups.append(one)
        print(groups)
        asset = list(combinations(groups, 2))
        print('asset', asset)
        # 找出链接每两个group之间的最短连接
        briges = []
        for g1, g2 in asset:
            minBrige = sys.maxsize
            brige = None
            for i in g1:
                for j in g2:
                    if graphMat[i][j] < minBrige:
                        minBrige = graphMat[i][j]
                        brige = [i, j]
            briges.append(brige)
        # n个group之间仅仅需要n-1个连接
        maxbrige = None
        value = 0
        for i, j in briges:
            totol += graphMat[i, j]
            if graphMat[i, j] > value:
                maxbrige = [i, j]
        briges.remove(maxbrige)
        saveEs.extend(briges)
        i, j = maxbrige
        return totol - graphMat[i, j], saveEs


graphMat = np.array([[0, 6, 1, 5, sys.maxsize, sys.maxsize],
                     [6, 0, 5, sys.maxsize, 3, sys.maxsize],
                     [1, 5, 0, 5, 6, 4],
                     [5, sys.maxsize, 5, 0, sys.maxsize, 2],
                     [sys.maxsize, 3, 6, sys.maxsize, 0, 6],
                     [sys.maxsize, sys.maxsize, 4, 2, 6, 0]])

print(kruskal(graphMat))
---out
return [[0, 2], [3, 5], [1, 4]]
[[0, 2], [3, 5], [1, 4]]
asset [([0, 2], [3, 5]), ([0, 2], [1, 4]), ([3, 5], [1, 4])]
(15, [[0, 2], [3, 5], [1, 4], [2, 5], [2, 1]])
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,372评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,368评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,415评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,157评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,171评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,125评论 1 297
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,028评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,887评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,310评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,533评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,690评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,411评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,004评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,659评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,812评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,693评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,577评论 2 353

推荐阅读更多精彩内容

  • 第一章 绪论 什么是数据结构? 数据结构的定义:数据结构是相互之间存在一种或多种特定关系的数据元素的集合。 第二章...
    SeanCheney阅读 5,771评论 0 19
  • https://zh.visualgo.net/graphds 浅谈图形结构https://zh.visualgo...
    狼之独步阅读 4,148评论 0 0
  • 1 数据2 算法3 线性表4 栈5 队列6 串朴素模式匹配算法 -子串的定位操作:从主串中找到子串KMP模式匹配算...
    oldSix_Zhu阅读 1,498评论 0 4
  • 图是一种比线性表和树更复杂的数据结构,在图中,结点之间的关系是任意的,任意两个数据元素之间都可能相关。图是一种多对...
    Alent阅读 2,306评论 1 22
  • 我不怕单身一辈子,就是怕在我不懂爱的时候遇到我真正爱的人。 L和我说这句话的时候,眼神中充满着留恋,却同样充满着失...
    玖溪成霖阅读 501评论 4 1