数据结构-图

》一笔画:

        -凡是由偶点组成的连通图,一定可以一笔画成。画时可以把任一偶点为起点,最后一定能以这个点为终点画完此图。

        -凡是只有两个奇点的连通图(其余都为偶点),一定可以一笔画成。画时必须把一个奇点为起点,另一个奇点终点。

》基本概念:

        -图的抽象数据类型

ADT Graph{

        数据对象V:数据元素的集合,顶点集。

        数据关系R:R={VR},VR={<v,w>|v,w∈V,且P(v,w),<v,w>表示从v到w的弧}。

        基本操作:

                CreateGraph(&G,V,VR) ;     //构造图

                DFSTraverse(G,V,visit());     //深度遍历图

                BFSTraverse(G,V,visit());      //广度遍历图

}ADT Graph

        -任意两个结点之间的关系是任意的,图中任意两个数据元素之间都可能相关。

        -顶点:图的数据元素。

        -V是顶点的集合,VR是两个顶点之间的关系的集合。

        -有向图:<v,w>∈VR,v为弧尾、w为弧头。

        -无向图:若<v,w>∈VR,必有<w,v>∈VR,用(v,w)表示。

        -完全图:每一个顶点之间有且只有一条边的相连。

        -无向完全图:有n(n-1)/2条边。

        -有向完全图:有n(n-1)条弧。

        -稀疏图:边或弧很少的图。

        -稠密图:边或弧较多的图。

        -子图:G=(V,{E}),G`=(V`,{E`}),若V`∈V,且E`∈ E,则称G`为G的子图。

        -邻接点:对于无向图,若(v,v`)∈E,则称顶点v和v`互为邻接点,即v和v`相邻接,并称边(v,v`)关联于顶点v和v`,或称(v,v`)与顶点v和v`相关联。

        -度:一个顶点v的度是与它相关联的边的条数,记做TD(v)。

        -入度:是以v为终点的弧的条数,记做ID(v)。

        -出度:是以v为始点的弧的条数,记做OD(v)。

        -在一个图中,所有顶点的度数之和等于图的边数的2倍。

        -在一个有向图中,所有顶点的入度之和等于所有顶点的出度之和。

        -路径:图G=(V,E)中,若存在一个顶点序列(v=vi,0,vi,1,…,vi,m=v`),其中(vi,j-1,vi,j)均属于E,则称顶点vi到vj 存在一条路径。

        -简单路径:若一条路径上除了vi 和vj 可以相同外,其余顶点均不相同,则称此路径为一条简单路径。

        -简单回路(简单环):起点和终点相同的路径称为简单回路或简单环。

数据结构-图

        -连通:在无向图G中,若两个顶点vi和vj之间有路径存在,则称vi和vj是连通的。

        -连通图:若G中任意两个顶点都是连通的,则称G为连通图。

        -连通分量:无向图的极大连通子图称为的连通分量。任何连通图的连通分量只有一个,即是其自身,非连通的无向图有多个连通分量。

        -强连通图:有向图中, 若对于每一对顶点vi和vj, 都存在一条从vi到vj和从vj到vi的路径,则称此图是强连通图。

        -强连通分量:极大强连通子图叫做强连通分量。

        -生成树:一个连通图的生成树是它的极小连通子图,含有图的全部顶点,在n个顶点的情形下,有n-1条边。

             数据结构-图

        -不予讨论的图:包含顶点到其自身的边;一条边在图中重复出现。


》图的存储结构

        #define INFINITY INT_MAX

        #defineMAX_VERTEX_NUM 20

        typedefenum{DG,DN,AG,AN} GraphKind;

        typedefstruct ArcCell{

              VRType   adj;

              InfoType *info;

        }ArcCell,AdjMatrix[MAX_VERTEX_NUM][MAX_VERTEX_NUM];

        typedefstruct{

              VertexType vexs[MAX_VERTEX_NUM];

              AdjMatrix arcs;

              int vexnum,arcnum;

             GraphKind kind;

        }MGraph;

        -数组表示法(邻接矩阵/顺序存储):用两个数组分别存放顶点信息和边(弧)信息。

           数据结构-图

        -图的邻接矩阵表示中,有一个记录各个顶点信息的顶点表,还有一个表示各个顶点之间关系的邻接矩阵。

        -设图A = (V, E)是一个有n个顶点的图,则图的邻接矩阵是一个二维数组A .Edge[n][n],定义:

               数据结构-图

        -无向图的邻接矩阵是对称的,有向图的邻接矩阵可能是不对称的。

          数据结构-图

        -在有向图中, 统计第i 行1 的个数可得顶点i 的出度,统计第j 列1 的个数可得顶点j 的入度。

        -在无向图中, 统计第 i 行 (列) 1 的个数可得顶点i 的度。

        -网络的邻接矩阵:可达用边的权值表示,不可达用正无穷表示。

            数据结构-图

        -邻接表(链式存储):图中每个顶点建立一个单链表,第i个单链表中的结点表示依附于顶点vi的边。

        -逆邻接表:任一表头结点下的边结点的数量是图中该结点入度的弧的数量,与邻接表相反。

        -图的邻接表反映的是节点的出度邻接情况,逆邻接表反映的是节点的入度邻接情况。

        -有向图的邻接表中,第 i 个边链表链接的边都是顶点 i 发出的边。也叫做出边表。

        -有向图的逆邻接表中,第 i 个边链表链接的边都是进入顶点 i 的边。也叫做入边表。

        -表结点:由三个域组成:

                >邻接点域(adjvex):指示与顶点vi邻接的点在图中的位置。

                >链域(nextarc):指示下一条边(弧)的结点。

                >数据域(info):存储和边(弧)相关的信息,如权值。

            数据结构-图
        -网络的邻接表(带权图)
 数据结构-图
        -邻接表(Adjacency List)
            #define MAX_VERTEX_NUM 20
            typedef  struct  ArcNode{
                   int adjvex;
                   struct ArcNode *nextarc;
                   InfoType      *info;
            }ArcNode;
            typedef  struct VNode{
                   VertexType data;
                   ArcNode *firstarc;
            }VNode,AdjList[MAX_VERTEX_NUM];

