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

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

     

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

      邻接表是一种链式存储。就如上图,一共有四个顶点(分别是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()
{

/*

8
9

A B C D E F G H

0 1
0 2
1 3
1 4
2 5
2 6
3 7
4 7
5 6

*/

ALGraph graph;

//1.创建邻接表
CreateGraph(graph);

//2.打印邻接表
cout << "\n邻接表打印为: \n";
PrintGraph(graph);

//3.深度优先搜索DFS
cout << "\n深度优先搜索DFS: ";
DFSTraverse(graph);
cout << endl;

//4.广度优先搜索BFS
cout << "\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;
}
}
}
}
}


三:数据测试

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


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

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