06数据结构——图

6.2图的存储及基本操作

6.2.1邻接矩阵法

图的邻接矩阵存储结构定义如下:

#define MaxVertexNUm 100            //顶点数目的最大值
typedef char VertexType;            //顶点的数据类型
typedef int EdgeType;               //带权图中边上权值的数据类型
typedef struct{
    VertexType Ver[MaxVertexNum];   //顶点表
    EdgeType Edge[MaxVertexNum][MaxVertexNum];    //邻接矩阵,边表
    int vexnum,arcnum;                            //图的当前顶点数和弧数
}MGraph;

6.2.2邻接表法

图的邻接表存储结构定义如下:

#define MaxVertexNum 100                //图中顶点数目的最大值
typedef struct ArcNode{                 //边表结点
    int adjvex;                         //该弧所指向的顶点的位置
    struct ArcNode *next;               //指向下一条弧的指针
    //InfoType info;                    //网的边权值
}ArcNode;
typedef struct VNode{                   //顶点表结点
    VertexType data;                    //顶点信息
    ArcNode *first;                     //指向第一条依附该结点的弧的指针
}VNode,AdjList[MaxVertexNum];
typedef struct{
    AdjList vertices;                   //邻接表
    int vexnum,arcnum;                  //图的顶点数和弧数
}ALGraph;                               //ALGraph是以邻接表存储的图类型

6.2.3十字链表

6.2.4邻接多重表

6.2.5图存储小结 


6.3图的遍历 

6.3.1广度优先搜索(BFS)

1.广度优先搜索算法的伪代码如下:

bool visited[MAX_VERTEX_NUM];        //访问标记数组
void BFSTraverse(Graph G){           //对图G进行广度优先遍历
    for(i=0;i<G.vexnum;++i)
        visited[i]=FALSE;            //访问标记数组初始化
    InitQueue(Q);                    //初始化辅助队列Q
    for(i=0;i<G.vexnum;++i)          //从0号顶点开始遍历
        if(!visited[i])              //对每个连通分量调用一次BFS
            BFS(G,i);                //Vi未访问过,从Vi开始BFS
}
void BFS(Graph G,int v){            //从顶点v出发,广度优先遍历图G
    visit(v);                       //访问初始顶点v
    visited[v]=TRUE;                //对v做已访问标记
    EnQueue(Q,v);                   //顶点v入队列Q
    while(!isEmpty(Q)){
        DeQueue(Q,v);               //顶点v出队列
        for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))
                                    //检测v所有邻接点
        if(!visited[w]){            //w为v的尚未访问的邻接顶点
            visit(w);               //访问顶点w
            visited[w]=TRUE;        //对w做已访问标记
            EnQueue(Q,w);           //顶点w入队列
        }
    }
}

2.BFS算法求解单源最短路径问题的算法如下:

void BFS_MIN_Distance(Graph G,int u){
    for(i=0;i<G.vexnum;++i)
        d[i]=∞;                    //初始化路径长度
    visited[u]=TRUE; d[u]=0;
    EnQueue(Q,u);
    while(!isEmpty(Q)){            //BFS算法主过程
        DeQueue(Q,u);              //对头元素u出队
        for(w=FirstNeighbor(G,u);w>=0;w=NextNeighbor(G,u,w))
            if(!visited[w]){        //w为u的尚未访问的邻接顶点
                visited[w]=TRUE;    //设已访问标记
                d[w]=d[u]+1;        //路径长度加1
                EnQueue(Q,w);       //顶点w入队
            }
     }
}

 6.3.2深度优先搜索(DFS)

1.用递归进行深度优先搜索算法过程如下:

bool visited[MAX_VERTEX_NUM];        //访问标记数组
void DFSTraverse(Graph G){           //对图G进行深度优先遍历
    for(v=0;v<G.vexnum;++v)
        visited[v]=FALSE;            //初始化已访问标记数组
    for(v=0;v<G.vexnum;++v)          //本代码中是从v=0开始遍历
        if(!visited[v])
            DFS(G,v);
}
void DFS(Graph G,int v){            //从顶点v出发,深度优先遍历图G
    visit(v);                       //访问顶点v
    visited[v]=TRUE;                //设已访问标记
    for(w=FirstNeighbor(G,v);w>=0;w=NextNeighbor(G,v,w))
        if(!visited[w]){            //w为v的尚未访问的邻接顶点
            DFS(G,w);
        }
}

6.4图的应用

6.4.1最小生成树

1.通用的最小生成树算法如下:

GENERIC_MST(G){
    T=NULL;
    while T 未形成一棵生成树;
        do 找到一条最小代价边(u,v)并且加入T后不会产生回路;
            T=T∪(u,v);
}

2.Prim算法

 Prim算法的简单实现如下:

void Prim(G,T){
    T=∅;                //初始化空树
    U={w};              //添加任意一个顶点w
    while((V-U)!=∅){    //若树中不含全部顶点
        设(u,v)是使u∈U与v∈(V-U),且权值最小的边;
        T=T∪{(u,v)};    //边归入树
        U=U∪{v};        //顶点归入树
    }
}

3.Kruskal算法 

 Kruskal算法的步骤如下:

void Kruskal(V,T){
    T=V;                  //初始化树T,仅含顶点
    numS=n;               //连通分量数
    while(numS>1){        //若连通分量数大于1
        从E中取出权值最小的边(v,u);
        if{v和u属于T中不同的连通分量){
            T=T∪{(v,u)};        //将此边加入生成树中
            numS--;              //连通分量数减1
        }
    }
}

6.4.2最短路径

1.Dijkstra算法求单源最短路径问题 

2.Floyd算法求各顶点之间最短路径问题 

Floyd算法实现如下:

//......准备工作,根据图的信息初始化矩阵A和path(如上图)
for(int k=0;k<n;k++){        //考虑以Vk作为中转点
    for(int i=0;i<n;i++){    //遍历整个矩阵,i为行号,j为列号
        for(int j=0;j<n;j++){
            if(A[i][j]>A[i][k]+A[k][j]){    //以Vk为中转点的路径更短
                A[i][j]=A[i][k]+A[k][j];    //更新最短路径长度
                path[i][j]=k;               //中转点
            }
        }
    }
}

6.4.3求最短路径小结 

6.4.4有向无环图描述表达式 

6.4.5拓扑排序 

拓扑排序算法的实现如下:

bool TopologicalSort(Graph G){
    InitStack(S);                //初始化栈,存储入度为0的顶点
    int i;
    for(i=0;i<G.vexnum;i++)
        if(indegree[i]==0)
            Push(S,i);           //将所有入度为0的顶点进栈
    int count=0;                 //计数,记录当前已经输出的顶点数
    while(!isEmpty(S)){          //栈不空,则存在入度为0的顶点
        Pop(S,i);                //栈顶元素出栈
        print[count++]=i;        //输出顶点i
        for(p=G.vertices[i].firstarc;p;p=p->nextarc){
        //将所有i指向的顶点的入度减1,并且将入度减为0的顶点压入栈S
            v=p->adjvex;  
            if(!(--indegree[v]))
                Push(S,v);       //入度为0,则入栈
        }
    }//while
    if(count<G.vexnum)
        return false;            //排序失败,有向无环图中有回路
    else
        return true;            //拓扑排序成功
}

 6.4.6关键路径

posted @ 2023-10-21 16:23  freshman_xy  阅读(25)  评论(0)    收藏  举报  来源