》图的遍历性
        -图的遍历:从连通图中某一顶点出发访遍图中所有的顶点,且使每个顶点仅被访问一次。
        -图的遍历目标:解决图的连通性问题、关键路径问题等。
        -图的遍历方法:深度优先算法和广度优先算法。
        -深度优先搜索DFS(Depth First Search)       
        注意:每个结点只能被访问一次,又因为一个结点可以和其它的任何结点相邻接,为了避免对一个结点的重复访问,必须对访问过的结点加以标记。结点的邻接结点的次序是任意的,因此深度优先搜索的序列可能有多种。深度优先搜索类似于树的前序遍历。

        -访问方式:

            (1)选中第一个被访问的结点。

            (2)对结点作已访问过的标志。

            (3)依次从结点的未被访问过的第一个、第二个、第三个……邻接结点出发,进行深度优先搜索。转向2。

            (4)如果还有顶点未被访问,则选中一个起始结点,转向2。

            (5)所有的结点都被访问到,则结束。

            数据结构-图

        -图的深度遍历

            Boolean visited[Max];

            Status (*VisitFunc)(intv);

            void DFSTraverse(GraphG, Status (*Visit) (int v)){

                  VisitFunc=Visit;

                  for(v=0;v<G.vexnum;++v)   visited[v]=FALSE;

                  for(v=0;v<G.vexnum;++v)

            if(!visited[v])DFS(G,v);

            }//DFSTraverse

            void DFS(Graph G, int v){

                  vistited[v]=TRUE; VisitFunc(v);

                  for(w=FirstAdjVex(G,v); w=NextAdjVex(G,v,w))

                  if(!visited[w]) DFS(G,w);

            }//DFS

        -广度优先搜索BFS(Breadth First Search)

        注意:每个结点只能被访问一次,又因一个结点可以和其它的任何结点相邻接,为避免对一结点的重复访问,必须对访问过的结点加以标记。结点邻接结点的次序是任意的,因此广度优先搜索的序列可能有多种。广度优先搜索类似于树的从根出发的按层次遍历。

        -访问方式:

                (1)选中第一个被访问的结点V

                (2)对结点V 作已访问过的标志

                (3)依次从结点V 的未被访问过的第一个、第二个、第三个……第M个邻接结点W1、W2、W3……Wm ,且进行标记

                (4)依次访问结点W1、W2、W3……Wm的邻接结点,且进行标记。

                (5)如果还有结点未被访问,则选中一个起始结点,也标记为V,转向2。

                (6)所有的结点都被访问到,则结束。

            数据结构-图
        -图的广度遍历
        void BFSTraverse(Graph G, Status (*Visit) (int v)){
                  for(v=0;v<G.vexnum;++v)   visited[v]=FALSE;
                      InitQueue(Q);
                  for(v=0;v<G.vexnum;++v)
                  if(!visited[v]) {
                       EnQueue(Q,v);
                       while(!QueueEmpty(Q)){
                            DeQueue(Q,u);
                            vistited[u]=TRUE; Visit(u);
                            for(w=FirstAdjVex(G,u); w=NextAdjVex(G,u,w))
                               if(!visited[w]) EnQueue(Q,w);
                      }//while
                   }//if
         }//BFSTraverse

》图的连通性
        -连通图:仅需从任一顶点出发,进行深(广)度优先搜索,便可访问图中所有顶点。
        -非连通图:利用深(广)度优先搜索算法,只能访问到该顶点所在的最大连通子图(连通分量)的所有顶点。
        -生成树:极小连通子图。包含图的所有n 个结点,但只含图的n-1 条边。在生成树中添加一条边之后,必定会形成回路或环。
        -生成方法:进行深度为主的遍历或广度为主的遍历,得到深度优先生成树或广度优先生成树。
        -生成森林:在进行深度为主的遍历或广度为主的遍历时,对于非连通图,将得到多棵深度优先生成树或广度优先生成树。称之为生成森林。
            数据结构-图
            数据结构-图
                      数据结构-图
                数据结构-图

