图的深度与广度优先遍历(DFS & BFS)(C/C++)

先介绍一下两种图的结构

邻接矩阵:

由一个一维数组存储图中的顶点,由一个二维数组表示元素之间的关系,用行和列以及其中的值表示两个顶点之间是否有边(弧),如第2行第3列的值为1,则表示第2个元素与第3个元素之间存在边。

typedef struct AMGraph
{
    int vex[ARRAYSIZE]={0};
    int arc[ARRAYSIZE][ARRAYSIZE];
    int vexnum=0,arcnum=0;//顶点个数、弧个数
    int type=0;//1表示无向图,2表示有向图,3表示无向网,4表示有向网
}AMGraph;
邻接表:

由一个结构体表示图结构,内部有一个顶点数组,存储图的顶点;还有一个表示图类型的成员和一个记录顶点数量的成员。
其中顶点数组的每一个结点也都是一个结构体,有两个成员,一个存储该顶点的值;另一个是一条单链表,表示与该顶点连接的边(弧)。
单链表的每一个结点也都是一个结构体,有三个成员,一个存储另一个顶点的下标(单链表所在的结构体,是一个顶点,而这条单链表的每一个结点都是与这个顶点相连的弧,所以该弧则需要记录其所连接的另一个顶点是谁);还有两个成员分别是用来连接顶点的next指针和存储权值的变量。

//定义弧结点
typedef struct ArcNode
{
    int adjvex=-1;//另一个顶点的下标
    struct ArcNode *next=nullptr;
    int weight=0;//权值
}ArcNode;
//定义顶点结点
typedef struct VexNode
{
    int data=0;//顶点数据
    ArcNode *AList=nullptr;//单链表头指针
}VexNode;
//定义邻接表
typedef struct ALGraph
{
    VexNode vex[ARRAYSIZE];//顶点数组
    int vexnum=0;//顶点数
    int type=0;//图的种类:1表示无向图,2表示有向图,3表示无向网,4表示有向网
}ALGraph;
图的遍历:

图的遍历是从某一顶点出发访遍图中其余顶点,且每个顶点只能被访问一次。
为了避免同一个顶点重复访问,在遍历的过程中,必须记下每个已访问过的顶点。为此可以设置一个辅助数组,其下标对应着顶点数组的下标,当数组元素值为假时,代表该顶点还未被访问,值为真则代表已访问。

深度优先遍历:

图的深度优先遍历类似树的先根遍历。假设初始状态是图中所有顶点未曾访问,此时从某一顶点v出发,访问此顶点,然后以此访问该顶点的所有邻接顶点,直到与v相连的顶点都被访问了一次;若此时图中还有顶点未访问,则再次重复上述过程,直到图中所有顶点都被访问到为止。
领接矩阵实现:

bool visited[ARRAYSIZE];//标志数组:true代表该顶点已访问,false代表该顶点未访问。
void DFS(AMGraph &G,int v)
{
    cout << G.vex[v] << endl;
    visited[v]=true;//标记已访问
    for(int i=0;i<G.vexnum;i++)//寻找下标为v的顶点的邻接顶点
    {
        if(G.arc[v][i]!=0 && G.arc[v][i]!=INT_MAX)
            if(visited[i]==false) DFS(G,i);//如果该邻接顶点尚未访问,对其调用DFS
    }
    //判断是否有向
    if(G.type==2 || G.type==4)
    {
        for(int i=0;i<G.vexnum;i++)
        {
            if(G.arc[i][v]!=0 && G.arc[v][i]!=INT_MAX)
               if(visited[i]==false) DFS(G,i);
        }
    }
}
void DFSTraverse(AMGraph &G)
{
    //初始化标志数组
    for(int i=0;i<G.vexnum;i++) visited[i]=false;
    //因为图中可能存在互不相连的子图,所以需要迭代判断每一个顶点是否已访问
    for(int i=0;i<G.vexnum;i++)
        if(visited[i]==false)
            DFS(G,i);//对尚未访问到的结点调用DFS
}

邻接表实现:

