图的遍历

http://blog.youkuaiyun.com/cqnuztq/article/details/8955970


概述

    遍历分为深度优先遍历和广度优先遍历,其对有向图和无向图都适用。深度优先,顾名思义,就是只要存在后续节点就一直往下走,直到没有后续节点或者后续节点已经被访问输出了;广度优先,就是节点一层一层的输出。举个例子,

 

    上面的两个图,深度优先遍历的结果为ABCD;而广度优先遍历的结果为ABDC。

    如何存储上面的图结构呢?可以采用数组表示法和邻接法。我这里只介绍数组表示法。

    图的结构体定义如下:

   

[html]  view plain copy
  1. typedef struct   
  2. {  
  3.     VertexType vexs[MAX_VERTEX_NUM];            //顶点向量  
  4.      VRType arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//邻接矩阵  
  5.      int vexnum,arcnum;                          //顶点数和弧数  
  6.      GKind kind;                                 //图的种类标识     
  7. }MGraph;  


    要对图进行遍历,首先应该把图建立起来。以建立无向图为例。

    输入:定点数、边数、定点标号、边的长度。

    具体的创建代码如下:

[html]  view plain copy
  1. //创建无向图  
  2. void CreatUDG(MGraph &G)  
  3. {  
  4.     int i,j,k,w;  
  5.     char v1,v2;  
  6.   
  7.     printf("输入顶点数和边数:");  
  8.     scanf("%d%d",&G.vexnum,&G.arcnum);   
  9.   
  10.     visited = (int *)malloc(G.vexnum*sizeof(int));  
  11.     for ( i = 0; i < G.vexnum; i++ )  
  12.         visited[i] = 0;  
  13.     printf("请按次序输入%d个顶点字母标号(如ABC等):",G.vexnum);  
  14.   
  15.     getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  16.      for ( i = 0; i < G.vexnum; i++ )  
  17.     scanf("%c",&G.vexs[i]);  
  18.           
  19.     getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  20.      for ( i = 0; i < G.vexnum; ++i )  
  21.     for ( j = 0; j < G.vexnum; ++j )  
  22.         {//初始化邻接矩阵  
  23.         if ( i == j )  
  24.         G.arcs[i][j] = 0;  
  25.         else  
  26.         G.arcs[i][j] = INT_MAX;  
  27.         }  
  28.       
  29.     printf("输入边的顶点和权值(如A B 1):\n");  
  30.       
  31.     for ( k = 0; k < G.arcnum; k++ )  
  32.     {  
  33.     scanf("%c %c %d",&v1,&v2,&w);  
  34.     i = LocateVex(G,v1);  
  35.          j = LocateVex(G,v2);  
  36.     G.arcs[i][j] = w;  
  37.     G.arcs[j][i] = w;  
  38.     getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  39.     }  
  40. }  


    源代码

    以下是遍历的完整代码:

[cpp]  view plain copy
  1.   
