2021-07-02

查找函数(LocateVex查找坐标)
构建无向图(Undirected Graph)
输出邻接矩阵(print)
深度优先查找函数(DFS)
深度优先遍历(DFSTraverse)
图的遍历
深度优先遍历(DFS):类似于树中的先序遍历,整体思想是:先输出当前结点,在根据一定的次序去递归查找孩子。
广度优先遍历(BFS):类似于树中的层次遍历,需要用队列来体现结点访问的次序关系。

图的遍历需要考虑的问题
图是一种多对多的关系,每一个顶点有若干个度,结点之间也有若干条回路,每一个连通图都有若干种路径,那么我们怎么知道结点是否已经被访问过?
设置 "标志"数组 visited,数组每一位都对应一个结点的访问状态,0代表未被访问,1代表已访问。并且visited数组要设置成全局变量!
连通图与非连通图的问题
如果是连通图,根据程序递归,以任意一个端点为起点都可以走完整个图

  • 如果是连通图,根据程序递归,以任意一个端点为起点都可以走完整个图
    在这里插入图片描述
  • 如果是非连通图,存在“落单”的端点,“孤岛”端点,既无法一次走完整个图,此时就需要多次调用遍历函数来保证每一个结点都被访问到。
    在这里插入图片描述
  • 回到算法设计上而言,也就是解释了为什么会出现DFS、DFSTraverse两个函数,其实,如果是连通图由DFS函数就可以完成对整个图的遍历,DFSTraverse里面的for(i=0;i<G->vexnum;i++)(邻接矩阵第134-139行,邻接表第150-155行)就是为了非连通图而准备的。
    由水流的例子,我们还可以知道:

  • 在这里插入图片描述

    深度优先遍历基本步骤
    设置全局变量visited数组并初始化为全0,代表所有节点均未被访问
    根据端点存放顺序:
    2.1 选取初始端点:对初始端点进行访问,并在visited数值中标记成已访问状态(代码演示的初始端点是G->Vertex[i],此时i=0)
    2.2 由初始端点开始对后续端点进行处理
    (步骤2为深度优先搜索)
    循环对所有节点都执行步骤2,前提是该节点未被访问!(对应函数DFSTraverse,主要用于非连通图能访问到每一个结点)
    (步骤3 循环执行深度优先搜索,就是深度优先遍历)

    完整源代码:
    注:图的遍历算法在任何图与网中都适用,此处仅用无向图UDG进行演示!
    注:邻接矩阵和邻接表对同一个图的深度优先遍历顺序是不一样的!因为此处邻接表的边关系是由头插法的形式插入,若采用尾插法则遍历序列与邻接矩阵一致
    1.邻接矩阵的深度优先遍历
    #include <stdio.h>
    #include <stdlib.h>
    #define VertexMax 100 //最大顶点数为100

    typedef char VertexType; //每个顶点数据类型为字符型 

    typedef struct
    {
        VertexType Vertex[VertexMax];//存放顶点元素的一维数组 
        int AdjMatrix[VertexMax][VertexMax];//邻接矩阵二维数组 
        int vexnum,arcnum;//图的顶点数和边数  
    }MGraph;

    int LocateVex(MGraph *G,VertexType v)//查找元素v在一维数组 Vertex[] 中的下标,并返回下标 
    {
        int i;
        
        for(i=0;i<G->vexnum;i++)
        {
            if(v==G->Vertex[i])
            {
                return i; 
            } 
         } 
         
         printf("No Such Vertex!\n");
         return -1;
    }

    //无向图
    void CreateUDG(MGraph *G) 
    {
        int i,j;

        printf("输入顶点个数和边数:\n");
        printf("顶点数 n="); 
        scanf("%d",&G->vexnum);
        printf("边  数 e="); 
        scanf("%d",&G->arcnum);
        printf("\n"); 
        
        printf("\n");
        

        printf("输入顶点元素(无需空格隔开):");
        scanf("%s",G->Vertex);
        printf("\n");

        for(i=0;i<G->vexnum;i++) 
         for(j=0;j<G->vexnum;j++)
            {
                G->AdjMatrix[i][j]=0;
            }
        

         int n,m;
         VertexType v1,v2;
         
         printf("请输入边的信息:\n");
         for(i=0;i<G->arcnum;i++)
         {
             scanf(" %c%c",&v1,&v2);
             n=LocateVex(G,v1); 
             m=LocateVex(G,v2); 
             
             if(n==-1||m==-1)
             {
                 printf("NO This Vertex!\n");
                 return;
              } 
        
           G->AdjMatrix[n][m]=1;
           G->AdjMatrix[m][n]=1;
         } 
         
    }

    void print(MGraph G)
    {
        int i,j;
        printf("\n-------------------------------");
        printf("\n 邻接矩阵:\n\n");     

            printf("\t ");
            for(i=0;i<G.vexnum;i++)
            printf("  %c",G.Vertex[i]);
            printf("\n");
             
            for(i=0;i<G.vexnum;i++)
           {
                 printf("\t%c",G.Vertex[i]);
               
              for(j=0;j<G.vexnum;j++)
            {
                 printf("  %d",G.AdjMatrix[i][j]);
            }
                printf("\n");
           }
    }

    /*深度优先遍历DFS*/ 
    int visited[VertexMax];//定义"标志"数组为全局变量 

    void DFS(MGraph *G,int i)
    {
        int j;
        
        //1.处理起始点 
        printf("%c",G->Vertex[i]);//1.输出起始结点 
        visited[i]=1;//2.将已访问的结点标志成1
        
         //2.由起始点开始,对后续结点进行操作
        for(j=0;j<G->vexnum;j++)//依次搜索vi的邻接点 
        {
            if(G->AdjMatrix[i][j]==1&&visited[j]==0)//当满足有边且未被访问过时,递归调用去查找该邻接点 
            {
                DFS(G,j);//注意此处的G已经是指针类型,不需要再&G 
            }
        }
        
    }

    void DFSTraverse(MGraph *G) 
    {
        int i;
        
        //初始化"标志"数组为0,代表未访问
        for(i=0;i<G->vexnum;i++)
        {
            visited[i]=0; 
        } 
        
        for(i=0;i<G->vexnum;i++)
        {
            if(visited[i]==0)
            {
                DFS(G,i);//注意此处的G已经是指着类型,不需要再&G 
            }
        } 
        
    }

    int main() 
    {
        MGraph G;
        CreateUDG(&G);
        print(G); 

        printf("\n\n深度优先遍历:"); 
        DFSTraverse(&G); 
         
        return 0;
    }    

  • 2.邻接表的深度优先遍历:
    #include <stdio.h>
    #include <stdlib.h>
    #define VertexType char //顶点的数据类型(char) 
    #define VertexMax 20 //最大顶点个数 

    typedef struct ArcNode//边表 
    {
        int adjvex;//存储的是该顶点在顶点数组即AdjList[]中的位置 
        struct ArcNode *next;
    }ArcNode;

    typedef struct VNode //顶单个点 
    {
        VertexType vertex;
        struct ArcNode *firstarc;
    }VNode;

    typedef struct //顶点表 
    {
        VNode AdjList[VertexMax];//由顶点构成的结构体数组 
        int vexnum,arcnum; //顶点数和边数 
    }ALGraph;

    int LocateVex(ALGraph *G,VertexType v)
    {    
        int i;
        for(i=0;i<G->vexnum;i++)
        {
            if(v==G->AdjList[i].vertex)
            {
                return i;
            }
        }
        
        printf("No Such Vertex!\n");
        return -1;
    }

    //2.无向图 
    void CreateUDG(ALGraph *G)
    {
        int i,j;
        //1.输入顶点数和边数
        printf("输入顶点个数和边数:\n");
        printf("顶点数 n="); 
        scanf("%d",&G->vexnum);
        printf("边  数 e="); 
        scanf("%d",&G->arcnum);
        printf("\n"); 
        
        printf("\n");
        //2.顶点表数据域填值初始化顶点表指针域
        printf("输入顶点元素(无需空格隔开):");
        for(i=0;i<G->vexnum;i++)
        {
            scanf(" %c",&G->AdjList[i].vertex);
            G->AdjList[i].firstarc=NULL;
        } 
        printf("\n");
        
        //3.输入边信息构造邻接表
        int n,m;
        VertexType v1,v2;
        ArcNode *p1,*p2; 
        
        printf("请输入边的信息:\n\n"); 
        for(i=0;i<G->arcnum;i++)
        {   //输入边信息,并确定v1和v2在G中的位置,即顶点在AdjList[]数组中的位置(下标) 
            printf("输入第%d条边信息:",i+1); 
            scanf(" %c%c",&v1,&v2);
            n=LocateVex(G,v1);
            m=LocateVex(G,v2);
            
            if(n==-1||m==-1)
             {
                 printf("NO This Vertex!\n");
                 return;
              } 
            
            p1=(ArcNode *)malloc(sizeof(ArcNode));
            p1->adjvex=m;//填上坐标 
            p1->next=G->AdjList[n].firstarc;//改链(头插法) 
            G->AdjList[n].firstarc=p1;
            
            p2=(ArcNode *)malloc(sizeof(ArcNode));//无向图的对称 
            p2->adjvex=n;
            p2->next=G->AdjList[m].firstarc;
            G->AdjList[m].firstarc=p2;
            
        }//for 

    void print(ALGraph G)
    {
        int i;
        ArcNode *p;
        printf("\n-------------------------------");
        printf("\n图的邻接表表示:\n");
        
        for(i=0;i<G.vexnum;i++)
        {
            printf("\n   AdjList[%d]%4c",i,G.AdjList[i].vertex);
            p=G.AdjList[i].firstarc;
            
            while(p!=NULL)
            {
                printf("-->%d",p->adjvex);
                p=p->next;
            }
         } 
         printf("\n");

    /*深度优先遍历*/
    int visited[VertexMax]; //定义数组为全局变量 

    void DFS(ALGraph *G,int i)
    {
        int j;
        struct ArcNode *p;
        int w;
        
        printf("%c",G->AdjList[i].vertex);//1.访问当前节点 
        visited[i]=1;//2.将当前节点标记成已访问结点
        
        p=G->AdjList[i].firstarc;
        while(p!=NULL)
        {
            w=p->adjvex;//w是邻接点的坐标 
            if(visited[w]==0)
            {
                DFS(G,w);
            }
               p=p->next;//查找完之后,将p向后推一位 
        }
         

    void DFSTraverse(ALGraph *G)
    {
        int i;
        
        //初始化"标志"数组
        for(i=0;i<G->vexnum;i++)
        {
            visited[i]=0;
        } 
        
        for(i=0;i<G->vexnum;i++)
        {
            if(visited[i]==0)
            {
                DFS(G,i);
            }
        }
    }

    int main()
    {
         ALGraph G;
         CreateUDG(&G);
        print(G);
         
        printf("\n\n深度优先遍历:"); 
        DFSTraverse(&G);  
         
        return 0;
    }
     

  • 在这里插入图片描述

    ————————————————
    版权声明:本文为CSDN博主「Attract1206」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/Attract1206/article/details/106546534
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值