bool visited[ARRAYSIZE];//标志数组
void DFS(ALGraph &G,int v)
{
    cout << G.vex[v].data << endl;
    visited[v]=true;
    //访问该顶点的邻接顶点
    ArcNode *p=G.vex[v].AList;
    while(p!=nullptr)
    {
        if(visited[p->adjvex]==false)
            DFS(G,p->adjvex);
        p=p->next;
    }
    //若是有向图,搜索入度的邻接顶点
    if(G.type==2 || G.type==4)
        for(int i=0;i<G.vexnum;i++)
        {
            if(i==v) continue;
            p=G.vex[i].AList;
            while(p!=nullptr)
            {
                if(p->adjvex==v)
                {
                    if(visited[i]==false)
                        DFS(G,i);
                    break;
                }
                p=p->next;
            }
        }
}
void DFSTraverse(ALGraph &G)
{
    //初始化标志数组
    for(int i=0;i<G.vexnum;i++) visited[i]=false;
    //检测每一个顶点是否已访问
    for(int i=0;i<G.vexnum;i++)
        if(visited[i]==false) DFS(G,i);
}
广度优先遍历:

广度优先遍历类似树的层序遍历。先从图中某一点v出发,访问v,然后依次访问与v相连的顶点,接着再依次访问这些顶点的邻接顶点,以此类推,直到图中的顶点都被访问到为止。
和图的深度优先遍历一样,需要借助辅助数组记录顶点是否已访问;和树的层次遍历一样,需要借助队列结构,访问一个顶点并加入队列,顶点出队时将与之相连的顶点也加入队列。

领接矩阵实现:

void BFSTraverse(AMGraph &G)
{
    queue<int> Q;//辅助队列
    int pos=-1;//用于获取队头元素
    //初始化标志数组
    for(int i=0;i<G.vexnum;i++) visited[i]=false;
    
    for(int i=0;i<G.vexnum;i++)
    {
        if(visited[i]==false)
        {
            cout << G.vex[i] << endl;
            visited[i]=true;//标记已访问
            Q.push(i);//顶点下标入队
            while(!Q.empty())
            {
                pos=Q.front();
                //访问队头顶点的邻接顶点
                for(int j=0;j<G.vexnum;j++)
                    if(G.arc[pos][j]!=0 && G.arc[pos][j]!=INT_MAX)
                    {
                        if(visited[j]==false)
                        {
                            cout << G.vex[j] << endl;
                            visited[j]=true;
                            Q.push(j);
                        }
                    }
                //判断是否有向
                if(G.type==2 || G.type==4)
                {
                    for(int j=0;j<G.vexnum;j++)
                        if(G.arc[j][pos]!=0 && G.arc[j][pos]!=INT_MAX)
                           if(visited[j]==false)
                           {
                               cout << G.vex[j] << endl;
                               visited[j]=true;
                               Q.push(j);
                           }
                }
                //队头出队
                Q.pop();
            }//while
        }//if
    }//for
}

邻接表实现:

void BFSTraverse(ALGraph &G)
{
    queue<int> Q;//辅助队列
    int pos=-1;//负责获取队头
    ArcNode *p=nullptr;//搜索单链表的指针
    //初始化标记数组
    for(int i=0;i<G.vexnum;i++) visited[i]=false;
    //检测每一个顶点是否已访问
    for(int i=0;i<G.vexnum;i++)
        if(visited[i]==false)
        {
            cout << G.vex[i].data << endl;
            visited[i]=true;//标记已访问
            Q.push(i);//入队
            while(!Q.empty())
            {
                pos=Q.front();
                //访问队头的邻接顶点
                p=G.vex[pos].AList;
                while(p!=nullptr)
                {
                    if(visited[p->adjvex]==false)
                    {
                        cout << G.vex[p->adjvex].data << endl;
                        visited[p->adjvex]=true;
                        Q.push(p->adjvex);
                    }
                    p=p->next;
                }
                if(G.type==2 || G.type==4)
                for(int j=0;j<G.vexnum;j++)
                {
                    if(j==pos) continue;
                    p=G.vex[j].AList;
                    while(p!=nullptr)
                    {
                        if(p->adjvex==pos)
                        {
                            if(visited[j]==false)
                            {
                                cout << G.vex[j].data << endl;
                                visited[j]=true;
                                Q.push(j);
                            }
                            break;
                        }
                        p=p->next;
                    }
                }
                //队头出队
                Q.pop();
            }//while
        }//if
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值