数据结构05:图

来源:互联网 发布:笛子软件下载 编辑:程序博客网 时间:2024/05/16 01:30

图的基本概念

  1. 图:顶点(V ) + 边(E)的集合
  2. 有向图和无向图
  3. 弧(有向图)
  4. 顶点的度、入度、出度
  5. 有向完全图(任意两个顶点间都有两条边相连) + 无向完全图(任意两个顶点间都有一条边相连)
  6. 连通图, 连通分量,极大连通分量(任意两个顶点之间都连通无向图)
  7. 强连通图、强联通分量,(有向图)

图的存储结构

邻接矩阵

  1. 邻接矩阵概念:图的顺序存储结构,表示图中顶点之间关系的矩阵(A[i][j] = 0/1表示第i个结点和第j个结点的邻接状态,或者权重)
    这里写图片描述
  2. 邻接矩阵的定义(顶点的定义 + 邻接矩阵的定义)
//顶点的定义typedef struct {    int no;//顶点编号    char info;//顶点的其它信息}VertexType;//邻接矩阵的定义typedef struct {    VertexType vex[maxSize];//存放结点的信息    int n,e;//图的顶点数和边数    int edges[maxSize][maxSize];//边的定义}MGraph;

邻接表
这里写图片描述
这里写图片描述

  1. 邻接表的定义
    图的链式存储结构 + 第一个结点存放顶点的信息(顶点表) + 其余结点存放边的信息(边表)
  2. 邻接表存储结构的定义(含有三个信息:边表 + 顶点表 + 邻接表)
//边结点的定义:所指向的顶点编号 + 下一个边表的指针 + 其它信息(譬如说权值)typedef struct ArcNode {    int adjvex;    struct ArcNode * nextr;    char info;}ArcNode;//顶点结点的信息:其它信息(结点自带的信息 + 第一个边结点的指针)typedef struct VNode {    char data;    ArcNode * firstArc;}VNode;//邻接表的定义:定点结点数组 + 结点数 + 边树typedef struct {    VNode adjlist[maxSize];    int n,e;}AGraph;

图的遍历算法操作

深度优先遍历(DFS)
类似于二叉树的先序遍历 + 邻接表的存储结构 + 想象在邻接表中遍历过程是怎么进行的
遍历算法为:

void DFS(AGraph *G, int v) {    ArcNode *p;    visit[v] = 1;//访问标识位    visit(v);    p = G->adjList[v].firstArc;    while(p != null) {        if(visit[p->adjvex] == 0) {            DFS(G, p->adjvex);        }           p = p->nextArc;    }}

广度优先遍历(BFS)
类似于二叉树的层次遍历,不同的是:循环列表存储的是顶点结点的编号 + 先访问,再入队 + 有visit[]判断是否访问过 + 将顶点结点的所有邻接节点入队
(P174)

最小生成(代价)树

(与前面的最优二叉树(郝夫曼树 + 带权路径最短 )要区分开来)
生成树:包含连通图G所有结点的树称之为生成树
最小生成树:边的代价之和最小的生成树称之为最小生成树
普里姆算法求解最小生成树

  1. 思想:从连通图中任取一个结点当成一棵树,然后从这棵树相邻的所有边中取权值最小的边,并将这条边所连接的顶点并入这棵树,直至所有的结点都并入这棵树,得到的这颗树即为最小生成树。
  2. 算法时间复杂度分析:n的平方,只与顶点有关而与边无关、适用于边多的稠密图

克鲁斯卡尔算法求解最小生成树
1. 思想:每次都从图中选取权值最小的边,直至构成一棵树,即为最小生成树(注意不要构成回路)
2. 算法时间复杂度分析:取决于对边的排序算法,适用于边少的稀疏图

最短路径

最短路径:从某一顶点到其余个顶点的最短路径
迪杰斯特拉算法

  1. 迪杰斯特拉算法思想
    设有两个顶点集合S和T,集合S存放的是找到了最短路径的顶点,T存放的是还没找到最短路径的顶点(剩余顶点)。一开始的时候,集合S只包含一个初始顶点,然后从集合T中找出路径最短的结点并入到集合S。每并入一个新的顶点到集合S中,就要修改初始顶点到T中剩余顶点点的最短路径长度,直到T中剩余结点全部并入到S集合中
  2. 如何理解每并入一个新的顶点到集合S中,就要修改初始顶点到T中剩余顶点的最短路径长度
    每找到一个新的最短路径顶点的时候,就相当于多了一条从初始顶点到剩余顶点T中的路径,将原路径的长度跟新的路径长度对比,如果这条心的路径长度更短的话,则这条新的路径长度即为初始顶点到达该剩余顶点的最短路径。
  3. 迪杰斯特拉算法求解最短路径问题的过程:dis[](距离) + path[](前驱顶点)
  4. 迪杰斯特拉算法的时间复杂度:n的平方

弗洛伊德算法

  1. 弗洛伊德算法求解的问题:有向图中任意一对顶点间的最短路径
  2. 佛洛依德算法求解任意一对顶点间最短路径问题的过程:
    首先用邻接矩阵表示任意两个邻接顶点的距离,然后依次以每一个顶点作为其他顶点的中间结点,计算通过该中间结点的具体与原距离进行比较,如果小的话则修改这两个顶点间的最短距离(Ai[]:距离举证 + Pathi[]:最短距离的中间结点)
  3. 弗洛伊德算法的时间复杂度:n的立方

拓扑排序

AOV网:activity on Vertex活动在结点上的网

  1. AOV网的概念:是一种以顶点表示活动,边表示活动的先后次序且没有回路的有向图。它在实际中的意义是表示一个工程或者一个项目中各个活动之间的先后关系。
  2. 拓扑排序:描述一个工程或者一个项目中各个活动之间先后关系的顶点序列
  3. 拓扑排序的方法:选择入度为0的顶点,输出并删除该顶点的边。
  4. 拓扑排序:可能不唯一 + 逆拓扑排序

关键路径

AOE网activity on Edge活动在边上的网

  1. AOE网的概念:是一种边表示活动,边上的权值表示活动持续的事件,顶点表示事件(一项活动的开始或者结束标志)的有向无环图
  2. 关键路径:源点到终点的所有路径当中最长路径成为关键路径
  3. 关键路径即表示了AOE网中的最长路径,也表示了整个活动完成的最短时间
    (这样理解:事件K要发生,必须K之前的所有活动必须都结束了才能发生,而且K之前的活动可能有很多,因此要选用一个最长的路径作为事件K的最早发生时间)
  4. 关键路径的求解步骤:
    1、拓扑,求出每个事件的最早发生时间(事件有几个入度箭头,就有几种可能性 + 选Max)
    2、逆拓扑,求出每个事件的最迟发生时间(事件的最迟发生时间,就是在不推迟整个工程或者项目的前提下,该事件最迟必须发生的时间)(事件的最早发生时间 + 事件有几个出度箭头,就有几种可能性 + 选Min)
    3、求出活动的最早发生时间:活动的最早发生时间 == 事件的最早发生时间
    4、求出活动的最迟发生时间:活动的最迟发生时间 == 事件最迟发生时间 - 活动持续的事件
    5、最早发生时间和最迟发生时间相同的活动即为关键活动。
    剩余事件:活动的最迟开始时间 - 活动的最早开始时间,它表现了一个活动完成的松弛度,关键活动的剩余时间为0。
0 0