[C语言] 数据结构 严蔚敏版 图的几个重点掌握算法

本文主要记录了C语言实现的几个图这一章需要重点掌握并且体会的算法。实现的结构另参照其他文章。

算法基本参照了书上的伪代码和http://www.cnblogs.com/kangjianwei101/category/791617.html

 

算法列表目录:

1.图的深度优先搜索 DFS

2.图的广度优先搜索 BFS

3.无向图的连通分量/生成树 

4.有向图的强连通分量/生成树 (SCC) Kosaraju算法

5.无向网的最小生成树 Prim 算法 和 Kruskal算法(技术不够...未实现)

6.无向图的关节点 (DFS算法的改进)

7.有向无环图的拓扑排序 (+对是否有环的判断)

8.有向网的关键路径 (依赖拓扑序列的实现)

9.有向网的最短路径 Dijkstra 算法和 Floyd算法

说明:基本上无特殊注释的数组0号单元均未弃用

 

算法实现:

1.图的深度优先搜索 DFS

        算法依赖于实现寻找弧/边和下一条弧/边的函数FirstAdjVex,NextAdjVex。输入与返回均为顶点值

Status DFSTraverse (ALGraph G, Status(*Visit)(VertexType))
{
    int v;
    VisitFunc = Visit;
    for (v=0;v<G.vexnum;v++){
        visited[v] = -1;
    }
    pre = 0;
    for (v=0;v<G.vexnum;v++){
        if(visited[v]==-1)
            DFS(G,v);
    }
    return OK;
}

Status DFS (ALGraph G,int v)
{
    int w;
    if (VisitFunc(G.vertices[v].data)==ERROR)
        return ERROR;

    visited[v] = pre;
    pre = v;
    for (w = FirstAdjVex(G,G.vertices[v].data);w>=0;w = NextAdjVex(G,G.vertices[v].data,G.vertices[w].data)){
        if (visited[w]==-1)
            DFS(G,w);
    }
    return OK;
} //开始每一次遍历的序号

2.图的广度优先搜索 BFS

        BFS同样依赖于FirstAdjVex,NextAdjVex函数,以及队列这个数据结构。

Status BFSTraverse (ALGraph G, Status(*Visit)(VertexType))
{
    int v,w;
    LinkQueue Q;
    InitQueue(&Q);
    QElemType e;
    for (v=0;v<G.vexnum;v++){
        visited[v] = -1;
    }
    pre = 0;
    for (v=0;v<G.vexnum;v++){
        if (visited[v]==-1){
            visited[v] = pre;
            Visit(G.vertices[v].data);
            EnQueue(&Q,v);
            while (!QueueEmpty(Q)){
                DeQueue(&Q,&e);
                for (w= FirstAdjVex(G,G.vertices[e].data);w>=0;w=NextAdjVex(G,G.vertices[e].data,G.vertices[w].data)){
                    if (visited[w]==-1){
                        Visit(G.vertices[w].data);
                        visited[w] = pre;
                        pre = w;
                        EnQueue(&Q,w);
                    }
                }
            }
        }
    }
    return OK;
}

3.无向图的连通分量/生成树 

        生成树的存储方法为Left Child-Right Sibling二叉树。本质是DFS遍历顶点。算法利用DFS核心函数的特性,跳出一次核心函数代表着创建出了一棵生成树,树的结点构成了图的连通分量。

#ifndef SPANNINGTREE_H
#define SPANNINGTREE_H

#include <stdio.h>
#include <stdlib.h>
#include "MGraph.h"
#include "ChildSibling.h"

//无向图生成树函数列表
void DFSForest (MGraph G, CSTree *T);
//创建无向图的生成树

void DFSTree (MGraph G,int v,CSTree *T);
//生成结点v起始的树


#endif // SPANNINGTREE_H
#ifndef SPANNINGTREE_C
#define SPANNINGTREE_C

#include "SpanningTree.h"

