数据结构----图的遍历方法总结
提示:写出用邻接矩阵和邻接表做图的存储结构,并分别实施广度优先遍历和深度优先遍历。
文章目录
一、邻接矩阵和邻接表做图的存储结构
1.邻接矩阵
邻接矩阵的存储结构表示如下:
用矩阵表示上图为:
用代码将图表示为邻接矩阵为:
vexnum,arcnum,arc[MAXSIZE][MAXSIZE];//从左到右分别表示图的顶点数,弧数以及邻接矩阵
//初始化邻接矩阵
for(i=0;i<vexnum;i++){
for(j=0;j<vexnum;j++){
arcs[i][j]=0;
}
}
p1,p2; //表示一条弧的起始点与终止点
//无向图
for(int i=0;i<arcnum;i++){
cin>>p1>>p2;
arcs[p1][p2]=1;
arcs[p2][p1]=1;
}
//有向图
for(int i=0;i<arcnum;i++){
cin>>p1>>p2;
arcs[p1][p2]=1;
}
2.邻接表
邻接表的存储结构表示如下:
用代码将图表示为邻接表
//弧的存储结构
struct ArcNode {
int adjvex; //该边所指向的顶点的位置
ArcNode* nextarc; //指向下一条边的指针
};
//顶点的存储结构
struct VNode {
char data;
ArcNode* firstarc;
};
VNode vex[MAXSIZE]; //存放顶点的数组
int vexnum,arcnum; //当前的顶点数与弧数
bool visited[MAXSIZE]; //记录已访问过的结点
int start,end; //表示弧的起始位置与终止位置
//无向图的邻接表创建方法
for(int i=0;i<arcnum;i++){
ArcNode *p1=(ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex=end;
p1->nextarc=vex[start].firstarc;
v[start].firstarc=p1->nextsarc;//用头插法连接
ArcNode *p2=(ArcNode*)malloc(sizeof(ArcNode));
p2->adjvex=start;
p2->nextarc=v[end].firstarc;
v[end].firstarc=p2;
}
//有向图的邻接矩阵创建方法,有向图与无向图的区别是有向图只需要连接一条边,而无向图需要连接两条边
for(int i=0;i<arcnum;i++){
ArcNode *p1=(ArcNode *)malloc(sizeof(ArcNode));
p1->adjvex=end;
p1->nextarc=vex[start].firstarc;
v[start].firstarc=p1->nextsarc;//用头插法连接
}
二、使用邻接矩阵和邻接表实施的广度优先与深度优先遍历
1.利用邻接矩阵实现的广度优先与深度优先遍历
广度优先遍历
思路:广度顾名思义就是大范围地进行搜索,从图的某一结点出发,首先依次访问该结点的所有邻接点vi1,vi2,…,vin,再按这些顶点被访问的先后次序依次访问与它们相邻接的所有未被访问的顶点。重复此过程,直至所有顶点均被访问为止。
代码如下:
void AMGraph::BFS(int v) {
queue<int> res;
res.push(v);
while (!res.empty()) {
int q = res.front();
res.pop();
cout << q << " ";
visited[q] = true;
for (int w = 0; w < vexnum; w++) {
if (arcs[q][w] && visited[w] != true) {
res.push(w);
}
}
}
}
深度优先遍历
/利用邻接矩阵实现的深度优先
void AMGraph::DFS(int v) {
cout << v << " ";
//v表示图遍历的起点
visited[v] = true;
for (int w = 0; w < vexnum; w++) {
if (arcs[v][w] && visited[w] != true) {
DFS(w);
}
}
}
2.利用邻接表实现的广度优先与深度优先遍历
广度优先遍历与深度优先遍历的思路都和用矩阵表示的存储结构类似,不过是换了一种存储结构
广度优先遍历
void ALGraph::BFS(char start) {
queue<int>ret;
int tag; //用于记录起始点的下标
for (int i = 0; i < vexnum; i++) {
if (v[i].data == start) {
tag = i;
break;
}
}
ret.push(tag);
visited[tag] = true;
while (!ret.empty()) {
int p = ret.front();
ret.pop();
cout << v[p].data << " ";
ArcNode* arc = (ArcNode*)malloc(sizeof(ArcNode));
arc = v[p].firstarc;
while (arc != NULL ) {
if (visited[arc->adjvex] != true) {
ret.push(arc->adjvex);
visited[arc->adjvex] = true;
}
arc = arc->nextarc;
}
}
}
深度优先遍历
void ALGraph::DFS(char start) {
int tag;
for (int i = 0; i < vexnum; i++) {
if (v[i].data == start) {
tag=i;
break;
}
}
visited[tag] = true;
cout << v[tag].data << " ";
ArcNode* arc = (ArcNode*)malloc(sizeof(ArcNode));
arc = v[tag].firstarc;
while (arc != NULL ) {
if (visited[arc->adjvex] != true) {
DFS(v[arc->adjvex].data);
}
arc = arc->nextarc;
}
}
三.图的遍历的例题以及全部代码
测试样例:
AMGraph.h(邻接矩阵)
#include<iostream>
#include<queue>
#define MaxSize 100
using namespace std;
class AMGraph {
public:
void Matrix(); //将输入的数据转换为邻接矩阵
void DFS(int v); //图的邻接矩阵深度遍历
void BFS(int v); //图的邻接矩阵的广度优先遍历
private:
int vexnum; //矩阵的行
int arcs[MaxSize][MaxSize]; //矩阵的规模
bool visited[MaxSize]; //记录已访问的结点
char ch[MaxSize]; //用于存放节点的数据
};
void AMGraph::Matrix() {
char P1,P2;
int M, N;
int select;
cout << "分别输入图中结点的个数以及图中弧的条数" << endl;
cin >> M >> N;
cout << "请确定该图是有向图还是无向图(1.有向图 0.无向图)" << endl;
cin>> select;
cout << "请输入结点的数据" << endl;
for (int i = 0; i < M; i++){
cin>>ch[i];
}
vexnum = M;
//cout << "vexnum="<<vexnum << endl;
//初始化矩阵
for (int i = 0; i < vexnum; i++) {
for (int j = 0; j < vexnum; j++) {
arcs[i][j] = 0;
}
}
cout << "请分别输入弧的起始点与终止点" << endl;
for (int i = 0; i < N; i++) {
cin >> P1 >> P2;
if (select == 0) {
arcs[P1 - 'A'][P2 - 'A'] = 1;
arcs[P2 - 'A'][P1 - 'A'] = 1;
//cout << P1 - '65' << endl;
}
if (select == 1) {
arcs[P1 - 'A'][P2 - 'A'] = 1;
}
}
}
//利用邻接矩阵实现的深度优先
void AMGraph::DFS(int v) {
cout << ch[v] << " ";
//v表示图遍历的起点
visited[v] = true;
for (int w = 0; w < vexnum; w++) {
if (arcs[v][w] && visited[w] != true) {
DFS(w);
}
}
}
//利用邻接矩阵实现的广度优先
void AMGraph::BFS(int v) {
queue<int> res;
res.push(v);
while (!res.empty()) {
int q = res.front();
res.pop();
cout << ch[q] << " ";
visited[q] = true;
for (int w = 0; w < vexnum; w++) {
if (arcs[q][w] && visited[w] != true) {
res.push(w);
}
}
}
}
AdjList.h(邻接表)
#include<iostream>
#include<queue>
#define MAXSIZE 100
using namespace std;
//弧的结点结构
struct ArcNode {
int adjvex; //该边所指向的顶点的位置
ArcNode* nextarc; //指向下一条边的指针
};
//顶点的存储结构
struct VNode {
char data;
ArcNode* firstarc;
};
//图的结构定义以及操作
class ALGraph {
private:
VNode v[MAXSIZE];
int vexnum, arcnum; //图的当前顶点数和弧数
bool visited[MAXSIZE]; //记录已访问过的结点
public:
void CreateUDG();
int LocateVex(char ch);
void BFS(char v); //利用邻接表实现的广度优先
void DFS(char v); //利用邻接表实现的深度优先
};
void ALGraph::CreateUDG(){
ArcNode* p1,*p2;
int select;
char P1, P2;
cout << "请输入图的顶点数与弧数";
cin >>vexnum >>arcnum;
char ch[MAXSIZE];
cout << "请确定该图是有向图还是无向图(1.有向图 0.无向图)" << endl;
cin >> select;
cout << "请输图的顶点的数据" << endl;
for (int i = 0; i <vexnum; i++) {
cin >> ch[i];
}
for (int j = 0; j < vexnum; j++) {
v[j].data = ch[j];
v[j].firstarc = NULL;
}
cout << "请分别输入弧的起始点与终止点" << endl;
for (int i = 0; i <arcnum; i++) {
//无向图
if (select == 0) {
cin >> P1 >> P2;
int m = LocateVex(P1);
int n = LocateVex(P2);
p1 = (ArcNode*)malloc(sizeof(ArcNode));
p1->adjvex = n;
p1->nextarc = v[m].firstarc;
v[m].firstarc = p1;
p2 = (ArcNode*)malloc(sizeof(ArcNode));
p2->adjvex = m;
p2->nextarc = v[n].firstarc;
v[n].firstarc = p2;
}
//有向图
if (select == 1) {
cin >> P1 >> P2;
int m = LocateVex(P1);
int n = LocateVex(P2);
p1 = (ArcNode*)malloc(sizeof(ArcNode));
p1->adjvex = n;
p1->nextarc = v[m].firstarc;
v[m].firstarc = p1;
}
}
}
//利用邻接表实现的广度优先遍历
void ALGraph::BFS(char start) {
queue<int>ret;
int tag; //用于记录起始点的下标
for (int i = 0; i < vexnum; i++) {
if (v[i].data == start) {
tag = i;
break;
}
}
ret.push(tag);
visited[tag] = true;
while (!ret.empty()) {
int p = ret.front();
ret.pop();
cout << v[p].data << " ";
//visited[p] = true;
ArcNode* arc = (ArcNode*)malloc(sizeof(ArcNode));
arc = v[p].firstarc;
while (arc != NULL ) {
if (visited[arc->adjvex] != true) {
ret.push(arc->adjvex);
visited[arc->adjvex] = true; //刚开始这一步错了,输出了两个F,是因为F还没输出变为true时,另一个F已经进入了队列中
}
arc = arc->nextarc;
}
}
}
//利用邻接表实现的深度优先
void ALGraph::DFS(char start) {
int tag;
for (int i = 0; i < vexnum; i++) {
if (v[i].data == start) {
tag=i;
break;
}
}
visited[tag] = true;
cout << v[tag].data << " ";
ArcNode* arc = (ArcNode*)malloc(sizeof(ArcNode));
arc = v[tag].firstarc;
while (arc != NULL ) {
if (visited[arc->adjvex] != true) {
DFS(v[arc->adjvex].data);
}
arc = arc->nextarc;
}
}
//查找指定元素在头结点数组中的位置
int ALGraph::LocateVex(char ch) {
for (int i = 0; i < vexnum; i++) {
if (v[i].data == ch) {
return i;
}
}
return 0;
}
测试
#include<iostream>
#include"AMGraph.h"
#include "AdjList.h"
using namespace std;
void menu() {
cout << "------------图的遍历方式------------" << endl;
cout << "--1.采用邻接矩阵实现的广度优先遍历--" << endl;
cout << "--2.采用邻接矩阵实现的深度优先遍历--" << endl;
cout << "--3.采用邻接表实现的广度优先遍历----" << endl;
cout << "--4.采用邻接表实现的深度优先遍历----" << endl;
cout << "--0.退出程序------------------------" << endl;
}
int main() {
int choice;
AMGraph G1;
AMGraph G2;
int v;
char tag;
ALGraph Al;
ALGraph ALG;
while (true) {
menu();
cout << "请选择功能键" << endl;
cin >> choice;
switch (choice) {
case 1:
G1.Matrix();
cout << "请输入遍历的起始点" << endl;
cin >> tag;
v = tag - 'A';
G1.DFS(v);
cout << endl;
break;
case 2:
G2.Matrix();
cout << "请输入遍历的起点" << endl;
cin >> tag;
v = tag - 'A';
G2.BFS(v);
cout << endl;
break;
case 3:
Al.CreateUDG();
cout << "请输入遍历的起始点" << endl;
cin >> tag;
Al.BFS(tag);
cout << endl;
break;
case 4:
ALG.CreateUDG();
cout << "请输入遍历的起点" << endl;
cin >> tag;
ALG.DFS(tag);
cout << endl;
break;
case 0:
exit(1);
break;
}
}
return 0;
}