【数据结构6】图

来源:互联网 发布:python 异或加密算法 编辑:程序博客网 时间:2024/06/03 20:37

  • 图存储结构的定义
    • 1 图的邻接矩阵定义法
    • 2 图的邻接表定义法
    • 3 有向图的十字链表定义法
    • 4 无向图的邻接多重表定义法
  • 图的遍历
    • 1 深度优先搜索
    • 2广度优先搜索
  • 图的基本应用
    • 1 最小生成树
      • 11 Prim算法
      • 12 Kruskal算法
    • 2 最短路径
      • 21 Dijkstra算法
      • 22 Floyd-Warshall算法
    • 3 拓扑排序
    • 4 关键路径
  • 图的实例

1 图存储结构的定义

1.1 图的邻接矩阵定义法

用一个一维数组存储图中顶点(vertex)的信息,用一个二维数组存储图中边(弧arc)的信息(即各顶点之间的邻接关系)。存储顶点之间的邻接关系的二维数组称为邻接矩阵
 对于有向图,如果vi到vj有边,arc[vi][vj] = 1;如果vi到vj无边,arc[vi][vj] = 0。
 对于无向图,如果vi到vj有边,arc[vi][vj] = arc[vj][vi] = 1;如果vi到vj无边,arc[vi][vj] = arc[vj][vi] = 0。
这里写图片描述
 对于带权图(网),若顶点vi和vj之间有边相连,则邻接矩阵中对应项存放着对应的权值;若不相连,则用∞来表示两个顶点之间不存在的边。
这里写图片描述

#define MaxVertexNum 100#define VertexType int//## 1.1 图的邻接矩阵定义法typedef struct{                             VertexType vexs[MaxVertexNum];          //顶点信息    int arc[MaxVertexNum][MaxVertexNum];    //边(弧)信息    int vexnum,arcnum;                      //顶点数和边数}MGraph;    //以邻接矩阵存储的图类型

图的邻接矩阵存储表示法的特点:
1. 无向图的邻接矩阵一定是个对称矩阵,并且唯一。因此,在实际存储邻接矩阵只需存储上(下)三角矩阵的元素即可。
2. 对于无向图,邻接矩阵的第i行(或第i列)非零元素的个数正好是第i个顶点的。对于有向图,邻接矩阵的第i行(或第i列)非零元素的个数正好是第i个顶点的出度(或入度)
3. 容易确定图中任意两个顶点是否有边,但要确定图中有多少条边则按行(列)对每个元素检测,时间开销很大。
4. 空间复杂度为O(n^2),适合存储稠密图
5. 非带权图的邻接矩阵n次方值,就是对应顶点间路径长度为n的路径条数。

1.2 图的邻接表定义法

邻接表法是对图G中的每个顶点vi,将所有邻接于vi的顶点链成一个单链表,这个单链表就称为顶点vi的边表(对于有向图则称为出边表),边表的头指针(firstarc)和顶点信息采用顺序存储,称为顶点表。所以,在邻接表中存在两种结点:顶点表(头)结点和边表结点。
这里写图片描述

#define MaxVertexNum 100#define VertexType int#define WeightType double//## 1.2 图的邻接表定义法typedef struct ArcNode{ //弧(边表)结点    int adjvex;         //弧所指顶点的位置(下标)    WeightType cost;    //带权图的边权值(info)    struct ArcNode *nextarc;//下一条弧指针    //ArcNode *nextarc; //is also ok}ArcNode;typedef struct{         //顶点表(顶点/头)结点    VertexType data;        //顶点数据    ArcNode *firstarc;      //指向第一条依附该顶点的弧指针}VNode,AdjList[MaxVertexNum];typedef struct{     AdjList vertices;       //邻接表    int vexnum,arcnum;      //顶点数和边数}ALGraph;           //以邻接表存储的图类型

图的邻接表存储表示法的特点:
1. 对于图G=(V,E),如果G为无向图,则所需存储空间为O(|V|+2|E|);如果G为有向图,则所需存储空间为O(|V|+|E|)
2. 对于稀疏图,采用邻接表表示将大大节省存储空间。
3. 求某个顶点的所有邻边,只需读取它的邻接表。其效率O(ViE)一般比邻接矩阵O(n)所实现的优。
4. 确定两个顶点是否有边,需在邻接表相应的边表中查找另一个结点。其效率O(ViE)不如邻接矩阵O(1)所实现的。
5. 在有向图的邻接表中,求某个顶点的出度只需计算其边表结点个数;但求其入度,则需要遍历全部边表,因此可以设计逆邻接表实现快速求其入度,也可以设计下面的有向图的十字链表来实现。
6. 图的邻接表表示并不唯一,但可表示一个确定的图。因为每个顶点的边结点链接次序可以是任意的,取决于建立邻接表的算法和边的输入次序。

