• 无向图深度优先遍历(DFS)和广度优先遍历(BFS)算法


    定义

    深度优先遍历

    (1)从图中某个初始顶点v出发,首先访问初始顶点v。 (2)选择一个与顶点v相邻且没被访问过的顶点w,再从w出发进行深度优先搜索,直到图中与当前顶点v邻接的所有顶点都被访问过为止。   (3) 利用递归实现,简单但是不好理解,时间复杂度 O(n+e)。

    广度优先遍历

    (1)访问初始点v,接着访问v的所有未被访问过的邻接点v1,v2,…,vt。 (2)按照v1,v2,…,vt的次序,访问每一个顶点的所有未被访问过的邻接点。    (3)依次类推,直到图中所有和初始点v有路径相通的顶点都被访问过为止。
    (4) 利用队列实现, 时间复杂度 O(n+e).

    实现代码

    深度优先遍历算法

    //深度优先遍历算法
    void DFS(AdjGraph *G, int v)
    {
        ArcNode *p;
        visited[v] = 1;
        printf("%d ", v);
        p = G->adjlist[v].firstarc;
    
        while(p != NULL) //p == NULL is the break of circle
        {
            if(visited[p->adjvex] == 0)
                DFS(G, p->adjvex);
            p=p->nextarc;
        } 
    }
    

    广度优先遍历算法

    //广度优先遍历算法
    void BFS(AdjGraph *G, int v)
    {
        int w, i;
        ArcNode *p;
        SqQueue *qu;
        InitQueue(qu);
        int visited[MAXV];
    
        for(i = 0; i < G->n; i++)
            visited[i] = 0;
        
        printf("%2d",v);
        visited[v] = 1;
    
        enQueue(qu, v);
    
        while( !QueueEmpty(qu))
        {
            deQueue(qu, w);
            p = G->adjlist[w].firstarc;
    
            while(p!=NULL)
            {
                if(visited[p->adjvex] == 0)
                {
                    printf("%2d", p->adjvex);
                    visited[p->adjvex] = 1;
                    enQueue(qu, p->adjvex);
                }
                p = p->nextarc;
            }
        }
        printf("
    ");
    }
    

    注意理解

    1. 注意,DFS是基于递归形式的, 主要是往深入的方向去遍历。 每次碰到可以读取输出的顶点就直接输出,并且将其视作是头节点数组,接着向它的下一个进行读取。
    2. BFS则比较憨厚,他是直接在一个头节点数组走到黑,一直到读取NULL才肯回头。这时候,需要利用队列来保存被它错过的路口,给他提供后悔药。回头时队列出栈,出一颗后悔药给他吃,让它接着往下一个方向一直走。一直等到它把后悔药都吃完,然后就遍历结束了。
    全部代码
    #include <stdio.h>
    #include <stdlib.h>
    #include <math.h>
    #include <float.h>
    #define ElemType int
    #define maxsize 100
    #define InfoType int
    #define MAXV 100
    #define MaxSize 100
    #define INF 214748364 
    #define INFINITE INF
    /////////////////////////////////////////////////
    //邻接表的结构体定义
    typedef struct ANode
    {
        int adjvex;            //该边的邻接点的编号,即有向边指向的顶点编号
        struct ANode *nextarc; //指向下一条边的指针
        int weight;            //边的相关的信息,如权值
    } ArcNode;                 //边节点的类型
    
    typedef struct Vnode
    {
        InfoType info;     //顶点的其他信息
        int count;         //存放顶点入度
        ArcNode *firstarc; //指向第一个边节点
    } VNode;               //邻接表的头节点的结构体类型
    
    typedef struct
    {
        VNode adjlist[MAXV]; //头节点的数组
        int n, e;            //图的顶点数和边数
    } AdjGraph;              //整个邻接表的数据结构体类型
    //////////////////////////////////////////////////
    //邻接矩阵的结构体
    typedef struct S
    {
        int no;        //顶点的编号
        InfoType info; //顶点的其他信息
    } VertexType;      //顶点的类型
    
    typedef struct SS
    {
        int edges[MAXV][MAXV]; //邻接矩阵的数组
        int n, e;              //图的顶点数和边数
        VertexType vexs[MAXV]; //存放顶点信息
    } MatGraph;
    ///////////////////////////////////////////////////
    typedef struct SSS
    {
        ElemType data[maxsize];
        int front;
        int rear;
    } SqQueue; //队列的结构体
    ////////////////////////////////
    //Kruskal算法需要的简化图的结构体
    typedef struct head
    {
        int u; //边的起始顶点
        int v; //边的终止顶点
        int w; //边的权值
    } Edge;
    ///////////////////////////////
    ///零零零零啦啦啦啦啦
    int visited[MAXV] = {0};
    ///////////////////////////////
    //队列的操作函数集合
    //由于队列的函数在另一个文件
    //所以需要声明一下
    void InitQueue(SqQueue *&q);
    void DestoryQueue(SqQueue *&q);
    bool QueueEmpty(SqQueue *q);
    bool enQueue(SqQueue *&q, ElemType e);
    bool deQueue(SqQueue *&q, ElemType &e);
    /////////////////////////////////////////////////////////////////
    //后序遍历需要的一些队列的基本函数
    void InitQueue(SqQueue *&q)
    {
        q = (SqQueue *)malloc(sizeof(SqQueue));
        q->front = q->rear = 0;
    }
    
    void DestoryQueue(SqQueue *&q)
    {
        free(q);
    }
    
    bool QueueEmpty(SqQueue *q)
    {
        return (q->front == q->rear);
    }
    
    bool enQueue(SqQueue *&q, ElemType e)
    {
        if ((q->rear + 1) % maxsize == q->front)
            return false;
        q->rear = (q->rear + 1) % maxsize;
        q->data[q->rear] = e;
        return true;
    }
    
    bool deQueue(SqQueue *&q, ElemType &e)
    {
        if (q->front == q->rear)
            return false;
    
        q->front = (q->front + 1) % maxsize;
        e = q->data[q->front];
    
        return true;
    }
    /////////////////////////////////////////////
    void CreateAdj(AdjGraph *&G, int A[MAXV][MAXV], int n, int e)
    {
        int i, j;
        ArcNode *p;
        G = (AdjGraph *)malloc(sizeof(AdjGraph));
        for (i = 0; i < n; i++)
            G->adjlist[i].firstarc = NULL;
    
        for (i = 0; i < n; i++)
            for (j = n - 1; j >= 0; j--)
                if (A[i][j] != 0 && A[i][j] != INF)
                {
                    p = (ArcNode *)malloc(sizeof(ArcNode));
                    p->adjvex = j;
                    p->weight = A[i][j];
                    p->nextarc = G->adjlist[i].firstarc;
                    G->adjlist[i].firstarc = p;
                }
        G->n = n;
        G->e = e;
    }
    
    void DispAdj(AdjGraph *G) //输出邻接表G
    {
        int i;
        ArcNode *p;
        for (i = 0; i < G->n; i++)
        {
            p = G->adjlist[i].firstarc;
            printf("%3d: ", i);
            while (p != NULL)
            {
                if (p->weight != 2147483647) //2147483647
                    printf("%3d[%d]→", p->adjvex, p->weight);
                p = p->nextarc;
            }
    
            printf("^
    ");
        }
    }
    
    void DestroyAdj(AdjGraph *&G) //销毁邻接表
    {
        int i;
        ArcNode *pre, *p;
        for (i = 0; i < G->n; i++) //扫描所有的单链表
        {
            pre = G->adjlist[i].firstarc; //p指向第i个单链表的首结点
            if (pre != NULL)
            {
                p = pre->nextarc;
                while (p != NULL) //释放第i个单链表的所有边结点
                {
                    free(pre);
                    pre = p;
                    p = p->nextarc;
                }
                free(pre);
            }
        }
        free(G); //释放头结点数组
    }
    
    //////////////////////////////////////////////////////////
    //无向图邻接表的深度优先算法
    void DFS(AdjGraph *G, int v)
    {
        ArcNode *p;
        visited[v] = 1;
        printf("%d ", v);
        p = G->adjlist[v].firstarc;
    
        while(p != NULL) //p == NULL is the break of circle
        {
            if(visited[p->adjvex] == 0)
                DFS(G, p->adjvex);
            p=p->nextarc;
        } 
    }
    //////////////////////////////////////////////////////
    void BFS(AdjGraph *G, int v)
    {
        int w, i;
        ArcNode *p;
        SqQueue *qu;
        InitQueue(qu);
        int visited[MAXV];
    
        for(i = 0; i < G->n; i++)
            visited[i] = 0;
        
        printf("%2d",v);
        visited[v] = 1;
    
        enQueue(qu, v);
    
        while( !QueueEmpty(qu))
        {
            deQueue(qu, w);
            p = G->adjlist[w].firstarc;
    
            while(p!=NULL)
            {
                if(visited[p->adjvex] == 0)
                {
                    printf("%2d", p->adjvex);
                    visited[p->adjvex] = 1;
                    enQueue(qu, p->adjvex);
                }
                p = p->nextarc;
            }
        }
        printf("
    ");
    }
    
    int main ()
    {
        int a[4][MAXV] = {{0, 1, 1, 1},
                       {1, 0, 1, 1},
                       {1, 1, 0, 0},
                       {1, 1, 0, 0}};
        AdjGraph* g;
        CreateAdj(g, a, 4, 5);
    
        printf("这是原始邻接表的结构: 
    ");
        DispAdj(g);
    
        printf("
    this is the Deep fist search (from '0'):
    ");
        DFS(g, 0);
    
        printf("
    this is the Broad fist search (from '0): 
    ");
        BFS(g, 0);
    
        system("pause");
        return 0;
    
    }
    

    原始数据

    原始数据以及运行结果 在这里插入图片描述

    记得点赞哦!

    在这里插入图片描述

  • 相关阅读:
    1.Netty 实战前言
    8.Netty发送对象
    7.Netty中 handler 的执行顺序
    6.高性能NIO框架netty
    5.NIO_ Selector选择器
    4.NIO_Channel 通道
    3.NIO_Buffer缓冲区
    2.Java NIO 简介
    那些堪称神器的 Chrome 插件
    获取当前操作的IFrame 对象的方法
  • 原文地址:https://www.cnblogs.com/billyme/p/13454635.html
Copyright © 2020-2023  润新知