跟我学数据结构之图

图的存储结构
  • 邻接矩阵
    定义:邻接矩阵是表示顶点之间相邻关系的矩阵。设G = (V,E)是具有n个顶点的图,顶点序号依次为0,1,2,…,n-1,则G的邻接矩阵是具有如下定义的n阶方阵A:
    A[i][j] = 1表示顶点i与j邻接,即i与j之间存在边或者弧
    A[i][j] = 0表示顶点i与j不邻接(0<=i,j<=n-1)

    邻接矩阵结构的定义

    #define MaxVertexNum 100 /*最大顶点数设为100*/
    typedef char VertexType; /*顶点类型设为字符型*/
    typedef int EdgeType; /*无权图用0或1表示顶点是否邻接,网则表示权值*/
    typedef struct {
        VertexType vexs[MaxVertexNum]; /*顶点表*/
        EdeType edges[MaxVertexNum][MaxVertexNum]; /*邻接矩阵*/
        int n,e; /*顶点数和边数*/
    }Mgragh; /*Maragh 是以邻接矩阵存储的图类型*/

建立一个图的邻接矩阵存储的算法如下:

void CreateMGraph(MGraph *G)
{
    /*建立有向图G 的邻接矩阵存储*/
    int i,j,k,w;
    char ch;
    printf("请输入顶点数和边数(输入格式为:顶点数,边数):\n");
    /*输入顶点数和边数*/
    scanf("%d,%d",&(G->n),&(G->e));
    /*输入顶点信息,建立顶点表*/
    printf("请输入顶点信息:\n");
    for (i = 0; i < G->n; i++) 
        scanf("\n%c",&(G->vexs[i]));
    /*初始化邻接矩阵*/ 
    for (i = 0;i < G->n; i++)
        for (j = 0; j<G->n; j++) 
            G->edges[i][j]=0; 
    printf("请输入每条边对应的两个顶点的序号(输入格式为:i,j):\n");
    for (k=0;k<G->e;k++)
    {
        scanf("\n%d,%d",&i,&j); /*输入e 条边,建立邻接矩阵*/
        G->edges[i][j]=1; 
        /*若加入G->edges[j][i]=1;*/
        /*则为无向图的邻接矩阵存储建立*/
    }
}
  • 邻接表
    定义:邻接表(Adjacency List)是图的一种顺序存储与链式存储结合的存储方法。邻接表表示法类似于树的孩子链表表示法。就是对于图G 中的每个顶点vi,将所有邻接于vi 的顶点vj 链成一个单链表,这个单链表就称为顶点vi 的邻接表,再将所有点的邻接表表头放到数组中,就构成了图的邻接表。在邻接表表示中有两种结点结构,如图所示:
    图片来自C语言中文网
    一种是顶点表的结点结构,它由顶点域(vertex)和指向第一条邻接边的指针域(firstedge)构成,另一种是边表(即邻接表)结点,它由邻接点域(adjvex)和指向下一条邻接边的指针域(next)构成。对于网图的边表需再增设一个存储边上信息(如权值等)的域(info),网图的边表结构如图所示
    这里写图片描述

    邻接表的定义:

#define MAX_VERTEX_NUM 100
typedef int VertexType;
typedef struct node{
    int adjvex;
    struct node * next;
    int info; /*We can add an info node to represent weight*/
}EdgeNode;

typedef struct vnode{
    VertexType vertex;
    EdgeNode * firstedge;
}VertexNode;
/*This is a weird express way,what it expected to show may like Java:VertexNode[MAX_VERTEX_NUM] AdjList*/
typedef VertexNode AdjList[MAX_VERTEX_NUM];
typedef struct{
    AdjList adjlist;
    int n, e;
}AdjGraph;
  • 图的遍历
    DFS
