• 浅谈数据结构之图的邻接矩阵深度和广度优先遍历(八)


       图:是由顶点的有穷非空集合和顶点之间边的集合组成,通常表示为:G(V,E),其中,G表示一个图,V是图G中顶点的集合,E是图G中边的集合。注意:(1).线性表中我们把数据元素叫元素,树中将数据元素叫结点,而图中数据元素,我们一般称之为顶点;(2).在图结构中,不允许没有顶点,在定义中,若V是顶点的集合,则强调了顶点集合V有穷非空;(3).线性表中,相邻的元素之间具有线性关系,树结构中,相邻两层的结点具有层次关系,而图中,任意两个顶点之间都可能有关系,顶点之间的逻辑关系用边来表示,边的集合可以是空的。

      图按照有无方向分为有向图和无向图,无向图由顶点和边构成,有向图由顶点和弧构成,弧有弧头和弧尾之分。由于图的结构比较复杂,任意两个顶点之间都可能存在联系,因此无法以数据元素在内存中的物理位置来表示元素之间的关系,也就是说,图不可能用简单的顺序存储结构来表示,而多重链表的的方式,即以一个数据域和多个指针域组成的结点表示图中的一个顶点,尽管可以实现图结构,但还是有很多问题的。

      考虑到图是由顶点和边或弧两部分组成的,而边或弧又是顶点与顶点之间的关系,所以可以用两个数组来表示图,一个以为数组存储图中顶点的信息,另一个二维数组存储图中边或弧的信息,其中这个二维数组我们一般称之为邻接矩阵。

      图的遍历和树的遍历类似,是从图中某一顶点出发访遍其余顶点,且使每一个顶点仅被访问一次,这一过程就叫做图的遍历。图的遍历又分为深度优先遍历和广度优先遍历,深度优先遍历像是一棵树的前序遍历,而广度优先遍历就类似于一棵树的层序遍历。

    图的创建及邻接矩阵深度和广度优先遍历源程序代码如下所示:

      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 
      4 #define OK 1
      5 #define ERROR 0
      6 #define TRUE 1
      7 #define FALSE 0
      8 
      9 typedef int Status;           /* Status是函数的类型,其值是函数结果状态代码,如OK等 */  
     10 typedef int Boolean;          /* Boolean是布尔类型,其值是TRUE或FALSE */
     11 
     12 typedef char VertexType;      /* 顶点类型应由用户定义 */
     13 typedef int EdgeType;         /* 边上的权值类型应由用户定义 */
     14 
     15 #define MAXSIZE 9             /* 存储空间初始分配量 */
     16 #define MAXEDGE 15
     17 #define MAXVEX 9
     18 #define INFINITY 65535
     19 
     20 typedef struct
     21 {
     22     VertexType vexs[MAXVEX];         /* 顶点表 */
     23     EdgeType arc[MAXVEX][MAXVEX];    /* 邻接矩阵,可看作边表 */
     24     int numVertexes, numEdges;       /* 图中当前的顶点数和边数 */ 
     25 }MGraph;
     26 
     27 /* 循环队列的顺序存储结构 */
     28 typedef struct
     29 {
     30     int data[MAXSIZE];
     31     int front;             /* 头指针 */
     32     int rear;              /* 尾指针,若队列不空,指向队列尾元素的下一个位置 */
     33 }Queue;
     34 
     35 /* 初始化一个空队列Q */
     36 Status InitQueue(Queue *Q)
     37 {
     38     Q->front=0;
     39     Q->rear=0;
     40     return  OK;
     41 }
     42 
     43 /* 若队列Q为空队列,则返回TRUE,否则返回FALSE */
     44 Status QueueEmpty(Queue Q)
     45 { 
     46     if(Q.front==Q.rear)         /* 队列空的标志 */
     47         return TRUE;
     48     else
     49         return FALSE;
     50 }
     51 
     52 /* 若队列未满,则插入元素e为Q新的队尾元素 */
     53 Status EnQueue(Queue *Q,int e)
     54 {
     55     if ((Q->rear+1)%MAXSIZE == Q->front)        /* 队列满的判断 */
     56         return ERROR;
     57     Q->data[Q->rear]=e;                    /* 将元素e赋值给队尾 */
     58     Q->rear=(Q->rear+1)%MAXSIZE;           /* rear指针向后移一位置, */
     59                                            /* 若到最后则转到数组头部 */
     60     return  OK;
     61 }
     62 
     63 /* 若队列不空,则删除Q中队头元素,用e返回其值 */
     64 Status DeQueue(Queue *Q,int *e)
     65 {
     66     if (Q->front == Q->rear)            /* 队列空的判断 */
     67         return ERROR;
     68     *e=Q->data[Q->front];               /* 将队头元素赋值给e */
     69     Q->front=(Q->front+1)%MAXSIZE;      /* front指针向后移一位置, */
     70                                         /* 若到最后则转到数组头部 */
     71     return  OK;
     72 }
     73 
     74 void CreateMGraph(MGraph *G)
     75 {
     76     int i, j;
     77 
     78     G->numEdges=15;
     79     G->numVertexes=9;
     80 
     81     /* 读入顶点信息,建立顶点表 */
     82     G->vexs[0]='A';
     83     G->vexs[1]='B';
     84     G->vexs[2]='C';
     85     G->vexs[3]='D';
     86     G->vexs[4]='E';
     87     G->vexs[5]='F';
     88     G->vexs[6]='G';
     89     G->vexs[7]='H';
     90     G->vexs[8]='I';
     91 
     92     for (i = 0; i < G->numVertexes; i++)        /* 初始化图 */
     93     {
     94         for ( j = 0; j < G->numVertexes; j++)
     95         {
     96             G->arc[i][j]=0;
     97         }
     98     }
     99 
    100     G->arc[0][1]=1;
    101     G->arc[0][5]=1;
    102 
    103     G->arc[1][2]=1; 
    104     G->arc[1][8]=1; 
    105     G->arc[1][6]=1; 
    106     
    107     G->arc[2][3]=1; 
    108     G->arc[2][8]=1; 
    109     
    110     G->arc[3][4]=1;
    111     G->arc[3][7]=1;
    112     G->arc[3][6]=1;
    113     G->arc[3][8]=1;
    114 
    115     G->arc[4][5]=1;
    116     G->arc[4][7]=1;
    117 
    118     G->arc[5][6]=1; 
    119     
    120     G->arc[6][7]=1; 
    121 
    122     for(i = 0; i < G->numVertexes; i++)
    123     {
    124         for(j = i; j < G->numVertexes; j++)
    125         {
    126             G->arc[j][i] =G->arc[i][j];
    127         }
    128     }
    129 }
    130  
    131 Boolean visited[MAXVEX];     /* 访问标志的数组 */
    132 
    133 /* 邻接矩阵的深度优先递归算法 */
    134 void DFS(MGraph G, int i)
    135 {
    136     int j;
    137      visited[i] = TRUE;
    138      printf("%c ", G.vexs[i]);        /* 打印顶点,也可以其它操作 */
    139     for(j = 0; j < G.numVertexes; j++)
    140         if(G.arc[i][j] == 1 && !visited[j])
    141              DFS(G, j);               /* 对为访问的邻接顶点递归调用 */
    142 }
    143 
    144 /* 邻接矩阵的深度遍历操作 */
    145 void DFSTraverse(MGraph G)
    146 {
    147     int i;
    148      for(i = 0; i < G.numVertexes; i++)
    149          visited[i] = FALSE;         /* 初始所有顶点状态都是未访问过状态 */
    150     for(i = 0; i < G.numVertexes; i++)
    151          if(!visited[i])             /* 对未访问过的顶点调用DFS,若是连通图,只会执行一次 */ 
    152             DFS(G, i);
    153 }
    154 
    155 /* 邻接矩阵的广度遍历算法 */
    156 void BFSTraverse(MGraph G)
    157 {
    158     int i, j;
    159     Queue Q;
    160     for(i = 0; i < G.numVertexes; i++)
    161            visited[i] = FALSE;
    162     InitQueue(&Q);                      /* 初始化一辅助用的队列 */
    163     for(i = 0; i < G.numVertexes; i++)  /* 对每一个顶点做循环 */
    164     {
    165         if (!visited[i])                /* 若是未访问过就处理 */
    166         {
    167             visited[i]=TRUE;            /* 设置当前顶点访问过 */
    168             printf("%c ", G.vexs[i]);          /* 打印顶点,也可以其它操作 */
    169             EnQueue(&Q,i);              /* 将此顶点入队列 */
    170             while(!QueueEmpty(Q))       /* 若当前队列不为空 */
    171             {
    172                 DeQueue(&Q,&i);         /* 将队对元素出队列,赋值给i */
    173                 for(j=0;j<G.numVertexes;j++) 
    174                 { 
    175                     /* 判断其它顶点若与当前顶点存在边且未访问过  */
    176                     if(G.arc[i][j] == 1 && !visited[j]) 
    177                     { 
    178                          visited[j]=TRUE;            /* 将找到的此顶点标记为已访问 */
    179                         printf("%c ", G.vexs[j]);    /* 打印顶点 */
    180                         EnQueue(&Q,j);               /* 将找到的此顶点入队列  */
    181                     } 
    182                 } 
    183             }
    184         }
    185     }
    186 }
    187 
    188 
    189 int main(void)
    190 {    
    191     MGraph G;
    192     CreateMGraph(&G);
    193     
    194     printf("
    1.图的邻接矩阵的深度优先遍历为:");
    195     DFSTraverse(G);
    196     
    197     printf("
    2.图的邻接矩阵的广度优先遍历为:");
    198     BFSTraverse(G);
    199     
    200     return 0;
    201 }
  • 相关阅读:
    August 4th, 2016, Week 32nd, Thursday
    August 3rd, 2016, Week 32nd, Wednesday
    Java的垃圾回收机制
    学java入门到精通,不得不看的15本书
    java中set和get方法的理解
    eclipse快捷键
    main方法无法编译
    Java构造器和方法的区别
    交换两个变量的值,不使用第三个变量
    计算圆周率 Pi (π)值, 精确到小数点后 10000 位 只需要 30 多句代码
  • 原文地址:https://www.cnblogs.com/mix88/p/6241495.html
Copyright © 2020-2023  润新知