非带权无向图的广度优先遍历
【问题描述】输入一个不带权值的无向图的信息,用邻接表存储图,输出邻接表,然后输入一个起始顶点,从该顶点开始进行广度优先遍历,输出遍历的顶点序列
【输入形式】输入有多行,第1行输入两个整数m, n,第1个m为顶点数,第2个n为边数,第2行输入全部顶点名字(一般用大写字母表示),后面还有n行数据,分别是每一条边的2个顶点的名字,最后一行输入广度优先遍历起始顶点的名字
【输出形式】输出图的邻接表,具体格式见Sample Output,最后一行输出图得广度优先遍历的顶点序列,各个顶点之间用一个空格隔开,最后一个顶点后也有一个空格,不用单独处理
【样例输入】
9 10
ABCDEFGHI
AD
AC
AB
BE
BC
CF
DF
EG
FH
HI
A
【样例输出】
0 A–>1–>2–>3
1 B–>2–>4–>0
2 C–>5–>1–>0
3 D–>5–>0
4 E–>6–>1
5 F–>7–>3–>2
6 G–>4
7 H–>8–>5
8 I–>7
A B C D E F G H I
代码如下(含有注释):
#include<iostream>
using namespace std;
//邻接边的结点定义
struct EdgeNode
{
int Ver_position;//邻接结点的位置
string Edge_info;//邻接边的信息
EdgeNode* Next_edge;//下一个邻接边
EdgeNode()
{
Ver_position = -1;
Edge_info = "";
Next_edge = NULL;
}
EdgeNode(int x, string y)
{
Ver_position = x;
Edge_info = y;
Next_edge = NULL;
}
};
//顶点的结点定义
template<class T>
struct VertexNode
{
T data;//顶点的值
EdgeNode* Adj_edge;//顶点的第一条邻接边的信息
VertexNode()
{
data = 0;
Adj_edge = NULL;
}
};
//队列结点定义
template<class T>
struct QueneNode
{
VertexNode<T>* data;//以顶点指针为数据域
QueneNode* link;//下一个队列结点
QueneNode()
{
data = NULL;
link = NULL;
}
QueneNode(VertexNode<T>* x)
{
data = x;
link = NULL;
}
};
//无向图的类定义
template<class T>
class UndirGraph
{
public:
UndirGraph(int x, int y);//构造函数
int Judge_ver(T x);//判断顶点的位置
char output_ver(int x)//输出某个位置的顶点的值
{
return array[x].data;
}
void Insert_edge(string x);//插入边
void display();//输出邻接边
VertexNode<T>* Get_ver()//取得顶点数组的首地址
{
return array;
}
private:
VertexNode<T>* array;//顶点数组指针
int Len;//顶点的个数
};
//队列类的定义
template<class T>
class Quene
{
public:
Quene();//构造函数
bool Join_quene(VertexNode<T>* x);//入队
bool Leave_quen(VertexNode<T>*& x);//出队
bool Is_Empty();//判断队列是否为空
private:
QueneNode<T>* front;//队头指针
QueneNode<T>* rear;//队尾指针
};
//无向图的构造函数,构造邻接表
template<class T>
UndirGraph<T>::UndirGraph(int x, int y)//x为顶点数目,y为边的数目
{
Len = x;
array = new VertexNode<T>[x];//构造顶点数组
for (int i = 0; i < Len; i++)
cin >> array[i].data;//顶点赋值
string temp = "";//边的定义
for (int i = 0; i < y; i++)
{
cin >> temp;//输入边
Insert_edge(temp);//插入边
temp = "";
}
}
//判断顶点为某值的顶点的位置
template<class T>
int UndirGraph<T>::Judge_ver(T x)
{
for (int i = 0; i < Len; i++)
{
if (array[i].data == x)//值对应,则返回顶点位置
{
return i;
}
}
}
//插入邻接边
template<class T>
void UndirGraph<T>::Insert_edge(string str)
{
EdgeNode* newedgeleft = NULL, * newedgeright = NULL;//无向图一条边属于两个结点,所以两个结点后都要插入边
int num, pos;
pos = Judge_ver(str[0]);//获取第一个顶点的位置
num = Judge_ver(str[1]);//获取邻接顶点的位置
newedgeleft = new EdgeNode(num,str);//构造邻接顶点的边
newedgeleft->Next_edge = array[pos].Adj_edge;
array[pos].Adj_edge = newedgeleft;//第一个顶点后面插入边
pos = Judge_ver(str[1]);//获取邻接顶点的位置
num = Judge_ver(str[0]);//获取第一个顶点的位置
newedgeright = new EdgeNode(num, str);//构造第一个顶点的边
newedgeright->Next_edge = array[pos].Adj_edge;
array[pos].Adj_edge = newedgeright;//邻接顶点后面插入边
}
//输出邻接表
template<class T>
void UndirGraph<T>::display()
{
EdgeNode* current = NULL;//边遍历指针
for (int i = 0; i < Len; i++)
{
cout << i << ' ' << array[i].data;//输出顶点值
current = array[i].Adj_edge;
while (current != NULL)//遍历输出边值
{
cout << "-->" << current->Ver_position;
current = current->Next_edge;
}
cout << endl;
}
}
//队列构造函数
template<class T>
Quene<T>::Quene()
{
front = new QueneNode<T>;//空头结点
rear = front;//尾指针最开始向头结点
}
//入队
template<class T>
bool Quene<T>::Join_quene(VertexNode<T>* x)
{
QueneNode<T>* newquenenode = NULL;//队列指针定义
newquenenode = new QueneNode<T>(x);//队列结点的新建
if (newquenenode==NULL)//分配空间失败
{
return false;
}
//队尾入队
newquenenode->link = rear->link;//新结点的指针指向rear的指针域(NULL)
rear->link = newquenenode;//rear的指针域指向新结点
rear = newquenenode;//队尾指针指向新结点
return true;
}
//出队
template<class T>
bool Quene<T>::Leave_quen(VertexNode<T>*& x)
{
QueneNode<T>* p = front->link;//队头结点的指针定义
if (front == rear)//判断队列是否为空
{
return false;
}
if (p == rear)//front指针域指向的是rear
rear = front;//删除p时,避免rear成为野指针
front->link = p->link;//头结点的指针域指向队头结点的指针域
x = p->data;//传值
delete p;//删除队列结点
p = NULL;//避免野指针
return true;
}
//判断队列是否为空
template<class T>
bool Quene<T>::Is_Empty()
{
if (front == rear)//判空条件
{
return true;
}
else
{
return false;
}
}
//无向图的广度遍历
void Graph_tra(UndirGraph<char> t, int n)
{
char x;//遍历开始的顶点
cin >> x;//输入遍历开始的顶点
VertexNode<char>* p = NULL;//顶点遍历指针
VertexNode<char>* temp = t.Get_ver();//顶点数组
EdgeNode* current = NULL;//边遍历指针
bool* Judge_ver_tra;//顶点是否被访问数组
Judge_ver_tra = new bool[n];
for (int i = 0; i < n; i++)
Judge_ver_tra[i] = false;//被访问顶点所在位置为true,否者为false
Quene<char> s;//队列
if (temp == NULL)//如果顶点数组为空,不进行遍历
{
return;
}
s.Join_quene(&temp[t.Judge_ver(x)]);//入队开始遍历的顶点,通过顶点值找到顶点结点
while (!s.Is_Empty())//队列为空,结束循环
{
int num ;//顶点位置
s.Leave_quen(p);//出队
num = t.Judge_ver(p->data);//顶点位置赋值
if (!Judge_ver_tra[num])//如果没有被访问输出
{
cout << p->data << ' ';//输出顶点
Judge_ver_tra[num] = true;//访问数组对应值改变为已经被访问
}
current = p->Adj_edge;//边遍历指针赋值
while (current!=NULL)//边遍历指针为空,停止循环
{
if (!Judge_ver_tra[current->Ver_position])//如果边邻接的顶点未被访问,入队
s.Join_quene(&temp[current->Ver_position]);
current = current->Next_edge;//边遍历指针改变下一条边
}
}
cout << endl;//保证格式
}
int main()
{
int m, n;
cin >> m >> n;//输入顶点数,边数
UndirGraph<char> t(m, n);//构造无向图邻接表
t.display();//输出无向图邻接表
Graph_tra(t,m);//无向图的广度遍历
}