//define global variable
bool visited[MAX_VERTEX_NUM]; /*mark if the vertex has visited*/
int dfn[MAX_VERTEX_NUM]; /*record the DFS sequence num*/;
int cnt = 1; /* counter */
void DFSTraverse(Graph * G)
{
    for (int i = 0; i < G->n; ++i)
        visited[i] = false;
    for (int i = 0; i < G->n; ++i)
        if (!visited[i])
            DFS(G,i);
}
/*邻接表DFS*/
void DFS(AdjGraph * G, int i)
{
    EdgeNode * p;
    cout << G->adjlist[i].vertex << endl;
    visited[i] = true;
    dfn[i] = cnt ++; 
    p = G->adjlist[i].firstedge;
    while (p != NULL)
    {
        if (!visited[p->adjvex])
            DFS(G,p->adjvex);
        p = p->next;
    }
}
/*邻接矩阵DFS*/
void DFS(MGraph * G, int i)
{
    cout << G->vex[i] << endl;
    visited[i] = true;
    dfn[i] = cnt ++; /*可以不写这句*/
    for (int j = 0; j < G->n; ++j)
        if ((G->edge[i][j] == 1) && (!visited[j]))
            DFS(G,j);
}
/* A general method */
void DFS(Graph * G, int i)
{
    int w;
    cout << i << endl;
    visited[i] = true;
    dfn[i] = cnt ++;
    w = FirstAdjVertex(G,i);
    while (w != NULL)
    {
        if (!visited[w])
            DFS(G,w);
        w = NextAdjVertex(G,i,w);
    }
}
/*邻接表BFS*/
void
BFS(AdjGraph * G, int k)
{
    int i;
    Edge *p;
    Queue Q;
    InitQueue(Q);
    cout << G->adjlist[k].vertex << endl;
    visited[k] = true; 
    EnQueue(Q,k);
    while (!IsEmpty(Q))
    {
        i = DeQueue(Q);
        p = G->adjlist[i].firstedge;
        while (p != NULL)
        {
            if (!visited[p->adjvex])
            {
                visited[p->adjvex] = true;
                cout << G->adjlist[p->adjvex].vertex << endl;
                EnQueue(Q,k);
            }
            p = p->next;
        }
    }
}   
/*邻接矩阵BFS*/
void
BFS(MGraph * G, int k)
{
    int i;
    Queue Q;
    InitQueue(Q);
    cout << G->vex[k] << endl;
    visited[k] = true; 
    EnQueue(Q,k);
    while(!IsEmpty(Q))
    {
        i = DeQueue(Q);
        for (int j = 0; j < G->n; ++j)
            if (G->edge[i][j] == 1 && !visited[j])
            {
                visited[j] = true;
                EnQueue(Q,j);
                cout << G->vex[j] << endl;          
            }
    }

} 

最小生成树

  • Prime算法
    void prime(MGraph * G, int v0)
    {
        int min;
        int lowcost[MAX_VERTEX_SIZE];
        int vset[MAX_VERTEX_SIZE];
        int sum = 0; //sum up the total weight
        int k,v;
        for (int i = 0; i < G->n; ++i)
        {
            lowcost[i] = G->edges[v0][i];
            vset[i] = 0;
        }
        vset[v0] = 1;
        for (int i = 0; i < G->n - 1; ++i)
        {
            min = INF //INF是定义好的一个比图中任何一条边的权值都大的数       for (int j = 0; j < G->n; ++j)
                if (vset[j] == 0 && min > lowcost[j])
                {
                    min = lowcost[j];
                    k = j;
                }
            vset[k] = 1;
            v = k;
            cout << min << " ";
            sum += min;
            for (int j = 0; j < G->n; ++j)
            {
                if (vset[j] == 0 && lowcost[j] > G->edges[v][j])
                    lowcost[j] = G->edges[v][j];
            }
        }
    }

最短路径

有向无环图及其应用

一个有向的无环图称为有向无环图(Directed Acycline Graph),简称DAG.是比有向树更一般的特殊有向图。
  • 拓扑排序(Topological Sort)
    拓扑排序是将某个集合上的偏序得到这个集合全序的过程。
    PS:有关偏序和全序的知识
    或者,有如下定义:
    来自大话数据结构
    拓扑排序其实就是对一个有向图构造拓扑序列的过程。

    • AOV-网(Activity On Vertex Network)

AOV网是一种以顶点表示活动,以边表示活动先后次序或制约关系的有向无环图。

求拓扑排序的思路:选取图中入度为0的顶点输出并删除,同时删除从该顶点发出的边。重复以上步骤直至图中没有入度为0的点。
我们采用邻接表的结构来描述这个过程,我们把邻接表的定义稍作修改。
typedef struct node{
    int adjvex;
    struct node * next;
    int weight;
}EdgeNode;

typedef struct vnode{
    int in;
    VertexType vertex;
    EdgeNode * firstedge;
}VertexNode;
int TopoSort(AdjGraph * G)
{
    int cnt = 0;
    int temp;
    int stack[MAX_VERTEX_SIZE];
    int top = -1;
    EdgeNode * p;
    for (int i = 0; i < G->n; ++i)
        if (G->adjlist[i].in == 0)
            stack[++top] = i;
    while (top != -1)
    {
        temp = stack[top--];
        cnt ++;
        cout << temp << " ";
        p = G->adjlist[temp].firstedge;
        while (p)
        {
            (G->adjlist[p->adjvex].in)--;
            if (G->adjlist[p->adjvex].in == 0)
                stack[++top] = p->adjvex;
            p = p->next;
        } 
    }
    if (cnt == G->n)
        return 1;
    return 0;
}
这里写代码片
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值