图的深度优先遍历和广度优先遍历

来源:互联网 发布:重庆oppo公司知乎 编辑:程序博客网 时间:2024/06/03 13:35

图的深度优先遍历和广度优先遍历


一、邻接表法建立图

创建图的方法有邻接矩阵和邻接表法。

  • 邻接矩阵把边的关系包含在一个矩阵中,虽然很方便,但是,当图中的定点数远大于边数时,浪费了很大的空间。
  • 邻接表把边与顶点的关系存在一个叫弧(边)的数据结构中,有几条边就创建几条弧。节省了内存空间,但也怎加了对各种结构体之间关系的理解难度。
  • 其实图的DFS和BFS就算法上来看,是非常简单的,但是要很流利的写出图的这两种遍历的算法,要对结构体之间关系有较好的理解。

下面先来看数据结构:

typedef enum{DG,DN,UDG,UDN}GraphyType; //图的种类typedef struct ArcNode  //弧结点{    int adjVerxIndex;    //该弧指向的顶点在图中顶点数组的下标    struct ArcNode* nextArc;  //该弧在邻接表中的下一条弧}ArcNode;typedef struct VertexNode  //顶点{    char data;   //顶点数据    ArcNode* firstArc;   //该顶点相连的第一条弧}VertexNode;typedef struct graphy //邻接表(图){    VertexNode vertex[MAXSIZE];    int verNum,arcNum;    GraphyType type;//图的种类,若要简单可以舍去这一项}*AdjList;

再来看如何创建图:

int Locate(AdjList adj , char des) //通过顶点数据找到顶点下标{    for(int i = 0; i< adj->verNum; ++i)    {        if(des == adj->vertex[i].data)        {            return i;        }    }    return -1;}void CreatAdjList(AdjList* adj)//创建图{    *adj = (AdjList)malloc(sizeof(graphy));    cout<<"请输入顶点数:"<<endl;    cin>>(*adj)->verNum;    cout<<"请输入边数:"<<endl;      cin>>(*adj)->arcNum;    (*adj)->type = DN;    int i = 0;    cout<<"请依次输入顶点的值:"<<endl;    for(i = 0; i < (*adj)->verNum; ++i)    {           cin>>(*adj)->vertex[i].data;        (*adj)->vertex[i].firstArc = NULL;    }    for(i = 0; i < (*adj)->arcNum; ++i)    {        char start,end;        int ixS,ixE;        cout<<"请输入第"<<i<<"条边的两个顶点值:"<<endl;        cin>>start>>end;        ixS = Locate(*adj,start);        ixE = Locate(*adj,end);        ArcNode* node = (ArcNode*)malloc(sizeof(ArcNode));        node->nextArc = (*adj)->vertex[ixS].firstArc;        node->adjVerxIndex = ixE;        (*adj)->vertex[ixS].firstArc = node;//头插法    }}

没什么难以理解的,就是把图结构体中的变量初始化,唯一要注意的是,在创建边的时候,采用头插还是尾插的方法对最后遍历结果有一定影响,实际上先遍历哪一个邻接点都没有关系,所以图的两种遍历结果其实都是不唯一的,只要某些关键点的前后顺序一致就行了。


二、图的深度优先遍历(DFS)

算法分析

图的深度优先遍历其实就是通常说的回溯,一般用递归实现,做法是依次对每个未访问的结点做DFS。

DFS:访问该顶点,然后在一个循环中分别对每一个邻接点做DFS,直到所有邻接点都已做完DFS返回,可见DFS使用了递归。

代码:

void Dfs(AdjList adj, int i){    if(flag[i])    {        return;    }    cout<<adj->vertex[i].data<<"  ";    flag[i] = true;    ArcNode* p = adj->vertex[i].firstArc;     while(p)    {            Dfs(adj,p->adjVerxIndex);            p = p->nextArc;    }}

三、图的广度优先遍历(BFS)