[cpp]  view plain copy
  1. //myGraph.cpp  
  2. #include <stdio.h>  
  3. #include <string.h>  
  4. #include <stdlib.h>  
  5. #include <limits.h>  
  6.   
  7. #define MAX_VERTEX_NUM 20  
  8.   
  9. typedef int QElemType;   
  10. typedef int VRType;  
  11. typedef char VertexType;  
  12. typedef enum {DG,UDG} GKind;  //{有向图,无向图}  
  13.   
  14. typedef struct QNode  
  15. {  
  16.     QElemType data;  
  17.     struct QNode *next;  
  18. }QNode,*QPtr;  
  19.   
  20. typedef struct  
  21. {  
  22.     QPtr front;  
  23.     QPtr tail;  
  24. }LinkQueue;  
  25.   
  26. typedef struct   
  27. {  
  28.     VertexType vexs[MAX_VERTEX_NUM];            //顶点向量  
  29.      VRType arcs[MAX_VERTEX_NUM][MAX_VERTEX_NUM];//邻接矩阵  
  30.      int vexnum,arcnum;                          //顶点数和弧数  
  31.      GKind kind;                                 //图的种类标识     
  32. }MGraph;  
  33.   
  34. //初始化队列  
  35. void InitQ(LinkQueue &Q);  
  36. //从队尾插入元素  
  37. void EnQueue(LinkQueue &Q,QElemType e);  
  38. //从对首删除元素  
  39. void DeQueue(LinkQueue &Q,QElemType &e);  
  40. //队列是否为空,为空返回1,否则返回0  
  41. int QEmpty(const LinkQueue &Q);  
  42.   
  43. //选择创建图的类型  
  44. void CreatGraph(MGraph &G);  
  45. //创建无向图  
  46. void CreatUDG(MGraph &G);  
  47. //创建有向图  
  48. void CreatDG(MGraph &G);  
  49. //打印邻接矩阵  
  50. void printArcs(const MGraph &G);  
  51. //返回字符在定点向量中的下标值  
  52. int LocateVex(const MGraph &G,VertexType ch);  
  53. //深度优先遍历函数  
  54. void DFSTraverse(const MGraph &G);  
  55. void DFS(const MGraph &G,int v);  
  56. //广度优先遍历函数  
  57. void BFSTraverse(const MGraph &G);  
  58. //得到第一个未被访问的相邻节点下标,若无,则返回-1  
  59. int firstAjdVex(const MGraph &G,int v);  
  60. //得到下一个未被访问的相邻节点下标,若无,则返回-1  
  61. int nextAjdVex(const MGraph &G,int v,int w);  
  62. int *visited;   //记录顶点是否被访问  
  63.   
  64. //主函数  
  65. int main()  
  66. {  
  67.     MGraph G;  
  68.     CreatGraph(G);  
  69.     printf("\n原始连接矩阵:\n");  
  70.     printArcs(G);  
  71.     //深度优先遍历结果  
  72.     printf("\n深度优先遍历:");  
  73.     DFSTraverse(G);  
  74.     //广度优先遍历结果  
  75.     printf("\n广度优先遍历:");  
  76.     BFSTraverse(G);  
  77.     printf("\n");  
  78.          return 0;  
  79.   
  80. }  
  81.   
  82.   
  83. //初始化队列  
  84. void InitQ(LinkQueue &Q)  
  85. {  
  86.     Q.front = Q.tail = (QPtr)malloc(sizeof(struct QNode));  
  87.     if ( !Q.front )  
  88.     {  
  89.         printf("InitQ分配内存出错!\n");  
  90.         return ;  
  91.     }     
  92.     Q.front->next = NULL;  
  93. }  
  94.   
  95. //从队尾插入元素  
  96. void EnQueue(LinkQueue &Q,QElemType e)  
  97. {  
  98.     QPtr q = (QPtr)malloc(sizeof(struct QNode));  
  99.     if ( !q )  
  100.     {  
  101.         printf("EnQueue分配内存出错!\n");  
  102.         return ;  
  103.     }  
  104.     q->data = e;  
  105.     q->next = NULL;  
  106.     Q.tail->next = q;  //如果是第一次插入,Q.front->next也指向了q  
  107.     Q.tail = q;  
  108. }  
  109.   
  110. //从对首删除元素  
  111. void DeQueue(LinkQueue &Q,QElemType &e)  
  112. {  
  113.     if ( Q.front == Q.tail )  
  114.     {  
  115.         printf("DeQueue队列为空,不能删除元素!\n");  
  116.         return ;  
  117.     }  
  118.     QPtr q = Q.front->next;  
  119.     e = q->data;  
  120.     Q.front->next = q->next;  
  121.     if ( Q.tail == q )  
  122.         Q.tail = Q.front;  
  123.     free(q);  
  124. }  
  125.   
  126. //队列是否为空,为空返回1,否则返回0  
  127. int QEmpty(const LinkQueue &Q)  
  128. {  
  129.     if ( Q.front == Q.tail )  
  130.     {  
  131.         return 1;  
  132.     }  
  133.     else  
  134.     {  
  135.         return 0;  
  136.     }  
  137. }  
  138.   
  139.   
  140. //选择创建图的类型  
  141. void CreatGraph(MGraph &G)  
  142. {  
  143.     int k;  
  144.     printf("---------------------\n创建有向图,输入0;\n创建无\  
  145. 向图,输入1;\n并按下确认键.\n---------------------\n输入:");  
  146.     scanf("%d",&k);  
  147.     switch(k)  
  148.     {  
  149.     case 0:  
  150.         G.kind = DG;  
  151.         CreatDG(G);  
  152.         break;  
  153.     case 1:  
  154.         G.kind = UDG;  
  155.         CreatUDG(G);  
  156.         break;  
  157.     default:  
  158.         printf("图类型输入有误!");  
  159.         break;  
  160.     }   
  161. }  
  162.   
  163. //创建无向图  
  164. void CreatUDG(MGraph &G)  
  165. {  
  166.     int i,j,k,w;  
  167.     char v1,v2;  
  168.   
  169.     printf("输入顶点数和边数:");  
  170.     scanf("%d%d",&G.vexnum,&G.arcnum);   
  171.   
  172.     visited = (int *)malloc(G.vexnum*sizeof(int));  
  173.     for ( i = 0; i < G.vexnum; i++ )  
  174.     visited[i] = 0;  
  175.     printf("请按次序输入%d个顶点字母标号(如ABC等):",G.vexnum);  
  176.   
  177.     getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  178.      for ( i = 0; i < G.vexnum; i++ )  
  179.         scanf("%c",&G.vexs[i]);  
  180.           
  181.      getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  182.       for ( i = 0; i < G.vexnum; ++i )  
  183.     for ( j = 0; j < G.vexnum; ++j )  
  184.         {//初始化邻接矩阵  
  185.         if ( i == j )  
  186.         G.arcs[i][j] = 0;  
  187.         else  
  188.         G.arcs[i][j] = INT_MAX;  
  189.         }  
  190.       
  191.     printf("输入边的顶点和权值(如A B 1):\n");  
  192.       
  193.     for ( k = 0; k < G.arcnum; k++ )  
  194.     {  
  195.     scanf("%c %c %d",&v1,&v2,&w);  
  196.     i = LocateVex(G,v1);  
  197.          j = LocateVex(G,v2);  
  198.     G.arcs[i][j] = w;  
  199.     G.arcs[j][i] = w;  
  200.     getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  201.     }  
  202. }  
  203.   
  204. //创建有向图  
  205. void CreatDG(MGraph &G)  
  206. {//和创建无向图类似,只是少了一句将G.arcs[j][i] = w;  
  207.  //因为无向图是对称的,而有向图不是  
  208.      int i,j,k,w;  
  209.     char v1,v2;  
  210.   
  211.     printf("输入顶点数和边数:");  
  212.     scanf("%d%d",&G.vexnum,&G.arcnum);   
  213.   
  214.     visited = (int *)malloc(G.vexnum*sizeof(int));  
  215.     for ( i = 0; i < G.vexnum; i++ )  
  216.         visited[i] = 0;  
  217.     printf("请按次序输入%d个顶点字母标号(如ABC等):",G.vexnum);  
  218.   
  219.     getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  220.      for ( i = 0; i < G.vexnum; i++ )  
  221.     scanf("%c",&G.vexs[i]);  
  222.           
  223.     getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  224.      for ( i = 0; i < G.vexnum; ++i )  
  225.     for ( j = 0; j < G.vexnum; ++j )  
  226.         {//初始化邻接矩阵  
  227.         if ( i == j )  
  228.         G.arcs[i][j] = 0;  
  229.        else  
  230.         G.arcs[i][j] = INT_MAX;  
  231.         }  
  232.       
  233.     printf("输入边的顶点和权值(如A B 1):\n");  
  234.       
  235.     for ( k = 0; k < G.arcnum; k++ )  
  236.     {  
  237.     scanf("%c %c %d",&v1,&v2,&w);  
  238.     i = LocateVex(G,v1);  
  239.          j = LocateVex(G,v2);  
  240.     G.arcs[i][j] = w;  
  241.     getchar();//弹出缓冲区中上次最后出入的换行符,即最后按下的回车键  
  242.     }  
  243. }  
  244.   
  245.   
  246. //打印邻接矩阵  
  247. void printArcs(const MGraph &G)  
  248. {  
  249.     int i;  
  250.     int j;  
  251.     for ( i = 0; i < G.vexnum; i++ )  
  252.     {  
  253.         for ( j = 0; j < G.vexnum; j++ )  
  254.         {  
  255.             if ( INT_MAX == G.arcs[i][j])  
  256.             printf("%6s%","INF");  
  257.             else   
  258.             printf("%6d",G.arcs[i][j]);  
  259.         }             
  260.         printf("\n");  
  261.     }         
  262. }  
  263.   
  264. //返回字符在定点向量中的下标值  
  265. int LocateVex(const MGraph &G,VertexType ch)  
  266. {  
  267.     int i;  
  268.     for ( i = 0; G.vexnum; i++ )  
  269.         if ( ch == G.vexs[i] )  
  270.         return i;  
  271.     return -1;  
  272. }  
  273.   
  274. //深度优先遍历函数  
  275. void DFSTraverse(const MGraph &G)  
  276. {  
  277.     int i;  
  278.   
  279.     for ( i = 0; i < G.vexnum; i++ )  
  280.         visited[i] = 0;   //初始化访问标记数组  
  281.     for ( i = 0; i < G.vexnum; i++ )  
  282.         if ( !visited[i] )  
  283.         {//对尚未访问的顶点调用DFS  
  284.             DFS(G,i);  
  285.         }  
  286.         printf("\n");  
  287. }  
  288.   
  289.   
  290. void DFS(const MGraph &G,int v)  
  291. {  
  292.     int w;  
  293.     visited[v] = 1;  
  294.          printf("%-4c",G.vexs[v]);  
  295.          for ( w = firstAjdVex(G,v); w >= 0; w = nextAjdVex(G,v,w) )  
  296.         if ( !visited[w] )  
  297.         DFS(G,w);  
  298. }  
  299.   
  300. //广度优先遍历函数  
  301. void BFSTraverse(const MGraph &G)  
  302. {  
  303.     int i,w,v;  
  304.     LinkQueue Q;  
  305.     InitQ(Q);  
  306.   
  307.     for ( i = 0; i < G.vexnum; i++ )  
  308.         visited[i] = 0;   //初始化访问标记数组  
  309.   
  310.     for ( i = 0; i < G.vexnum; i++ )  
  311.     {  
  312.         if ( !visited[i] )  
  313.         {  
  314.             visited[i] = 1;  
  315.             printf("%-4c",G.vexs[i]);  
  316.             EnQueue(Q,i);  
  317.             while (!QEmpty(Q))  
  318.             {  
  319.                 DeQueue(Q,v);  
  320.                 for ( w = firstAjdVex(G,v); w >= 0; w = nextAjdVex(G,v,w) )  
  321.                 {  
  322.                     if ( !visited[w] )  
  323.                     {  
  324.                         visited[w] = 1;  
  325.                         printf("%-4c",G.vexs[w]);  
  326.                         EnQueue(Q,w);  
  327.                     }  
  328.                 }  
  329.             }  
  330.         }  
  331.   
  332.     }  
  333.       
  334. }  
  335.   
  336.   
  337. //得到第一个未被访问的相邻节点下标,若无,则返回-1  
  338. int firstAjdVex(const MGraph &G,int v)  
  339. {  
  340.     int i;  
  341.     for ( i = 0; i < G.vexnum; i++ )  
  342.     {  
  343.         if ( !visited[i] && G.arcs[v][i] > 0 && G.arcs[v][i] < INT_MAX)  
  344.             return i;  
  345.     }  
  346.     return -1;    
  347. }  
  348.   
  349. //得到下一个未被访问的相邻节点下标,若无,则返回-1  
  350. int nextAjdVex(const MGraph &G,int v,int w)  
  351. {  
  352.     int i;  
  353.     for ( i = w; i < G.vexnum; i++ )  
  354.     {  
  355.         if ( !visited[i] && G.arcs[v][i] > 0 && G.arcs[v][i] < INT_MAX)  
  356.             return i;  
  357.     }  
  358.     return -1;  
  359. }  

程序运行结果(参照上面给出的例子):


 


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值