1.3 有向图的十字链表定义法

这里写图片描述
这里写图片描述

#define MaxVertexNum 100#define VertexType int#define InfoType double//## 1.3 有向图的十字链表定义法typedef struct XArcNode{    int tailvex,headvex;    struct XArcNode *hlink,*tlink;    //XArcNode *hlink,*tlink;//Successful    //InfoType info;}XArcNode;typedef struct{    VertexType data;    XArcNode *firstin,*firstout;}XVNode;typedef struct{    XVNode xlist[MaxVertexNum];    int vernum,arcnum;}XLGraph;

1.4 无向图的邻接多重表定义法

2 图的遍历

2.1 深度优先搜索

#include<stdio.h>#define MaxVertexNum 100#define VertexType int#define WeightType double#define InfoType doubleint visited[MaxVertexNum];//## 1.1 图的邻接矩阵定义法typedef struct{    VertexType vexs[MaxVertexNum];    int arc[MaxVertexNum][MaxVertexNum];    int vexnum,arcnum;}MGraph;//## 1.2 图的邻接表定义法typedef struct ArcNode{    int nodeindex;    WeightType cost;    struct ArcNode *nextarc;    //ArcNode *nextarc;//Successful    //AdjNode *nextarc;//[Error] 'AdjNode' does not name a type}AdjNode;typedef struct{    VertexType data;    AdjNode *firstarc;}VNode,AdjList[MaxVertexNum];typedef struct{    AdjList vertices;    int vexnum,arcnum;}ALGraph,Graph;void DFS_M(MGraph G,int i){    visited[i]=1;    printf("%d ",i);//    for(int j=0;j<G.vexnum;j++){        if(visited[j]==0&&G.arc[i][j]==1){            DFS_M(G,j);        }    }}void DFS_AL(ALGraph G,int i){    visited[i]=1;    printf("%d ",i);//    for(ArcNode *p=G.vertices[i].firstarc;p;p=p->nextarc){        int ind=p->nodeindex;        if(visited[ind]==0){            DFS_AL(G,ind);        }    }}void DFSTraverse(Graph G){    for(int i=0;i<G.vexnum;i++){        visited[i]=0;    }    for(int i=0;i<G.vexnum;i++){        if(visited[i]==0){            //DFS_M(G,i);//邻接矩阵            DFS_AL(G,i); //邻接表        }    }}int main(){    return 0;}

2.2广度优先搜索

#include<stdio.h>#define MaxVertexNum 100#define VertexType int#define WeightType double#define InfoType doubleint visited[MaxVertexNum];//## 1.1 图的邻接矩阵定义法typedef struct{    VertexType vexs[MaxVertexNum];    int arc[MaxVertexNum][MaxVertexNum];    int vexnum,arcnum;}MGraph;//## 1.2 图的邻接表定义法typedef struct ArcNode{    int nodeindex;    WeightType cost;    struct ArcNode *nextarc;    //ArcNode *nextarc;//Successful    //AdjNode *nextarc;//[Error] 'AdjNode' does not name a type}AdjNode;typedef struct{    VertexType data;    AdjNode *firstarc;}VNode,AdjList[MaxVertexNum];typedef struct{    AdjList vertices;    int vexnum,arcnum;}ALGraph,Graph;void BFS_AL(ALGraph G,int i){    visited[i]=1;    printf("%d ",i);    InitQueue(Q);    EnQueue(Q,i);    while(!IsEmpty(Q)){        int v;        DeQueue(Q,v);        for(ArcNode* p=G.vertices[v].firstarc;p;p=p->nextarc){            int ind=p->nodeindex;            if(visited[ind]==0){                printf("%d ",ind);                visited[ind]=1;                EnQueue(Q,ind);            }        }    }}void BFS_M(MGraph G,int i){    visited[i]=1;    printf("%d ",i);    InitQueue(Q);    EnQueue(Q,i);    while(!IsEmpty(Q)){        int v;        DeQueue(Q,v);        for(int ind=0;ind<G.vexnum;ind++){            if(visited[ind]==0&&G.arc[v][ind]==1){                printf("%d ",ind);                visited[ind]=1;                EnQueue(Q,ind);            }        }    }}void BFSTraverse(Graph G){    for(int i=0;i<G.vexnum;i++){        visited[i]=0;    }    for(int i=0;i<G.vexnum;i++){        if(!visited[i]){            //BFS_M(G,i);//邻接矩阵            BFS_AL(G,i); //邻接表        }    }}int main(){    return 0;}

