图的遍历

473 阅读6分钟
  • 深度优先遍历

    • 实现思路

      1. 将图的顶点和边信息输⼊到图结构中;
      2. 创建⼀个visited 数组,⽤来标识顶点是否已经被遍历过
      3. 初始化visited 数组,将数组中元素置为0
      4. 选择顶点开始遍历.(注意⾮连通图的情况)
      5. 进⼊递归; 打印i 对应的顶点信息. 并将该顶点标识为已遍历.
      6. 循环遍历边表,判断当前edges[i][j]区间是否是(0,65536),并且当前该顶点没有被遍历过,则继续递归 DFS;

      用通俗一点的话来表述实现思路,其实就是遍历整个图的关系表,发现存在没有访问过的关系顶点是就打印关系顶点然后将该顶点设置成已访问过,然后到这个顶点对应的关系表中继续冲0循环重复上述的步骤,如果是连通图的话只要冲0或者指定位置开始上述流程就行,但是如果是非连通图,就需要循环遍历所有顶点重复上述流程.

    • 实现代码

    #include <stdio.h>
    #include "stdlib.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    #define MAXVEX 100 /* 最大顶点数,应由用户定义 */
    #define INFINITYC 65535
    
    typedef int Status;    /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    typedef char VertexType; /* 顶点类型应由用户定义  */
    typedef int EdgeType; /* 边上的权值类型应由用户定义 */
    
    typedef struct {
        VertexType * vers;  //用来存储顶点信息的数据
        EdgeType **edges;   //用来储存b顶点之间的关系的二维数组
        int numNodes,numEdges;  //顶点的数量和边的数量
    } Graph;
    
    Status initGraph(int numNodes,int numEdges,Graph *G){
        G->numEdges = numEdges;
        G->numNodes = numNodes;
        G->vers = (VertexType *)malloc(sizeof(VertexType) * numNodes);
        if(G->vers == NULL) return ERROR;
        //初始化一个长为边的数量宽也是边的数量的二维数组
        G->edges = (EdgeType **)malloc(sizeof(EdgeType *) * numEdges);
        if(G->edges == NULL) return ERROR;
        for(int i = 0; i < numEdges; i ++){
            G->edges[i] = (EdgeType *)malloc(sizeof(EdgeType) * numEdges);
            if(G->edges[i] == NULL) return ERROR;
        }
        //循环遍历
        //这里有个小细节就是 没有关系的时候我们设置为无穷大,有关系的时候对应位置可以储存权值
        //初始化的时候默认每个顶点都没有对应关系
        for(int i = 0; i < G->numNodes; i ++)
            for(int n = 0; n < G->numNodes; n ++)
                G->edges[i][n] = INFINITYC;
        return OK;
    }
    
    void CreateGraph(Graph *G){
    
        int i,j,k,w,numNodes,numEdges;
        printf("输入顶点数和边数:\n");
        //1. 输入顶点数/边数
        scanf("%d,%d",&numNodes,&numEdges);
        getchar();
        //初始化
        initGraph(numNodes, numEdges, G);
        printf("顶点数:%d,边数:%d\n",G->numNodes,G->numEdges);
        //输入顶点的信息
        for(i = 0; i <= G->numNodes; i ++){
            scanf("%c",&G->vers[i]);
        }
        //4.输入边表信息
        for(k = 0; k < G->numEdges;k++){
            printf("输入边(vi,vj)上的下标i,下标j,权w\n");
            scanf("%d,%d,%d",&i,&j,&w);
            
            G->edges[i][j] = w;
            //如果无向图,矩阵对称;
            G->edges[j][i] = G->edges[i][j];
            
        }
        
        
        /*5.打印邻接矩阵*/
        for (int i = 0; i < G->numNodes; i++) {
            printf("\n");
            for (int j = 0; j < G->numNodes; j++) {
                printf("%d ",G->edges[i][j]);
            }
        }
        printf("\n");
        
        
    }
    
    int *visited;
    
    void DFS(Graph G,int index){
        visited[index] = 1;
        printf("%c",G.vers[index]);
        
        for(int i = 0; i < G.numNodes; i ++){
            if(G.edges[index][i] > 0 && G.edges[index][i] < INFINITYC && visited[i] == 0){
                DFS(G, i);
            }
        }
    }
    
    void DepthTraversal(Graph G){
        visited = (int *)calloc(G.numNodes, sizeof(int));
        
        //加一层循环为了防止非连通图的遍历
        for(int i = 0; i < G.numNodes; i ++){
            if(visited[i] == 0){
                DFS(G,i);
            }
        }
    }
    
    
    
    int main(int argc, const char * argv[]) {
        // insert code here...
        printf("Hello, World!\n");
        Graph G;
        CreateGraph(&G);
        printf("\n");
        DepthTraversal(G);
        return 0;
    }
    
    
  • 广度优先遍历

    • 实现思路

      1. 同样的需要创建一个visited数组用来记录顶点的访问记录
      2. 遍历所有顶点,先判断顶点是否访问过,如果没有则入队,然后再写一个循环,出队,然后再将所有与该结点有关系的顶点并且没有访问过的顶点入队,知道队列为空跳出循环,这样就把一个结点中与他有关系并且没有访问的顶点全部访问了一遍,直到外层循环全部循环完毕则遍历完成
        这里用到了队列的思想
    • 实现代码

    #include <stdio.h>
    #include "stdlib.h"
    
    #define OK 1
    #define ERROR 0
    #define TRUE 1
    #define FALSE 0
    #define MAXVEX 100 /* 最大顶点数,应由用户定义 */
    #define INFINITYC 65535
    
    typedef int Status;    /* Status是函数的类型,其值是函数结果状态代码,如OK等 */
    
    typedef int ElemType;
    typedef struct QueueNode{
        ElemType data;
        struct QueueNode * next;
    }QueueNode,*QueueNodePtr;
    
    typedef struct Queue{
        QueueNodePtr front;
        QueueNodePtr rear;
    }Queue;
    
    
    
    //初始化
    Status initQueue(Queue *q){
        q->front = q->rear = (QueueNodePtr)malloc(sizeof(QueueNode));
        if(q->front == NULL) exit(0);
        q->front->next = NULL;
        return OK;
    }
    
    //判空
    Status queueIsEmpty(Queue q){
        if(q.front == NULL) exit(0);
        if(q.front == q.rear) return TRUE;
        return FALSE;
    }
    
    //遍历
    Status traverseQueue(Queue q){
        if(q.front == NULL) exit(0);
        QueueNodePtr qPtr = q.front->next;
        for(;qPtr != NULL; qPtr = qPtr->next)
            printf("%d ",qPtr->data);
        printf("\n");
        return OK;
    }
    
    //入队
    Status enqueue(Queue *q,ElemType data){
        if(q->front == NULL) exit(0);
        QueueNodePtr ptr = (QueueNodePtr)malloc(sizeof(QueueNode));
        ptr->data = data;
        ptr->next = q->front->next;
        q->front->next = ptr;
        if(q->front == q->rear){
            q->rear = ptr;
        }
        return OK;
    }
    
    //出队
    Status dequeue(Queue *q){
        if(q->front == NULL) exit(0);
        if(queueIsEmpty(*q)) return ERROR;
        QueueNodePtr temp = q->rear;
        QueueNodePtr target = q->front;
        while (target->next != temp) {
            target = target->next;
        }
        target->next = NULL;
        q->rear = target;
        free(temp);
        return OK;
    }
    
    
    typedef char VertexType; /* 顶点类型应由用户定义  */
    typedef int EdgeType; /* 边上的权值类型应由用户定义 */
    
    typedef struct {
        VertexType * vers;  //用来存储顶点信息的数据
        EdgeType **edges;   //用来储存b顶点之间的关系的二维数组
        int numNodes,numEdges;  //顶点的数量和边的数量
    } Graph;
    
    Status initGraph(int numNodes,int numEdges,Graph *G){
        G->numEdges = numEdges;
        G->numNodes = numNodes;
        G->vers = (VertexType *)malloc(sizeof(VertexType) * numNodes);
        if(G->vers == NULL) return ERROR;
        //初始化一个长为边的数量宽也是边的数量的二维数组
        G->edges = (EdgeType **)malloc(sizeof(EdgeType *) * numEdges);
        if(G->edges == NULL) return ERROR;
        for(int i = 0; i < numEdges; i ++){
            G->edges[i] = (EdgeType *)malloc(sizeof(EdgeType) * numEdges);
            if(G->edges[i] == NULL) return ERROR;
        }
        //循环遍历
        //这里有个小细节就是 没有关系的时候我们设置为无穷大,有关系的时候对应位置可以储存权值
        //初始化的时候默认每个顶点都没有对应关系
        for(int i = 0; i < G->numNodes; i ++)
            for(int n = 0; n < G->numNodes; n ++)
                G->edges[i][n] = INFINITYC;
        return OK;
    }
    
    void CreateGraph(Graph *G){
    
        int i,j,k,w,numNodes,numEdges;
        printf("输入顶点数和边数:\n");
        //1. 输入顶点数/边数
        scanf("%d,%d",&numNodes,&numEdges);
        getchar();
        //初始化
        initGraph(numNodes, numEdges, G);
        printf("顶点数:%d,边数:%d\n",G->numNodes,G->numEdges);
        //输入顶点的信息
        for(i = 0; i <= G->numNodes; i ++){
            scanf("%c",&G->vers[i]);
        }
        //4.输入边表信息
        for(k = 0; k < G->numEdges;k++){
            printf("输入边(vi,vj)上的下标i,下标j,权w\n");
            scanf("%d,%d,%d",&i,&j,&w);
            
            G->edges[i][j] = w;
            //如果无向图,矩阵对称;
            G->edges[j][i] = G->edges[i][j];
            
        }
        
        
        /*5.打印邻接矩阵*/
        for (int i = 0; i < G->numNodes; i++) {
            printf("\n");
            for (int j = 0; j < G->numNodes; j++) {
                printf("%d ",G->edges[i][j]);
            }
        }
        printf("\n");
        
        
    }
    
    int *visited;
    
    void BFSTraverse(Graph G){
        Queue Q;
        initQueue(&Q);
        
        visited = (int *)calloc(G.numNodes, sizeof(int));
        
        for(int i = 0; i < G.numNodes; i ++){
            if(visited[i] == 0){
                visited[i] = 1;
                printf("%c",G.vers[i]);
                //没有访问过
                enqueue(&Q, i);
                
                while (!queueIsEmpty(Q)) {
                    dequeue(&Q);
                    for(int j = 0; j < G.numNodes; j ++){
                        if(G.edges[i][j] > 0 && G.edges[i][j] < INFINITYC && visited[j] == 0){
                            visited[j] = 1;
                            printf("%c",G.vers[j]);
                            enqueue(&Q, j);
                        }
                    }
                }
                
            }
        }
    }