关闭

[置顶] 图的遍历(下)——邻接表

标签: 数据结构BFSDFS邻接链表
381人阅读 评论(0) 收藏 举报
分类:

概述

在我的上一篇博客:图的遍历(上)——邻接矩阵 中主要介绍了邻接矩阵的BFS和递归的DFS与非递归的DFS这3种遍历算法。在这篇博客我将主要叙述邻接表的以上3中遍历算法。首先来看看邻接表的表示方法。

邻接表主要是针对稀疏图中邻接矩阵造成的空间浪费而提出的。下面我们来看看邻接表的表示。
1)无向图的表示
这里写图片描述
2)有向图
这里写图片描述

(说明:对于BFS,DFS的递归与非递归算法在这篇文章就不再重复,如有不了解请移步我的上一篇博客:图的遍历(上)——邻接矩阵


广度优先遍历(BFS)

//广度优先遍历(BFS)
void BFS(int vertex){
    EdgeList* cur = this->Find(vertex);     //找到当前结点    
    queue<int> queue;                   //初始化队列 
    queue.push(cur->getVertex(cur));            //当前结点入队
    while(!queue.empty()){
        int index = queue.front();      //队头元素出队
        queue.pop();
        isvisited[index] = 1;           //标记为已访问 
        cout<<index<<" ";
        cur = this->Find(index);
        while(cur){     //与当前结点相邻且未被访问的结点入队 
            index = cur->getVertex(cur);
            if(isvisited[index] == 0){
                queue.push(index);
            }
            cur = cur->getNext();   
        } 
    }
}

递归深度优先遍历(DFS)

//递归深度优先遍历(DFS)
void DFS1(int vertex){
    vector<int> node;
    //找到当前结点 
    EdgeList* cur = this->Find(vertex);
    while(cur){     //寻找当前结点的邻接点 
        node.push_back(cur->getVertex(cur));
        cur = cur->getNext();
    }
    //打印当前结点 
    cur = this->Find(node[0]);
    int index = cur->getVertex(cur);
    this->isvisited[index] = 1;
    cout<<index<<" ";
    //一次堆当前结点的邻接点进行DFS 
    for(int i = 1 ; i < node.size() ; i++){
        cur = this->Find(node[i]);
        index = cur->getVertex(cur);
        if(this->isvisited[index] == 0){
            this->isvisited[index] = 1;
            this->DFS1(index);
        }
    }
}

非递归深度优先遍历(DFS)

//非递归深度优先遍历(DFS)
void DFS2(int vertex){
    stack<int> stack;
    EdgeList* cur = this->Find(vertex);     //查找当前元素 
    int index = cur->getVertex(cur);        //当前元素的顶点 
    stack.push(index);                      //顶点入栈 
    this->isvisited[index] = 1;             //标记为已访问 
    while(!stack.empty()){          //栈不空一直循环 
        index = stack.top();        //栈顶的顶点出栈 
        stack.pop();
        cout<<index<<" ";           //打印当前顶点 
        cur = this->Find(index); 
        while(cur){         //把当前顶点的邻接点依次入栈 
            index = cur->getVertex(cur);
            if(this->isvisited[index] == 0){
                stack.push(index);
                this->isvisited[index] = 1;
            }
            cur = cur->getNext();
        }
    }
} 

例子

下面的程序所基于的图结构够如下:
这里写图片描述

#include <iostream>
#include <vector> 
#include <queue> 
#include <stack>
#include <cstring> 
using namespace std;

//边表类 
class EdgeList{
    private:
        int vertex;
        EdgeList* next;
    public:
        EdgeList* Create(int vertex){
            EdgeList* list = new EdgeList;
            list->vertex = vertex;
            list->next = NULL;
            return list;
        }

        //寻找最后一个结点
        EdgeList* getLast(EdgeList* list){
            EdgeList* cur = list;
            while(cur){
                if(cur->next == NULL){
                    return cur;
                }
                cur = cur->next;
            }
        }

        //插入函数 
        EdgeList* Attach(EdgeList* list,int vertex){
            EdgeList* last = this->getLast(list);
            EdgeList* insert = insert->Create(vertex);
            last->next = insert;
            return list;
        }

        int getVertex(EdgeList* list){
            return list->vertex;
        }

        void Print(EdgeList* list){
            EdgeList* cur = list;
            while(cur){
                cout<<cur->vertex<<" ";
                cur = cur->next;
            }
        }

        EdgeList* getNext(){
            return this->next;
        }
}; 


class Graph{
    private:
        vector<EdgeList*> Edgelist;     //邻接表 
        int* isvisited;                 //访问数组 
        int Nv;         //顶点数
        int Ne;         //边数 
    public: 
        //构造函数 
        Graph(int nv ,int ne){
            this->Ne = ne;
            this->Nv = nv;
            this->Edgelist.reserve(nv);
            this->isvisited = new int[nv+1];
            memset(this->isvisited,0,sizeof(this->isvisited[0])*(this->Nv+1));
            cout<<"请输入顶点:"<<endl;
            //依次构造图的结点 
            for(int i = 0 ; i < this->Nv ; i++){
                int vertex;
                cin>>vertex;
                this->Edgelist[i] = new EdgeList;
                this->Edgelist[i] = this->Edgelist[i]->Create(vertex);
            }
            cout<<"请输入边:"<<endl;
            //依次构造无向图的边 
            for(int i = 0 ; i < this->Ne ; i++){
                int start,end;
                cin>>start>>end;
                //找到一条边的两个顶点 
                EdgeList* s1 = this->Find(start);       
                EdgeList* s2 = this->Find(end);
                s1->Attach(s1,end);
                s2->Attach(s2,start);
            } 
        }

        //按指定结点查找
        EdgeList* Find(int vertex){
            for(int i = 0 ; i < this->Nv ; i++){
                if(this->Edgelist[i]->getVertex(this->Edgelist[i]) == vertex){
                    return this->Edgelist[i];
                }
            } 
        }

        //打印邻接表函数 
        void Print(){
            for(int i = 0 ; i < this->Nv ; i++){
                EdgeList* list = this->Edgelist[i];
                list->Print(list);
                cout<<endl;
            }
        }

        //广度优先遍历(BFS)
        void BFS(int vertex){
            EdgeList* cur = this->Find(vertex);     //找到当前结点    
            queue<int> queue;                   //初始化队列 
            queue.push(cur->getVertex(cur));            //当前结点入队
            while(!queue.empty()){
                int index = queue.front();      //队头元素出队
                queue.pop();
                isvisited[index] = 1;               //标记为已访问 
                cout<<index<<" ";
                cur = this->Find(index);
                while(cur){     //与当前结点相邻且未被访问的结点入队 
                    index = cur->getVertex(cur);
                    if(isvisited[index] == 0){
                        queue.push(index);
                    }
                    cur = cur->getNext();   
                } 
            }
        }

        //重置访问数组 
        void reset(){
            memset(this->isvisited,0,sizeof(this->isvisited[0])*(this->Nv+1));
        } 

        //递归深度优先遍历(DFS)
        void DFS1(int vertex){
            vector<int> node;
            //找到当前结点 
            EdgeList* cur = this->Find(vertex);
            while(cur){     //寻找当前结点的邻接点 
                node.push_back(cur->getVertex(cur));
                cur = cur->getNext();
            }
            //打印当前结点 
            cur = this->Find(node[0]);
            int index = cur->getVertex(cur);
            this->isvisited[index] = 1;
            cout<<index<<" ";
            //一次堆当前结点的邻接点进行DFS 
            for(int i = 1 ; i < node.size() ; i++){
                cur = this->Find(node[i]);
                index = cur->getVertex(cur);
                if(this->isvisited[index] == 0){
                    this->isvisited[index] = 1;
                    this->DFS1(index);
                }
            }
        }

        //非递归深度优先遍历(DFS)
        void DFS2(int vertex){
            stack<int> stack;
            EdgeList* cur = this->Find(vertex);     //查找当前元素 
            int index = cur->getVertex(cur);        //当前元素的顶点 
            stack.push(index);                      //顶点入栈 
            this->isvisited[index] = 1;             //标记为已访问 
            while(!stack.empty()){          //栈不空一直循环 
                index = stack.top();        //栈顶的顶点出栈 
                stack.pop();
                cout<<index<<" ";           //打印当前顶点 
                cur = this->Find(index); 
                while(cur){         //把当前顶点的邻接点依次入栈 
                    index = cur->getVertex(cur);
                    if(this->isvisited[index] == 0){
                        stack.push(index);
                        this->isvisited[index] = 1;
                    }
                    cur = cur->getNext();
                }
            }
        } 
};

int main()
{
    cout<<"请输入顶点数与边数:"<<endl;
    int nv,ne;
    cin>>nv>>ne;
    Graph graph(nv,ne);
    cout<<"邻接表为:"<<endl;
    graph.Print();


    cout<<"请输入结点:"<<endl;
    int vertex;
    cin>>vertex; 

    cout<<"广度优先遍历(BFS)序列为:"<<endl;
    graph.BFS(vertex);
    cout<<endl;

    cout<<"递归深度优先遍历(DFS)序列为:"<<endl;
    graph.reset(); 
    graph.DFS1(vertex);
    cout<<endl; 

    cout<<"非递归深度优先遍历(DFS)序列为:"<<endl;
    graph.reset(); 
    graph.DFS2(vertex);
    cout<<endl; 

    return 0;
}

截图:
这里写图片描述

1
0
查看评论

邻接表 实现图的遍历 C++

#include #include using namespace std; const int MaxSize = 5; struct ArcNode //边表节点 { int adjvex; ArcNode* next; }; template struct VertexNo...
  • A13155283231
  • A13155283231
  • 2016-11-29 22:28
  • 1211

邻接表实现图的储存,遍历

邻接表是图的一种链式存储结构。对图的每个顶点建立一个单链表(n个顶点建立n个单链表),第i个单链表中的结点包含顶点Vi的所有邻接顶点。又称链接表。 1.在有向图的邻接表中不易找到指向该顶点的弧。 2.在有向图的邻接表中,对每个顶点,链接的是以该顶点为弧尾的邻接点。
  • txl16211
  • txl16211
  • 2014-09-02 17:17
  • 1252

图的邻接表表示及其BFS遍历

图的邻接表表示及其BFS遍历有下面这张图: 假设该图为有向图,边的指向均为小序号指向大序号。那么对该图的BFS遍历如下(假设从序号0的节点开始遍历): 遍历结果应为:a b f c g i d e h BFS遍历类似于树的层序遍历,需要用到队列。下面是程序代码:1.队列定义和相关操作文件...
  • ww1473345713
  • ww1473345713
  • 2016-08-09 14:11
  • 330

图的遍历--使用邻接表作为存储结构的遍历(DFS、BFS)C语言

#include <stdbool.h> #include <stdlib.h> #include <stdio.h> #define MAX_VERTEX_NUM 20 //最大顶点个数 typedef char VertexType; typedef in...
  • haofight
  • haofight
  • 2017-01-16 20:37
  • 1400

图的邻接表储存及其遍历[数据结构学习]

好长时间没有写代码(感觉自己更弱了),今天晚上就把数据结构的链表和邻接表部分实现了(手都生了),第一次写邻接表,觉得还是邻接矩阵好很多,毕竟建表还是挺麻烦的.....顺便把bfs和dfs加了进去,刚学数据结构或者算法入门的可以看看,我是小菜,大神 求别喷......     &...
  • zhengxu001
  • zhengxu001
  • 2012-11-19 20:55
  • 3487

使用邻接表存图并遍历

我在写题目的时候基本上都是用邻接矩阵存图,因为方便,但有时候会发现邻接表过于浪费空间(关键是有时候直接开不了那么大的数组啊,欲哭无泪),所以我尝试了一下用邻接表,应该可以解决空间的问题。 对应的题目:https://pta.patest.cn/pta/test/1011/exam/4/questio...
  • Dimensions_
  • Dimensions_
  • 2016-08-05 09:38
  • 241

图的dfs递归(非递归)遍历和bfs遍历(邻接表)

1.深度优先遍历是连通图的一种遍历策略.其基本思想如下: 设x是当前被访问的顶点,在对x做过访问的标记之后,选择一条从x出发的未检测过的边(x,y),若发现顶点y已经访问过了,则重新选择另一条从x出发的未检测过的边,否则沿边(x,y)到达未曾访问过的y,对y访问并将其标记为已访问过,然后从y开始搜...
  • whoamiyang
  • whoamiyang
  • 2016-03-12 00:20
  • 894

数据结构之无向图邻接表DFS之查询遍历关节点(参考整理严蔚敏数据结构)

 #include using namespace std; #define MAXVEX 100 typedef char VType; typedef struct ArcNode {  int adjvex;  ArcNode *pNextArc; }...
  • hgeternal
  • hgeternal
  • 2014-10-27 14:49
  • 909

图邻接表类(图的遍历方法,最短距离及路径)

一:总结图的基本概念: 1.图分为有向图(入度和出度)和无向图(最大边数n(n-1)/2); 2.图的存储结构: 1)关联矩阵(表示了图的结构,即图中各结点的后件关系):表示各个结点的前件与后件关系,矩阵R(i,j)=1,表示结点i是结点j的前件,矩阵R(i,j)=0,表示结点i不是结点j的前...
  • xumin07061133
  • xumin07061133
  • 2012-10-04 12:11
  • 4783

图的遍历(邻接表)

#include #define MaxVertexNum 100 #define QueueSize 30 typedef enum{ FALSE, TRUE }Boolean; Boolean visited[MaxVertexNum]; typedef char VertexType; t...
  • GL771066709
  • GL771066709
  • 2017-05-04 21:26
  • 169
    个人资料
    • 访问:155572次
    • 积分:4928
    • 等级:
    • 排名:第6843名
    • 原创:329篇
    • 转载:0篇
    • 译文:0篇
    • 评论:80条
    博客专栏
    最新评论