3 图的基本应用

3.1 最小生成树

3.1.1 Prim算法

3.1.2 Kruskal算法

#include<stdio.h>#include<algorithm>#define MaxVertexNum 100//## 1.1 图的邻接矩阵定义法using namespace std;typedef struct{    int a,b,w;}Road;typedef struct{    int vexnum,arcnum;    Road road[MaxVertexNum];}MGraph;    int sum=0;    MGraph G;    int v[MaxVertexNum];int getRoot(int n){    while(n!=v[n])        n=v[n];    return n;}bool cmp(Road r1,Road r2){    return r1.w<r2.w;}void Kruskal(MGraph g,int &sum,Road road[]){    int N=g.vexnum,E=g.arcnum;    sum=0;    for(int i=1;i<=N;i++){        v[i]=i;    }    sort(road+1,road+E+1,cmp);    //sort(v,v+MaxVertexNum);    for(int i=1;i<=E;i++){        int a1=road[i].a;        int b1=road[i].b;        int ra=getRoot(a1);        int rb=getRoot(b1);        if(ra!=rb){            v[ra]=rb;sum+=road[i].w;        }    }}void input(){    printf("input vexnum arcnum:");    scanf("%d %d",&G.vexnum,&G.arcnum);    for(int i=1;i<=G.arcnum;i++){        scanf("%d %d %d",&G.road[i].a,&G.road[i].b,&G.road[i].w);    }}int main(){    input();    Kruskal(G,sum,G.road);    printf("%d\n",sum);    for(int i=1;i<=G.arcnum;i++){        printf("%d ",G.road[i].w);    }    return 0;}/*input6 101 2 61 4 52 3 52 5 34 3 54 6 23 5 63 6 45 6 61 3 1*/

3.2 最短路径

3.2.1 Dijkstra算法

/** * Copyright ? 2016 Authors. All rights reserved. * * FileName: .cpp * Author: Wu_Being <1040003585@qq.com> * Date/Time: 10-12-16 10:34 * Description: */#include <iostream>#include <cstdio>#include <string>#include <cstring>#include<vector>#include<queue>#include <algorithm>#define MAX_V 20000using namespace std;typedef long long LL;typedef unsigned long long ULL;typedef pair<int, int> Pii;const int inf  = 0x7e7e7e7e;const LL infLL = 0x7e7e7e7e7e7e7e7eLL;const unsigned uinf  = 0xfcfcfcfc;const ULL uinfLL = 0xfcfcfcfcfcfcfcfcLL;using namespace std;struct edge{    int to,cost;};typedef pair<int,int>P;int V;vector<edge>G[MAX_V];int d[MAX_V];void dijkstra(int s){    priority_queue<P,vector<P>,greater<P> >que;    fill(d,d+V,inf);    d[s]=0;//!!!!!!!!!!!    que.push(P(0,s));    while(!que.empty()){        P p=que.top();que.pop();        int v=p.second;        if(d[v]<p.first)            continue;        for(int i=0;i<G[v].size();i++){            edge e=G[v][i];            if(d[e.to]>d[v]+e.cost){                d[e.to]=d[v]+e.cost;                que.push(P(d[e.to],e.to));            }        }    }}void input(){    struct edge e;    int E,f,t,c;    cin>>V>>E;    for(int i=0;i<E;i++){        cin>>f>>t>>c;        e.cost=c;        e.to=t-1;   G[f-1].push_back(e);        //e.to=f;   G[t].push_back(e);    }}int main(int argc,char* argv[]){    input();    dijkstra(0);    for(int i=1;i<V;i++){        cout<<d[i]<<endl;    }    return 0;}/*样例输入3 31 2 -12 3 -13 1 2样例输出-1-2数据规模*/

3.2.2 Floyd-Warshall算法

void Floyd(int n){    int i, j, k;    for (k=0; k<n; k++)        for (i=0; i<n; i++)            for (j=0; j<n; j++)                if (dist[i][k] != INF && dist[k][j] !=INF                        && dist[i][j] > dist[i][k] + dist[k][j])                {                    dist[i][j] = dist[i][k] + dist[k][j];                    path[i][j] = k;        //i到j要经过K节点                }}

3.3 拓扑排序

3.4 关键路径

4 图的实例

Wu_Being 博客声明:本人博客欢迎转载,请标明博客原文和原链接!谢谢!
《【数据结构6】图》
http://blog.csdn.net/u014134180/article/details/55506259

Wu_Being 吴兵博客接受赞助费二维码

如果你看完这篇博文,觉得对你有帮助,并且愿意付赞助费,那么我会更有动力写下去。

0 0