//无向图生成树函数列表
void DFSForest (MGraph G, CSTree *T)
{ //建立无向图G的深度优先生成森林的最左孩子右兄弟生成链表T
    InitTree_CS(T);

    int v; //用来遍历
    for (v=0;v<G.vexnum;v++){
        visited[v] = FALSE;
    }

    CSTree p,q; //p为新的根节点,q为上一个根节点
    for (v=0;v<G.vexnum;v++){
        if (!visited[v]){
                //新的树生成根节点
            p = (CSTree)malloc(sizeof(CSNode));
            if (!p)
                exit (OVERFLOW);
            p->data = GetVex_M(G,v);
            p->firstchild = p->nextsibling = NULL;

            if(TreeEmpty_CS(*T))
                *T = p; //第一棵生成树的根
            else
                q->nextsibling = p;

            q = p;
            DFSTree(G,v,&p);
        }
    }
}
//创建无向图的生成树

void DFSTree (MGraph G,int v,CSTree *T)
{
    //从顶点序号v出发深度优先遍历图G,建立以T为根的生成树
    Status first;
    int w;
    CSTree p,q;

    visited[v] = TRUE;
    first = TRUE;

    for (w=FirstAdjVex_M(G,G.vexs[v]);w>=0;w=NextAdjVex_M(G,G.vexs[v],G.vexs[w])){
        if (!visited[w]){
            //分配孩子结点
            p = (CSTree)malloc(sizeof(CSNode));
            if (!p)
                exit(OVERFLOW);
            p->data = GetVex_M(G,w);
            p->firstchild = p->nextsibling = NULL;

            if (first){
                (*T)->firstchild = p;
                first = FALSE;
            } else
                q->nextsibling = p;

            q = p;
            DFSTree(G,w,&q);
        }
    }
}
//生成结点v起始的树

#endif // SPANNINGTREE_C

4.有向图的强连通分量/生成树 (SCC) Kosaraju算法

        生成树的存储方法为Left Child-Right Sibling二叉树。

        其中finished[]数组最为精髓。它用来记录正常深度搜索跳出DFS核心函数的顶点序号。

        然后逆置有向图。再从finished[]数组的最后一个顶点出发,对逆向图进行DFStraverese。此时每调用一次DFS函数访问到的顶点集便是有向图的一个强连通分量SCC所构成的顶点集。

#ifndef SCC_H
#define SCC_H

//利用十字链表存储的有向图求强连通分量
//Kosaraju算法
#include <stdio.h>
#include "OLGraph.h"
#include "ChildSibling.h"

//全局变量
int counts;
int finished [MAX_VERTEX_NUM];

//求强连通分量的函数列表
void InverseGraph (OLGraph *G);
//逆制有向图

void DFSTraverse_SCC (OLGraph G);
//改动后的深度优先遍历

void DFS_SCC1(OLGraph G, int v);

void DFS_SCC2(OLGraph G, int v);

void Kosaraju (OLGraph G);
//有向图的强连通分量的kosaraju算法

void KosarajuForest(OLGraph G, CSTree* T);

void KosarajuTree (OLGraph G,int v,CSTree *T);
#endif // SCC_H
#ifndef SCC_C
#define SCC_C

#include "SCC.h"

全局变量
//int counts;
//int finished [MAX_VERTEX_NUM];

void InverseGraph (OLGraph *G)
{
    int i; //i用来遍历顶点
    VexNode *h; //用来遍历顶点
    ArcBox *tmp,*p,*q; //p用来遍历弧
    int k;//用来交换顶点序号
    for (i=0;i<G->vexnum;i++){
        h = &(G->xlist[i]);

        if (h->firstout)
            p = h->firstout;
        //交换第一条入弧和出弧
        tmp = h->firstout;
        h->firstout = h->firstin;
        h->firstin = tmp;
        //交换每条弧
        while (p){
            q = p;
            p = p->tlink;

            k = q->tailvex;
            q->tailvex = q->headvex;
            q->headvex = k;

            tmp = q->tlink;
            q->tlink = q->hlink;
            q->hlink = tmp;
        }
    }
}
//逆制有向图

vo
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值