数据结构之图(邻接表存储,DFS和BFS遍历)

来源:互联网 发布:top gear 知乎 编辑:程序博客网 时间:2024/06/05 05:05

     来看下面的一个简单的图,


     

      那么这样的一个图,我们应该用什么存储结构来存储它呢?常用的是邻接矩阵和邻接表,这里邻接矩阵不做讲解,如下所有代码都是以邻接表作为存储结构,所以这里就只讲解下邻接表。那么什么是邻接表呢?如何构造呢?

      邻接表是一种链式存储。就如上图,一共有四个顶点(分别是A,B,C,D),邻接表就是为这四个顶点的每个顶点建立一条单链表,也就是四条单链表,每个链表第一个元素就是该顶点自己。下面就以上面的图为例,具体介绍如何建立邻接表。

       首先看第一条单链表,表头是顶点A。因为顶点A只与顶点B有邻接,因此,该单链表大概描述为A---->B;

       再看第二条单链表,表头是B,而B与A,C,D都有邻接,故而描述为B----->A------->C------->D;

       依次第三条单链表为C------>B----->D;

       最后第四条单链表为D------>B----->C。

       现在来理清一下下面代码的三个结构体都代表什么,理清的话,下面的代码就很容易理解了。

struct ArcNode{int adjvex;               //该弧所指向的顶点的位置ArcNode * next;           //指向下一条弧的指针                          //int weight;边上是否有权};typedef struct VNode{char vertex;              //顶点信息ArcNode * firstarc;       //指向第一条依附该顶点的弧的指针 }AdjList[20];struct ALGraph{AdjList adjList;int vexNum;               //图的顶点数int arcNum;               //图的弧数};

        看第二个结构体VNode,上面已经说过,对于ABCD四个顶点每个建立一条单链表,那么这四条链表该如何管理呢?对的,用数组,这也就是AdjList[20]的由来(这里假设一个图的顶点不超过20个,读者可以根据自己需求改动)。

         第一个结构体ArcNode就是建立链表所必需的节点。

         那么最后一个结构体ALGraph就是用来表示一个图,在一段程序里,你要做三个图,就要用这个结构体去申请三个变量,来存储你的三个图。

         好了,接下来直接看代码吧。所有源码都已经在下面贴出,没有遗漏。以下代码创建的图是无向,无权图,并且使用邻接表表示图。部分代码参考严蔚敏的数据结构。

一:main部分

#include<iostream>#include<queue>using namespace std;struct ArcNode{int adjvex;               //该弧所指向的顶点的位置ArcNode * next;           //指向下一条弧的指针                          //int weight;边上是否有权};typedef struct VNode{char vertex;              //顶点信息ArcNode * firstarc;       //指向第一条依附该顶点的弧的指针 }AdjList[20];struct ALGraph{AdjList adjList;int vexNum;               //图的顶点数int arcNum;               //图的弧数};bool visited[20];//设置标志数组void CreateGraph(ALGraph & graph);void PrintGraph(ALGraph & graph);void DFSTraverse(ALGraph & graph);void BFSTraverse(ALGraph & graph);int main(){/*89A B C D E F G H0 10 21 31 42 52 63 74 75 6*/ALGraph graph;//1.创建邻接表CreateGraph(graph);//2.打印邻接表cout << "\n邻接表打印为: \n";PrintGraph(graph);//3.深度优先搜索DFScout << "\n深度优先搜索DFS: ";DFSTraverse(graph);cout << endl;//4.广度优先搜索BFScout << "\n广度优先搜索BFS: ";BFSTraverse(graph);cout << endl<<endl;return 0;}

二:具体实现

1.构造邻接表

void CreateGraph(ALGraph & graph){////////1.输入顶点数和弧数cout << "请输入图的顶点数: ";cin >> graph.vexNum;cout << "请输入图的弧数: ";cin >> graph.arcNum;///////2.输入顶点信息cout << "请输入" << graph.vexNum << "个顶点信息: ";for (int i = 0; i < graph.vexNum; i++){cin >> graph.adjList[i].vertex;graph.adjList[i].firstarc = nullptr;}///////3.根据输入的弧的信息构造邻接表cout << "请输入" << graph.arcNum << "个弧的信息: \n";int h1, h2;ArcNode * temp;for (int i = 0; i < graph.arcNum; i++){cin >> h1 >> h2;temp = new ArcNode;temp->adjvex = h2;temp->next = graph.adjList[h1].firstarc;graph.adjList[h1].firstarc = temp;temp = new ArcNode;temp->adjvex = h1;temp->next = graph.adjList[h2].firstarc;graph.adjList[h2].firstarc = temp;}}

2.打印邻接表

void PrintGraph(ALGraph & graph){for (int i = 0; i < graph.vexNum; i++){cout << graph.adjList[i].vertex << "------>";ArcNode * p = graph.adjList[i].firstarc;while (p){cout << graph.adjList[p->adjvex].vertex << "  ";p = p->next;}cout << endl;}}

3.深度优先搜索DFS。类似于树的先序遍历。假设图中所有顶点未被访问,则深度优先遍历是从某个顶点v开始,访问完后,接着访问v的未被访问的邻接点,直至遍历完。

void DFS(ALGraph & graph, int v){visited[v] = true;cout << graph.adjList[v].vertex << " ";ArcNode * p = graph.adjList[v].firstarc;while (p){if (!visited[p->adjvex])DFS(graph, p->adjvex);p = p->next;}}void DFSTraverse(ALGraph & graph){for (int i = 0; i < graph.vexNum; i++)//初始化访问标志数组visited[i] = false;for (int i = 0; i < graph.vexNum; i++){if (!visited[i])//如果没有访问DFS(graph, i);}}

4.广度优先搜索BFS。类似于树的层次遍历。假设图中所有顶点未被访问,则广度优先遍历是从某个顶点v开始,访问后,接着访问v的未被访问的邻接点,然后分别从这些邻接点开始依次访问它们的邻接点(因此用到了队列),直至遍历完。

void BFSTraverse(ALGraph & graph){for (int i = 0; i < graph.vexNum; i++)//初始化访问标志数组 visited[i] = false;queue<int> q;for (int i = 0; i < graph.vexNum; i++){if (!visited[i])//如果没有访问过{visited[i] = true;q.push(i);//访问过的入队列cout << graph.adjList[i].vertex << " ";while (!q.empty())//队列不为空时{int x = q.front();q.pop();//先取出队首第一个元素,然后将第一个元素删除ArcNode * p = graph.adjList[x].firstarc;while (p)//访问未被访问过的邻接顶点{if (!visited[p->adjvex]){visited[p->adjvex] = true;cout << graph.adjList[p->adjvex].vertex << " ";q.push(p->adjvex);}p = p->next;}}}}}

三:数据测试



其中上述数据创建的图的结构如下图:






1 1