数据结构 12.图

一、图

1. 定义

  • 图(Graph)是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。在图中的数据元素,我们称之为顶点(Vertex),顶点集合有穷非空。在图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边集可以是空的。

  • 图按照边的有无方向分为无向图和有向图。无向图由顶点和边组成,有向图由顶点和弧构成。弧有弧尾和弧头之分,带箭头一端为弧头。

  • 图按照边或弧的多少分稀疏图和稠密图。如果图中的任意两个顶点之间都存在边叫做完全图,有向的叫有向完全图。若无重复的边或顶点到自身的边则叫简单图。

  • 图中顶点之间有邻接点、依附的概念。无向图顶点的边数叫做度。有向图顶点分为入度和出度。

  • 图上的边或弧带有权则称为网。

  • 图中顶点间存在路径,两顶点存在路径则说明是连通的,如果路径最终回到起始点则称为环,当中不重复的叫简单路径。若任意两顶点都是连通的,则图就是连通图,有向则称为强连通图。图中有子图,若子图极大连通则就是连通分量,有向的则称为强连通分量。

  • 无向图中连通且n个顶点n-1条边称为生成树。有向图中一顶点入度为0其余顶点入度为1的叫有向树。一个有向图由若干棵有向树构成生成森林。

2. 实现有向图、无向图、有权图、无权图的邻接矩阵和邻接表表示方法

2.1 邻接矩阵

图的邻接矩阵的表示方式需要两个数组来表示图的信息,一个一维数组表示每个数据元素的信息,一个二维数组(邻接矩阵)表示图中的边或者弧的信息。

如果图有n个顶点,那么邻接矩阵就是一个n*n的方阵,方阵中每个元素的值的计算公式如下:

f
邻接矩阵表示图的具体示例如下图所示:

首先给个无向图的实例:

fig
fig1

  • 无向图的邻接矩阵都是沿对角线对称的
  • 要知道无向图中某个顶点的度,其实就是这个顶点vi在邻接矩阵中第i行或(第i列)的元素之和;
  • 对于有向图,要知道某个顶点的出度,其实就是这个顶点vi在邻接矩阵中第i行的元素之和,如果要知道某个顶点的入度,那就是第i列的元素之和。

但是,如果我们需要表示的图是一个网的时候,例如假设有个图有n个顶点,同样该网的邻接矩阵也是一个n*n的方阵,只是方阵元素的值的计算方式不同,如下图所示:
f1
这里的wij表示两个顶点vi和vj边上的权值。无穷大表示一个计算机允许的、大于所有边上权值的值,也就是一个不可能的极限值。下面是具体示例,表示的一个有向网的图和邻接矩阵:
fig3
fig4

# 邻接矩阵
class Graph:           # 基本图类,采用邻接矩阵表示
    def __init__(self, mat, unconn = 0):
        vnum = lem(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
    
    def _invalid(self, v):
        return 0 > v or v >= self._num
    
    def add_vertex(self):
        raise GraphError("Adj-Matrix does not support 'add_vertex'.")
        
    def add_edge(self, vi, vj, val = 1):
        if self._invalid(vi) or self._invalid(vj):
            raise GraphError(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 GraphError(str(vi) + 'or' + str(vj) + "is not a valid vertex.")
        return self._mat[vi][vj]
    
    # 返回顶点的出边
    def out_edges(self, vi):
        if self._invalid(vi):
            raise GraphError(str(vi) + "is not a valid vertex.")
        return self._out_edges(self._mat[vi], self._unconn)
    
    @staticmethod
    def _out_edges(row, unconn):
        edge = []
        for i in range(len(row)):
            if row[i] != unconn:
                edges.append((i,row[i]))
        return edges
2.2 邻接表

邻接表是图的一种链式存储结构。主要是应对于邻接矩阵在顶点多边少的时候,浪费空间的问题。它的方法就是声明两个结构。如下图所示:
fig5

# 邻接表
def GraphAL(Graph):
    def __init__(self, mat = [], unconn = 0):
        vnum = len(mat)
        for x in mat:
            if len(x) != vnum:    # 检查是否为方阵
                raise ValueError("Argument for 'GraphAL'.")
        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 empty graph.")
        if self._invalid(vi) or self._invalid(vj):
            raise GraphError(str(vi) + 'or' + str(vj) + "is not a valid vertex.")
        row = self._mat[vi]
        i = 0
        while i < len(row):
            if row[i][0] == vj:     # 修改mat[vi][vj]的值
                self._mat[vi][i] = (vj, val)
                return
            if row[i][0] > vj:
                break
            i += 1
        self._mat[vi].insert(i, (vj, val))
        
    def get_e
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
数据结构(C语言版)》严蔚敏PDF带目录,是一本非常经典且广泛使用的数据结构教材。该书通过使用C语言作为编程语言,系统地介绍了数据结构的各种基本概念、常用算法和实际应用。以下是该书的目录。 第一部分 数据结构基础 1. 数据结构绪论 2. 算法基础 第二部分 线性表 3. 线性表的基本概念 4. 线性表的顺序存储结构 5. 线性表的链式存储结构 6. 线性表的应用 第三部分 栈与队列 7. 栈与队列的基本概念 8. 栈与队列的顺序存储结构 9. 栈与队列的链式存储结构 10. 栈与队列的应用 第四部分 串 11. 串的基本概念 12. 串的模式匹配算法 第五部分 树与二叉树 13. 树与二叉树的基本概念 14. 二叉树的存储结构 15. 二叉树的遍历 16. 线索二叉树 17. 树和森林 第六部分 18. 的基本概念 19. 的存储结构 20. 的遍历 21. 最小生成树 22. 最短路径 第七部分 查找 23. 查找的基本概念 24. 顺序表查找 25. 二叉排序树 26. 平衡二叉树 27. B树和B+树 第八部分 排序 28. 排序的基本概念 29. 插入排序 30. 希尔排序 31. 选择排序 32. 堆排序 33. 归并排序 34. 快速排序 35. 外排序 第九部分 动态规划 36. 动态规划的基本概念 37. 0-1背包问题 通过阅读该书,读者可以系统地学习和掌握数据结构的各种基础知识和常用算法,并将其应用到实际问题中。由于该教材附带了PDF和目录,读者可以方便地查阅和学习相关内容,并进行深入的理解和应用。这本书对于学习数据结构和提编程能力非常有价值,特别推荐给对数据结构感兴趣的读者。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值