图的深度优先遍历与广度优先遍历及其复杂度分析

这里放一下关于图的遍历

废话少说直接上~~
首先是图的结构类型:

typedef struct ANode{
    int  adjvex;            //编号
    struct ANode *nextarc;  //链接指针
    Elemtype weight;        //权值
}ArcNode;

typedef struct VNode{
    Elemtype data;          //头结点数据
    ArcNode *firstarc;      //指向第一个边结点
};

typedef struct{
    VNode adjlist[MAX];
    int n;int e;
}ArcGraph;

图的创建(邻接链表):

void CreateAdj(ArcGraph *&G,int A[MAXV][MAXV],int n,int e){
    ArcNode *p;
    G=new ArcGraph;//为G申请储存空间
    for(int i=0;i<n;i++)//置空
        G->adjlist[i].firstarc=NULL;
    for(int i=0;i<n;i++)
        for(int j=n-1;j>=0;j--)
            if(A[i][j]!=0&&A[i][j]!=MAX)//如果邻接矩阵存在边
            {
                p = new 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;
}

po出两种算法

  • 深度遍历算法(递归)

递归深度遍历分这么几步
首先初始化访问数组=0
然后先将访问数组的访问顶点=1
接着该顶点的邻接点w
最后就开始循环递归的
while(w存在)
{
if(w未被访问)
递归
w转到下一个邻接点
}

int visitedDPS[MAX]={0};//全局标记数组
void DFS(ArcGraph *G,int v){
    ArcNode *p;
    visitedDPS[v]=1;//访问标记
    cout<<v<<" ";//输出访问编号
    p=G->adjlist[v].firstarc;//指向第一个顶点
    while (p!=NULL)
    {
        if(visitedDPS[p->adjvex]==0)//如果访问标记为0
            DFS(G,p->adjvex);//递归调用
        p=p->nextarc;//指向下一个结点
    }
}
  • 广度优先遍历

首先还是初始化访问数组=0
然后访问顶点=1
将访问顶点的序号v加入队列queue
最后还是循环
while(queue为非空)
{
v=队列的头元素
w=v的第一个邻接点
while(w非空)
if(w的访问数组标记=0)
访问数组=1
w加入队列queue
w=顶点v的下一个邻接点

int visitedBFS[MAX]={0};//全局标记数组

void BFS(ArcGraph *G,int v){
   ArcNode *p;
   queue<int>que;//初始化队列
   //int visited[MAX];
   for(int i=0;i<G->n;i++)visitedBFS[i]=0;//初始化标记数组
   cout<<v<<" ";//编号
   visitedBFS[v]=1;//访问标记
   que.push(v);//进队操作
   while (!que.empty())
   {
       /*
        在标记顶点序号的时候本以为p->adjvex就可以了  但是debug出现了segfault(原因尚未知)
        但是考虑到出顶点的时候利用队列的front函数得到那个序号就可以了!!
        */
       int w=que.front();//这里真的是踩了一个大坑了!!!!
       que.pop();//顶点w点出队
       p = G->adjlist[w].firstarc;//指向w的第一个邻接点
       while (p != NULL) {
           if (visitedBFS[p->adjvex] == 0)//如果邻接点未被访问,访问该节点
           {
               cout << p->adjvex<< " " ;
               visitedBFS[p->adjvex] = 1;
               que.push(p->adjvex);//顶点进队
           }
           p = p->nextarc;//寻找下一个邻接点
       }
   }
}

这里主函数的调用

int main(){
    int A[5][5]={{ 0 , 8 ,MAX, 5 ,MAX},
                 {MAX, 0 , 3 ,MAX,MAX},
                 {MAX,MAX, 0 ,MAX, 6 },
                 {MAX,MAX, 9 , 0 ,MAX},
                 {MAX,MAX,MAX,MAX, 0 }};
    ArcGraph *G;
    int n=5,e=5;
    CreateAdj(G,A,n,e);
    cout<<"This is adjacency list which your created."<<endl;
    DispAdj(G);
    cout<<endl<<"This is Depth First Search."<<endl;
    DFS(G,0);
    cout<<endl<<"This is Breadth First Search."<<endl;
    BFS(G,0);
    return 0;
}

在深度优先遍历中使用了递归的方法,该算法的时间复杂度为O(n²),广度优先遍历中使用了标记数组的方法,该算法的时间复杂度为O(n+e),其中e为图中边的个数.对于空间复杂度来说,两者的储存类型都是一样的,所以空间复杂度是相同的.综合对比两个遍历算法,各有优点,而且遍历所得的结果不同,在实际使用的时候要考虑问题的实现方法来综合考量两种算法.

发布了2 篇原创文章 · 获赞 1 · 访问量 6561
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览