算法分析

  1. 图的广度优先遍历一般用队列来实现,和深度优先遍历一样,依次对图中每一个未访问的顶点做BFS.
  2. BFS:访问一个节点之前,现将这个顶点入队,然后在访问,访问完毕之后,将他的所有邻接点入队。然后判断队列是否为空,若为空则表示访问完毕,退出循环,可见BFS未用递归。

代码:

void Bfs(AdjList adj,int i){    q.push(i);      while(!q.empty())    {                       if(!flag[q.front()])        {            cout<<adj->vertex[q.front()].data<<"  ";            flag[q.front()] = true;             }        ArcNode* p = adj->vertex[q.front()].firstArc;        q.pop();        while(p)        {        q.push(p->adjVerxIndex);        p = p->nextArc;        }    } } 

四、整体实现及测试结果

  1. 画图分析:
    图

  2. 整体代码:

#include<iostream>#include<malloc.h>#include<queue>#include<string.h>#define MAXSIZE 20using namespace std;typedef enum{DG,DN,UDG,UDN}GraphyType;bool flag[MAXSIZE] = {false}; queue<int> q;typedef struct ArcNode{    int adjVerxIndex;    struct ArcNode* nextArc;}ArcNode;typedef struct VertexNode{    char data;    ArcNode* firstArc;}VertexNode;typedef struct graphy{    VertexNode vertex[MAXSIZE];    int verNum,arcNum;    GraphyType type;}*AdjList;void Dfs(AdjList adj, int i);void Bfs(AdjList adj,int i);int Locate(AdjList adj , char des){    for(int i = 0; i< adj->verNum; ++i)    {        if(des == adj->vertex[i].data)        {            return i;        }    }    return -1;}void CreatAdjList(AdjList* adj){    *adj = (AdjList)malloc(sizeof(graphy));    cout<<"请输入顶点数:"<<endl;    cin>>(*adj)->verNum;    cout<<"请输入边数:"<<endl;      cin>>(*adj)->arcNum;    (*adj)->type = DN;    int i = 0;    cout<<"请依次输入顶点的值:"<<endl;    for(i = 0; i < (*adj)->verNum; ++i)    {           cin>>(*adj)->vertex[i].data;        (*adj)->vertex[i].firstArc = NULL;    }    for(i = 0; i < (*adj)->arcNum; ++i)    {        char start,end;        int ixS,ixE;        cout<<"请输入第"<<i<<"条边的两个顶点值:"<<endl;        cin>>start>>end;        ixS = Locate(*adj,start);        ixE = Locate(*adj,end);        ArcNode* node = (ArcNode*)malloc(sizeof(ArcNode));        node->nextArc = (*adj)->vertex[ixS].firstArc;        node->adjVerxIndex = ixE;        (*adj)->vertex[ixS].firstArc = node;    }}void Print(AdjList adj){    for(int i = 0; i < adj->verNum; ++i)    {        if(flag[i])        {            continue;        }        cout<<"DFS:"<<endl;         Dfs(adj,i);    }    memset(flag,0,MAXSIZE);    for(int i = 0; i < adj->verNum; ++i)    {        if(flag[i])        {            continue;        }        cout<<endl<<"BFS:"<<endl;         Bfs(adj,i);    }}void Dfs(AdjList adj, int i){    if(flag[i])    {        return;    }    cout<<adj->vertex[i].data<<"  ";    flag[i] = true;    ArcNode* p = adj->vertex[i].firstArc;     while(p)    {            Dfs(adj,p->adjVerxIndex);            p = p->nextArc;    }}void Bfs(AdjList adj,int i){    q.push(i);      while(!q.empty())    {                       if(!flag[q.front()])        {            cout<<adj->vertex[q.front()].data<<"  ";            flag[q.front()] = true;             }        ArcNode* p = adj->vertex[q.front()].firstArc;        q.pop();        while(p)        {        q.push(p->adjVerxIndex);        p = p->nextArc;        }    } } int main(){    AdjList adj;    CreatAdjList(&adj);    Print(adj);    return 0;} 

3.结果:
结果