数据结构之图(邻接表存储,DFS和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;
				}
			}
		}
	}
}

三:数据测试



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






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值