轻轻松松学会图的遍历

图的存储结构一般常用邻接矩阵和邻接表,邻接矩阵可以称为数组表示法,用一个一维数组vertex[]来存储顶点的信息,再用一个二维数组edge来存储边的信息,这个二维数组我们称为邻接矩阵;对于邻接表来说,是使用顺序链表的方式存储,类似于树的孩子表示法。

邻接矩阵

 看edge数组,我们可以得知,无向图的邻接矩阵一定是对称矩阵,而有向图的邻接矩阵则不一定对称。在edge数组里面我们可以知道一个顶点的入度与出度的信息(无向图,入度等于出度)。对于顶点i来说,第i行代表的是出度,i列代表的是出度。

#include<iostream>
using namespace std;

const int MaxSize = 10; //图中最多顶点个数
int visited[MaxSize] = {0}; //全局数组变量visited初始化
template<typename DataType>
class MGraph
{
public:
MGraph(DataType a[ ], int n, int e); //构造函数,建立具有n个顶点e条边的图
~MGraph( ){ }; //析构函数
void DFTraverse(int v); //深度优先遍历图
void BFTraverse(int v); //广度优先遍历图
private:
DataType vertex[MaxSize]; //存放图中顶点的数组
int edge[MaxSize][MaxSize]; //存放图中边的数组
int vertexNum, edgeNum; //图的顶点数和边数
};

template<typename DataType>
MGraph<DataType>:: MGraph(DataType a[ ], int n, int e)
{
int i, j, k;
vertexNum = n; edgeNum = e;
for (i = 0; i < vertexNum; i++) //存储顶点
vertex[i] = a[i];
for (i = 0; i < vertexNum; i++) //初始化邻接矩阵
for (j = 0; j < vertexNum; j++)
edge[i][j] = 0;
for (k = 0; k < edgeNum; k++) //依次输入每一条边
{
cout << "请输入边依附的两个顶点的编号:";
cin >> i >> j; //输入边依附的两个顶点的编号
edge[i][j] = 1; edge[j][i] = 1; //置有边标志
}
}

template<typename DataType>
void MGraph<DataType>:: DFTraverse(int v)
{
cout << vertex[v]; visited[v] = 1;
for (int j = 0; j < vertexNum; j++)
if (edge[v][j] == 1 && visited[j] == 0) DFTraverse( j );
}

template<typename DataType>
void MGraph<DataType>:: BFTraverse(int v)
{
int w, j, Q[MaxSize]; //采用顺序队列
int front = -1, rear = -1; //初始化队列
cout << vertex[v]; visited[v] = 1; Q[++rear] = v; //被访问顶点入队
while (front != rear) //当队列非空时
{
w = Q[++front]; //将队头元素出队并送到v中
for (j = 0; j < vertexNum; j++)
if (edge[w][j] == 1 && visited[j] == 0 ) {
cout << vertex[j]; visited[j] = 1; Q[++rear] = j;
}
}
}

int main( )
{
int i;
char ch[ ]={'A','B','C','D','E'};
/* 测试数据六条边是:(0 1)(0 2)(0 3)(0 4)(1 2)(2 4) */
MGraph<char> MG(ch, 5, 6); //建立具有5个顶点6条边的无向图
for (i = 0; i < MaxSize; i++)
visited[i] = 0;
cout << "深度优先遍历序列是:" << endl;
MG.DFTraverse(0); //从顶点0出发进行深度优先遍历
for (i = 0; i < MaxSize; i++)
visited[i] = 0;
cout << "广度优先遍历序列是:" << endl;
MG.BFTraverse(0); //从顶点0出发进行广度优先遍历
return 0;
}

邻接表

我刚刚说过,邻接表类似于树的孩子表示法,对与图的每个顶点v,将v的所有邻接点链成一个单链表,称为顶点v的边表(有向图则称为出边表),为了方便对所有边表的头指针进行存取操作,采取顺序存储。存储边表头指针的数组和存储顶点的数组构成了邻接表的表头数组,称为顶点表。所以,在邻接表中存在两种结点结构:顶点结点和边表结点。其中,vertex为数据域,存放顶点信息:firstEdge为指针城,指向边表的第一个结点:adjvex为邻接点域,存放该顶点的邻接点在顶点表中的下标;next为指针域,指向边表的下一个结点。对于网图,边表结点还需增设info域存储边上信息(如权值)。