》最小生成树(最小代价生成树)
        -生成树中边的权值(代价)之和最小的树。
        -MST 性质:
                假设G = {V, {E}} 是一个连通图,U 是结点集合V 的一个非空子集。若(u,v) 是一条代价最小的边,且u 属于U,v 属于V –U,则必存在一棵包括边(u,v) 在内的最小代价生成树。
        -实际应用:
                把网络顶点看作城市,边的权看作连接城市的通讯线路成本,根据最小生成树建立的是城市间成本最低的通讯网。可类似考虑成本最低的公路网等
                 农村村庄之间的输电网络、有线电视网
                 输水管线、暖气管线、配送中心与线路的规划
        -普里姆(Prim)算法(适合稠密图)
        基本思想:
        1. 从图G 的顶点集V 中任取一顶点(例取顶点v0) 放入集合U 中,这时U={v0},TE={ },(U,TE) 是树。
        2. 在所有一个顶点在集合U 里另一顶点在集合V-U的边中,找出权值最小的边e=(u,v)(u∈U,v∈V-U),将顶点v加入集合U,将e 加入TE.(U,TE) 仍是一棵树。
        3. 重复2,直至U=V(树中包含所有顶点)。这时TE 有n-1条边,T=(U,TE) 就是G 的一棵最小生成树算法直接利用MST 性质构造最小生成树。

         数据结构-图
        -克鲁斯卡尔(Kruskal)算法(适合稀疏图)
        基本思想:
        设G = (V,E)是网络,构造最小生成树的过程:
        1.初始状态是只有n个顶点而无边的非连通图T = (V,φ),T中每个顶点自成一个连通分量。
        2.将E 中的边按递增顺序排列。构造中从小到大顺序选择两端点在T的两个不同连通分量的边e,把e加入T使这两个连通分量由于该边连接变成一个连通分量(每次操作,T 减少一个连通分量)。
        3.不断加入新边,直到T所有顶点都在一个连通分量上为止,这个连通分量就是G的一棵最小生成树。
        4.若不能得到一个连通分量,则图不连通,无最小生成树。
        -按边权值递增

          数据结构-图

》最短路径

        -问题的提出:
            交通咨询系统、通讯网、计算机网络常要寻找两结点间最短路径;
            交通咨询系统:A 到 B 最短路径;
            计算机网络:发送Email节省费用 A到B沿最短路径传送;
        -路径长度:路径上边数,路径上边的权值之和。
        -最短路径:两结点间权值之和最小的路径。

数据结构-图

        -问题解法

           -单源最短路径  —  Dijkstra算法

            对于给定的有向网G=(V,E),求源点v0到其它顶点的最短路径。Dijkstra提出了一个按路径长度递增的顺序逐步产生最短路径的方法,称为Dijkstra算法。

            数据结构-图

            数据结构-图

        Dijkstra算法求图中从顶点a到其他各顶点间的最短路径,以及执行算法过程中各步的状态。

     数据结构-图数据结构-图

          -任意顶点对之间的最短路径 — Floyd算法

              问题的提法:

                    已知一个各边权值均大于0的带权有向图,对每一对顶点vi不等于vj,要求求出vi与vj之间的最短路径和最短路径长度。

              解决问题:

                    可以利用单源最短路径算法,具体做法是依次把有向网G中的每个顶点作为源点,重复执行Dijkstra算法n次,即执行循环体:总的时间复杂度为O(n3)。

                    for (v=0;v<g.n;v++){

                        spath_dij(g,v,p,d);

                        print_gpd(g,p,d);

                    }

》AOV网与拓扑排序

        -有向无环图:没有回路的有向图。

        -AOV网(Activity On Vertex Network,顶点表示活动的网):

                用顶点表示活动,用弧表示活动间的优先关系的有向图称为顶点表示活动的网(Activity On Vertex Network),简称AOV网。在网中,若从顶点i到顶点j有一条有向路径,则i是j 的前驱。

        -拓扑排序

                 由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。

         -拓扑排序过程

         数据结构-图

        1)输入AOV网络。令 n 为顶点个数。    
        2)在AOV网络中选一个没有直接前驱(入度为0)的顶点, 并输出之;
        3)从图中删去该顶点, 同时删去所有它发出的有向 边;

        4)重复以上(2)、(3)步, 直到全部顶点均已输出,拓扑有序序列形成,拓扑排序完成;或图中还有未输出的顶点,但已跳出处理循环。这说明图中还剩下一些顶点,它们都有直接前驱,再也找不到没有前驱的顶点了。这时AOV网络中必定存在有向环。

数据结构-图   数据结构-图