【数据结构】图

【1】定义

图(Graph)是一种非线性数据结构
任意的两个元素都可能相关,即图中任一元素可以有若干个直接前驱和直接后继,属于网状结构类型。 
树是图的特例——有向无环图

【2】有向图(Digraph)

设 Vi、Vj为图中的两个顶点,若关系< Vi,Vj >存在方向性,称之为有向图,记作< Vi,Vj > ,Vi为弧尾,Vj为弧头

【3】无向图(Undigraph)

设Vi、Vj为图中的两个顶点,若关系<Vi,Vj>无方向性,称之为无向图,关系用(Vi,Vj)或(Vj,Vi)表示

【4】网(Network)

若在图的关系<Vi,Vj>或(Vi,Vj)上附加一个值w
称w为弧或边上的权。带权的图称为网。权w的具体含义视图在不同领域的应用而定,如顶点表示城市,
权w可以为两个城市间的距离等等

【5】顶点的度(Degree)

对于无向图,顶点的度等于与之直接相连的顶点的个数或者边的条数
对于有向图,顶点的度 = 出度 + 入度

【6】路径(Path)

若从顶点V出发,经过某些顶点能到达另一顶点V',则称V与V'之间存在一条路径。
若路径(Vi1,Vi2,……,Vim)中顶点不重复出现,则称其为简单路径;
若路径中只有第一顶点Vi1与最后一个顶点Vim相同,则称其为简单回路或简单环(Cycle)。

【7】图的存储结构

数组表示法
图的数组表示法又称“邻接矩阵”(Adjacency Matrix)表示法

【8】图的遍历

图的遍历是树的遍历的推广,是按照某种规则(或次序)访问图中各顶点一次且仅一次的操作,
亦是将网状结构按某种规则线性化的过程。由于图存在回路,为区别一顶点是否被访问过和避
免顶点被多次访问,在遍历过程中,应记下每个访问过的顶点,即每个顶点对应有一个标志位,
初始为False,一旦该顶点被访问,就将其置为True,以后若又碰到该顶点时,视其标志的状态,
而决定是否对其访问。
对图的遍历通常有“深度优先搜索”和“广度优先搜索”方法,二者是人工智能(AI)的一个基础。

【9】深度优先搜索(Depth First Search,简称DFS)

类似树的先根遍历。初始时,图中各顶点均未被访问,从图中某顶点(设为V0)出发,访问V0,
然后搜索V0的一个邻接点Vi,若Vi未被访问,则访问之,再搜索Vi的一个邻接点(深度优先)……。
若某顶点的邻接点全部访问完毕,则回溯(Backtracking)到它的上一顶点,然后再从此顶点又按
深度优先的方法搜索下去,……,直到能访问的顶点都访问完毕为止。

【10】广度优先搜索(Breadth First Search),简称BFS

类似树的按层次遍历。初始时,图中各顶点均未被访问,从图中某顶点(设V0)出发,访问V0,并
依次访问V0的各邻接点(广度优先)。然后,分别从这些被访问过的顶点出发,仍按照广度优先的
策略搜索其它顶点,……,直到能访问的顶点都访问完毕为止。
为控制广度优先的正确搜索,要用到队列技术,即访问完一个顶点后,让该顶点的序号进队。然后
取相应队头(出队),考察访问过的顶点的各邻接点,将未访问过的邻接点访问后再依次进队,……,
直到队空为止。

【11】代码

/* graph.h */
#ifndef GRAPH_H
#define GRAPH_H

#include "linkqueue.h"

#define N 10

struct graph{
    int n;
    char visit[N];
    int matrix[N][N]; //矩阵表示关系
};


extern struct graph *graph_create(int n);
extern int graph_input(struct graph *g);
extern int graph_output(struct graph *g);
extern void init(struct graph *g);
extern void dfs(struct graph *g,int n);
extern void bfs(struct graph *g);

#endif // GRAPH_H
/* graph.c */
#include "graph.h"
struct graph *graph_create(int n)
{
    int i;
    struct graph *g = (struct graph *)malloc(sizeof(struct graph));
    g->n=n;
    return g;
}

int graph_input(struct graph *g)
{
    int i = 0,j = 0;

    while(scanf("%d%d",&i,&j) == 2 && i!=-1)
    {
        g->matrix[i][j] = g->matrix[j][i] = 1;
    }

    return 0;
}


int graph_output(struct graph *g)
{
    int i = 0,j = 0;

    printf(" V0 V1 V2 V3 V4\n");
    for(i = 0; i < N; i++)
    {
        printf("V%d ",i);
        for(j = 0; j < N; j++)
        {
            printf("%d ",g->matrix[i][j]);
        }

        putchar(10);
    }

    return 0;
}

void init(struct graph *g)
{
    memset(g->visit,0,sizeof(g->visit));
}

void dfs(struct graph *g,int n)
{
    printf("%d ",n);
    g->visit[n]=1;
    int i;
    for(i=0;i<g->n;i++)
    {
        if(g->visit[i]==0&&g->matrix[n][i]==1)
            dfs(g,i);
    }
}

void bfs(struct graph *g)
{
    int tmp;
    int i;
    struct linkqueue *q=linkqueue_create();
    init(g);
    linkqueue_push(q,0);
    g->visit[0]=1;
    while(!linkqueue_empty(q))
    {
        tmp=linkqueue_pop(q);
        printf("out queue %d\n",tmp);
        for(i=0;i<g->n;i++)
        {
            if(g->visit[i]==0 && g->matrix[tmp][i]==1)
            {
                linkqueue_push(q,i);
                g->visit[i]=1;
                //printf("in queue %d\n",i);
            }
        }
    }
}

相关文章

【啊哈!算法】算法3:最常用的排序——快速排序       ...
匿名组 这里可能用到几个不同的分组构造。通过括号内围绕的正...
选择排序:从数组的起始位置处开始,把第一个元素与数组中其...
public struct Pqitem { public int priority; ...
在编写正则表达式的时候,经常会向要向正则表达式添加数量型...
来自:http://blog.csdn.net/morewindows/article/details/6...