zoukankan      html  css  js  c++  java
  • 图->遍历

    文字描述

      从图中某一顶点出发遍历图中其余顶点,且使每一个顶点仅被访问一次,这一过程就叫图的遍历。

      深度优先搜索:类似树的先根遍历;假设初始状态下,图中所有顶点都未曾被访问,则从某个顶点出发,访问此顶点,然后依次从v的未被访问的邻接点出发继续深度优先遍历图,直到图中所有和v有路径相通的顶点都被访问到;若此时图中尚有顶点未被访问,则另选一个未曾被访问的顶点作起始点。

      广度优先搜索:类似数的层次遍历;以v为起始点,由近及远,依次访问和v有路径相通且路径长度为1,2,…的顶点。

    示意图

    算法分析

      深度优先搜索:遍历图的过程实质上是对每个顶点找其邻接点的过程。其耗费的时间取决于所采用的存储结构。当用二维数组表示邻接矩阵作图的存储结构时,查找每个顶点的邻接点所需时间为n*n, 其中n为图中顶点数。而当以邻接表作图的存储结构时,找邻接点所需时间为e,其中e为无向图中的边数或有向图中弧的数。由此,当以邻接表作存储结构时,深度优先搜索遍历图的时间复杂度为n+e。

      广度优先搜索:其时间复杂度和深度优先遍历相同,两者不同之处在于对顶点的访问顺序不同。

    代码实现

      1 /*
      2     1.以邻接表作为图的存储结构创建图。
      3     2.用深度优先搜索的方法对图中结点进行遍历
      4     3.用广度优先搜索的方法对图中结点进行遍历
      5 */
      6 
      7 #include <stdio.h>
      8 #include <stdlib.h>
      9 #include <string.h>
     10 
     11 #define INFINITY        100000    //最大值
     12 #define    MAX_VERTEX_NUM    20        //最大顶点数
     13 #define None        -1
     14 typedef enum {DG, DN, UDG, UDN} GraphKind; //{有向图,有向网,无向图,无向网}
     15 typedef char VertexType;
     16 typedef struct{
     17     char note[10];
     18 }InfoType;
     19 //与顶点相连的弧结点
     20 typedef struct ArcNode{
     21     int adjvex;    //该弧所指向的顶点的位置
     22     struct ArcNode *nextarc;    //指向下一条弧的指针
     23     InfoType *info;    //该弧相关信息的指针
     24 }ArcNode;
     25 //顶点结点
     26 typedef struct VNode{
     27     VertexType data;//顶点信息
     28     ArcNode *firstarc;//指向第一条依附该顶点的弧的指针
     29 }VNode, AdjList[MAX_VERTEX_NUM];
     30 //图结点
     31 typedef struct{
     32     AdjList vertices;
     33     int vexnum;//图的顶点数
     34     int arcnum;//图的弧数
     35     int kind; //图的种类标志
     36 }ALGraph;
     37 
     38 /*
     39     若G中存在顶点u,则返回该顶点在图中位置;否则返回-1。
     40 */
     41 int LocateVex(ALGraph G, VertexType v)
     42 {
     43     int i = 0;
     44     for(i=0; i<G.vexnum; i++){
     45         if(G.vertices[i].data == v){
     46             return i;
     47         }
     48     }
     49     return -1;
     50 }
     51 
     52 /*
     53     在链表L的头部前插入v
     54 */
     55 int InsFirst(ArcNode *L, int v)
     56 {
     57     ArcNode *n = (ArcNode *)malloc(sizeof(struct ArcNode));
     58     n->adjvex = v;
     59     n->nextarc = L->nextarc;
     60     L->nextarc = n;    
     61     return 0;
     62 }
     63 
     64 /*
     65     采用邻接表的存储结构,构造无向图
     66  */
     67 int CreateUDG(ALGraph *G)
     68 {
     69     int i = 0, j = 0, k = 0, IncInfo = 0;
     70     int v1 = 0, v2 = 0;
     71     char tmp[10] = {0};
     72     
     73     printf("输入顶点数,弧数,其他信息标志位: ");
     74     scanf("%d,%d,%d", &G->vexnum, &G->arcnum, &IncInfo);
     75 
     76     for(i=0; i<G->vexnum; i++){
     77         printf("输入第%d个顶点: ", i+1);
     78         memset(tmp, 0, sizeof(tmp));
     79         scanf("%s", tmp);
     80         G->vertices[i].data = tmp[0];
     81         G->vertices[i].firstarc = malloc(sizeof(struct ArcNode));
     82         G->vertices[i].firstarc->adjvex = None;
     83         G->vertices[i].firstarc->nextarc = NULL;
     84     }
     85 
     86     for(k=0; k<G->arcnum; k++){
     87         printf("输入第%d条弧(顶点1, 顶点2): ", k+1);
     88         memset(tmp, 0, sizeof(tmp));
     89         scanf("%s", tmp);
     90         sscanf(tmp, "%c,%c", &v1, &v2);
     91         i = LocateVex(*G, v1);
     92         j = LocateVex(*G, v2);
     93         InsFirst(G->vertices[i].firstarc, j);
     94         InsFirst(G->vertices[j].firstarc, i);
     95         if(IncInfo){
     96             //other info on arc
     97         }
     98     }
     99     return 0;
    100 }
    101 
    102 /*
    103     采用邻接表的存储结构,构造图
    104 */
    105 int CreateGraph(ALGraph *G)
    106 {
    107     printf("输入图类型: -有向图(0), -有向网(1), +无向图(2), -无向网(3): ");
    108     scanf("%d", &G->kind);
    109     switch(G->kind){
    110         case DG:
    111         case DN:
    112         case UDN:
    113             printf("还不支持!
    ");
    114             return -1;
    115         case UDG:
    116             return CreateUDG(G);
    117         default:
    118             return -1;
    119     }
    120 }
    121 
    122 /*
    123     输出图的信息
    124 */
    125 void printG(ALGraph G)
    126 {
    127     if(G.kind == DG){
    128         printf("类型:有向图;顶点数 %d, 弧数 %d
    ", G.vexnum, G.arcnum);
    129     }else if(G.kind == DN){
    130         printf("类型:有向网;顶点数 %d, 弧数 %d
    ", G.vexnum, G.arcnum);
    131     }else if(G.kind == UDG){
    132         printf("类型:无向图;顶点数 %d, 弧数 %d
    ", G.vexnum, G.arcnum);
    133     }else if(G.kind == UDN){
    134         printf("类型:无向网;顶点数 %d, 弧数 %d
    ", G.vexnum, G.arcnum);
    135     }
    136     int i = 0;
    137     ArcNode *p = NULL;
    138     for(i=0; i<G.vexnum; i++){
    139         printf("%c	", G.vertices[i].data);
    140         p = G.vertices[i].firstarc;
    141         while(p){
    142             if(p->adjvex != None)
    143                 printf("%d	", p->adjvex);
    144             p = p->nextarc;
    145         }
    146         printf("
    ");
    147     }
    148     return;
    149 }
    150 
    151 
    152 //////////////////////////////////////////////////////////////////////
    153 //////////////////////////////////////////////////////////////////////
    154 //////////////////////////////////////////////////////////////////////
    155 //////////////////////////////////////////////////////////////////////
    156 //开始用深度优先搜索的方法对图中结点进行遍历
    157 int Visited[MAX_VERTEX_NUM] = {0};//访问标志数组
    158 void (*VisitFun)(ALGraph G, int v);//函数变量
    159 
    160 //打印顶点中位置v的顶点信息
    161 void printfun(ALGraph G, int v){
    162     printf("[%d]:%c	", v, G.vertices[v].data);
    163 }
    164 
    165 //返回图G中与顶点位置为v的顶点相连的第一个结点在顶点中的位置
    166 int FirstAdjVex(ALGraph G, int v)
    167 {
    168     return G.vertices[v].firstarc->nextarc->adjvex;
    169 }
    170 
    171 //返回图G中与顶点位置为v的顶点相连的结点w的下一个结点在顶点中的位置
    172 int NextAdjVex(ALGraph G, int v, int w)
    173 {
    174     ArcNode *arc = G.vertices[v].firstarc;
    175     while(arc && arc->adjvex != w){
    176         arc = arc->nextarc;
    177     }
    178     if(arc && arc->nextarc){
    179         return arc->nextarc->adjvex;
    180     }    
    181     return -1;
    182 }
    183 
    184 //从第v个顶点出发递归地深度优先遍历图G
    185 void DFS(ALGraph G, int v){
    186     //访问第v个顶点
    187     Visited[v] = 1;
    188     VisitFun(G, v);
    189     int w = 0;
    190     for(w=FirstAdjVex(G,v); w>=0; w=NextAdjVex(G,v,w)){
    191         //对v的尚未访问的邻接顶点w递归调用DFS
    192         if(!Visited[w]){
    193             DFS(G,w);
    194         }
    195     }
    196 }
    197 
    198 //对图G作深度优先遍历
    199 void DFSTraverse(ALGraph G, void (*Visit)(ALGraph G, int v))
    200 {
    201     printf("深度优先搜索: ");
    202     //使用全局变量VisitFun, 是DFS不必设函数指针参数
    203     VisitFun = Visit;
    204     int v = 0;
    205     //访问标志数组初始化
    206     for(v=0; v<G.vexnum; v++){
    207         Visited[v] = 0;
    208     }
    209     for(v=0; v<G.vexnum; v++){
    210         //对尚未访问的顶点调用DFS
    211         if(!Visited[v])
    212             DFS(G, v);
    213     }
    214 }
    215 
    216 
    217 //////////////////////////////////////////////////////////////////////
    218 //////////////////////////////////////////////////////////////////////
    219 //////////////////////////////////////////////////////////////////////
    220 //////////////////////////////////////////////////////////////////////
    221 //开始用广度优先搜索的方法对图中结点进行遍历
    222 typedef struct QNode{
    223     int data;
    224     struct QNode *next;
    225 }QNode, *QuenePtr;
    226 
    227 typedef struct{
    228     QuenePtr front;
    229     QuenePtr rear;
    230 }LinkQueue;
    231 LinkQueue *InitQueue(void){
    232     LinkQueue *Q = (LinkQueue*)malloc(sizeof(LinkQueue));
    233     Q->front = Q->rear = (QuenePtr)malloc(sizeof(QNode));
    234     Q->front->next = Q->rear->next = NULL;
    235     return Q;
    236 }
    237 int QueueEmpty(LinkQueue *Q){
    238     if(Q->front == Q->rear){
    239         return 0;
    240     }else{
    241         return -1;
    242     }
    243 }
    244 int EnQueue(LinkQueue *Q, int e){
    245     QuenePtr p = (QuenePtr)malloc(sizeof(QNode));
    246     p->data = e;
    247     p->next = NULL;
    248     Q->rear->next = p;
    249     Q->rear = p;
    250     return 0;
    251 }
    252 
    253 int DeQueue(LinkQueue *Q, int *e)
    254 {
    255     if(Q->rear == Q->front){
    256         return -1;
    257     }
    258     QuenePtr p = Q->front->next;
    259     *e = p->data;
    260     Q->front->next = p->next;
    261     if(p == Q->rear){
    262         Q->rear = Q->front;
    263     }
    264     free(p);
    265     return 0;
    266 }
    267 
    268 void PrintQ(LinkQueue *Q)
    269 {
    270     QuenePtr head = Q->front;
    271     while(head){
    272         printf("%d	", head->data);
    273         head = head->next;
    274     }
    275     printf("
    ");
    276 }
    277 
    278 /*广度优先搜索
    279  *按广度优先非递归遍历图G。使用辅助队列Q和访问标志数组Visited
    280  */
    281 void BFSTraverse(ALGraph G, void (*Visit)(ALGraph G, int v))
    282 {
    283     printf("广度优先搜索: ");
    284     int v = 0;
    285     int u = 0;
    286     int w = 0;
    287     //访问标志数组初始化
    288     for(v=0; v<G.vexnum; v++){
    289         Visited[v] = 0;
    290     }    
    291     //置空的辅助队列Q
    292     LinkQueue *Q = InitQueue();
    293     for(v=0; v<G.vexnum; v++){
    294         if(!Visited[v]){
    295             //v尚未访问
    296             Visited[v] = 1;
    297             //访问v顶点
    298             Visit(G, v);
    299             //v入队列
    300             EnQueue(Q, v);
    301             
    302             while(QueueEmpty(Q)){
    303                 //队头元素出队并置为u
    304                 DeQueue(Q, &u);
    305                 for(w=FirstAdjVex(G, u); w>=0; w=NextAdjVex(G, u, w)){
    306                     if(!Visited[w]){
    307                         //w为u的尚未访问的邻接顶点
    308                         Visited[w] = 1;
    309                         Visit(G, w);
    310                         EnQueue(Q, w);
    311                     }
    312                 }
    313             }
    314         }
    315     }
    316 }
    317 
    318 int main(int argc, char *argv[])
    319 {
    320     ALGraph G;
    321     if(CreateGraph(&G) > -1){
    322         printG(G);
    323     }
    324     DFSTraverse(G, printfun);printf("
    ");
    325     BFSTraverse(G, printfun);printf("
    ");
    326     return 0;
    327 }
    图深度优先遍历和广度优先遍历

    代码运行

  • 相关阅读:
    根据时间段查询数据并按照降序排列
    Json数组(以[ ] 中括号开头)字符串转为json对象
    Java 后台请求第三方系统接口详解
    Map 集合 和 String 字符串相互转换工具类
    并发工具类——CountDownLatch、CyclicBarrier、Semaphore与Exchanger
    AQS相关
    Atomic原子类
    CAS相关
    synchronized关键字相关
    谈谈对volatile关键字的理解
  • 原文地址:https://www.cnblogs.com/aimmiao/p/9768169.html
Copyright © 2011-2022 走看看