#include<iostream> 
using namespace std;

struct EdgeNode //定义边表结点
{
int adjvex; //邻接点域
EdgeNode *next;
};

template<typename DataType>
struct VertexNode //定义顶点表结点
{
DataType vertex;
EdgeNode *firstEdge;
};

const int MaxSize = 10; //图的最多顶点数
int visited[MaxSize] = {0};
template<typename DataType>
class ALGraph
{
public:
ALGraph(DataType a[ ], int n, int e); //构造函数,建立n个顶点e条边的图
~ALGraph( ); //析构函数,释放邻接表各边表结点的存储空间
void DFTraverse(int v); //深度优先遍历图
void BFTraverse(int v); //广度优先遍历图
private:
VertexNode<DataType> adjlist[MaxSize]; //存放顶点表的数组
int vertexNum, edgeNum; //图的顶点数和边数
};

template<typename DataType>
ALGraph<DataType>:: ALGraph(DataType a[ ], int n, int e)
{
int i, j, k;
EdgeNode *s = NULL;
vertexNum = n; edgeNum = e;
for (i = 0; i < vertexNum; i++) //输入顶点信息,初始化顶点表
{
adjlist[i].vertex = a[i];
adjlist[i].firstEdge = NULL;
}
for (k = 0; k < edgeNum; k++) //依次输入每一条边
{
cout << "输入边所依附的两个顶点的编号:";
cin >> i >> j; //输入边所依附的两个顶点的编号
s = new EdgeNode; s->adjvex = j; //生成一个边表结点s
s->next = adjlist[i].firstEdge; //将结点s插入到第i个边表的表头
adjlist[i].firstEdge = s;
}
}

template<typename DataType>
ALGraph<DataType>:: ~ALGraph( )
{
EdgeNode *p = NULL, *q = NULL;
for (int i = 0; i < vertexNum; i++)
{
p = q = adjlist[i].firstEdge;
while (p != NULL)
{
p = p->next;
delete q;
q = p;
}
}
}

template<typename DataType>
void ALGraph<DataType>:: DFTraverse(int v)
{
int j;
EdgeNode *p = NULL;
cout << adjlist[v].vertex; visited[v] = 1;
p = adjlist[v].firstEdge; //工作指针p指向顶点v的边表
while (p != NULL) //依次搜索顶点v的邻接点
{
j = p->adjvex;
if (visited[j] == 0) DFTraverse(j);
p = p->next;
}
}

template<typename DataType>
void ALGraph<DataType>:: BFTraverse(int v)
{
int w, j, Q[MaxSize]; //采用顺序队列
int front = -1, rear = -1; //初始化队列
EdgeNode *p = NULL;
cout << adjlist[v].vertex; visited[v] = 1; Q[++rear] = v; //被访问顶点入队
while (front != rear) //当队列非空时
{
w = Q[++front];
p = adjlist[w].firstEdge; //工作指针p指向顶点v的边表
while (p != NULL)
{
j = p->adjvex;
if (visited[j] == 0) {
cout << adjlist[j].vertex; visited[j] = 1;Q[++rear] = j;
}
p = p->next;
}
}
}
int main( )
{
//测试数据是图6-20(a),边是(0 1)(0 3)(0 4)(1 2)(2 4)(3 2)(3 4)
char ch[ ] = {'A','B','C','D','E'};
int i;
ALGraph<char> ALG(ch, 5, 7); //建立具有5个顶点6条边的有向图
for (i = 0; i < MaxSize; i++)
visited[i] = 0;
cout << "深度优先遍历序列是:";
ALG.DFTraverse(0); //从顶点0出发进行深度优先遍历
for (i = 0; i < MaxSize; i++)
visited[i] = 0;
cout << "广度优先遍历序列是:";
ALG.BFTraverse(0); //从顶点0出发进行广度优先遍历
return 0;
}

 本次分享到此就没有了,希望有帮到大家。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值