无向图深度优先遍历(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("\n");
}

注意理解

  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("^\n");
    }
}

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("\n");
}

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("这是原始邻接表的结构: \n");
    DispAdj(g);

    printf("\nthis is the Deep fist search (from '0'):\n");
    DFS(g, 0);

    printf("\nthis is the Broad fist search (from '0): \n");
    BFS(g, 0);

    system("pause");
    return 0;

}

原始数据

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

记得点赞哦!

在这里插入图片描述

posted @ 2020-08-07 18:41    阅读(1947)  评论(0编辑  收藏  举报