#include<iostream>
using namespace std;
#define MAX 20
#define NULL 0
typedef struct ArcCell{
int adj;
}ArcCell,AdjMatrix[MAX][MAX]; //定义二维数组矩阵,adj是将来存的权值
typedef struct{
char Vexs[MAX];
AdjMatrix arcs;
int vexnum,arcnum;
}MGraph; //点的名称,二维数组,点、边的个数
typedef struct QNode{
int data;
struct QNode *next;
}QNode,*QueuePtr; //队列的结点的申请,并且明确其类型!
typedef struct{
QueuePtr front;
QueuePtr rear;
}LinkQueue; //创建头尾指针结构体
int LnitQueue(LinkQueue &Q){
Q.front=Q.rear=(QueuePtr)malloc(sizeof(QNode)); //分配空节点,创建空队列
Q.front->next=NULL; //头结点next指针为空
return 0;
};
int EnQueue(LinkQueue &Q,int e){ //加入队列,结点值为e
QueuePtr p;
p=(QueuePtr)malloc(sizeof(QNode)); //分配结点空间
p->data=e; //数据赋值
p->next=NULL;
Q.rear->next=p; //在尾部插入
Q.rear=p; //尾部指针指向尾部,所谓的头指针和尾指针都只是指针,只不过指针指向特殊申明的结点,不要把它看成
return 0; //队列的一部分,意想成为也是头结点,其实不是这样的!
};
int DeQueue(LinkQueue &Q,int &e){ //Q.front or Q.rear仅仅是指针而已,不是什么结点!!!,但队列中还是有头结点概念!
//在创建空队列的时候就决定了一定会有头结 点,并且新加入元素在队伍尾进行!
if(Q.front==Q.rear) cout<<"The Queue is wrong!"<<endl;
QueuePtr p;
p=Q.front->next; //p指向第一个结点
e=p->data; //e复制数据
Q.front->next=p->next; // 队头指针下移一位
if(Q.rear==p) Q.rear=Q.front; //如果队列为空了,则队头等于对尾,这是常常忽略的,此时还是有空的头结点的!
delete(p);
return 0;
};
int QueueEmpty(LinkQueue Q){
if(Q.front==Q.rear)return 1; //判断是否为空,空为1,不空为0
else return 0;
};
int LocateVex(MGraph &G ,char v){
int i=0;
for(;v!=G.Vexs[i];i++); //根据点的名称确定其在二维数组中的下标
return i;
};
int CreateUDG(MGraph &G){
cout<<"please input the vexnum and arcnum"<<endl;
cin>>G.vexnum>>G.arcnum; //提示输入点和边的个数
int i,j,k,w;
char v1,v2; //v1,v2作为点的名称的临时存储变量
for(i=0;i<G.vexnum;++i){
cout<<"please input the name of the point"<<endl;
cin>>G.Vexs[i];
} //提示输入点的名称,存入Vexs数组中!
for(i=0;i<G.vexnum;++i) //初始化二维数组,使得其初值都为1000!
for(j=0;j<G.vexnum;++j)
G.arcs[i][j].adj=0;
for(k=0;k<G.arcnum;++k){
cout<<"please input the link and num"<<endl; //提示输入边及权值的信息!
cin>>v1>>v2>>w;
i=LocateVex(G,v1);
j=LocateVex(G,v2); //确定输入的点的名称在邻接矩阵中的下标
G.arcs[i][j].adj=w; //存入邻接矩阵中
G.arcs[j][i].adj=G.arcs[i][j].adj; //因为是无向图,因此是一个对称阵!
}
return 0;
};
int Visited[MAX]; //标志数组!用来表明是否被访问过
int FirstAdjVex(MGraph G,int v){ //求邻接结点
int j;
for(j=0;j<G.vexnum;j++){ //对邻接矩阵的v行进行遍历!
if(G.arcs[v][j].adj==1 && Visited[j]==0) //当v与某点有边存在并且没有被访问过,则就是v的邻接结点
return j;
}
return -1; //没有邻接节点就返回-1!
};
int NextAdjVex(MGraph G,int v,int w){
int j;
for(j=w;j<G.vexnum;j++){
if(G.arcs[v][j].adj==1 && Visited[j]==0) //求v的第二个邻接结点,即从v行w点后开始遍历!
return j;
}
return -1;
};
void BFSTraverse(MGraph G){
int v,u,w;
for(v=0;v<G.vexnum;++v)Visited[v]=0; //初始化标志数组,均置为0
LinkQueue Q;
LnitQueue(Q); //创建空队列
for(v=0;v<G.vexnum;++v) //for循环其实是很重要的,因为它遍历所有结点,考虑了多个分图存在的情况
if(!Visited[v]){
Visited[v]=1; //对没有访问过的结点进行反复,并且输出!
cout<<G.Vexs[v]<<endl;
EnQueue(Q,v); //记录访问过的结点,压入队列!做记录
while(!QueueEmpty(Q)){ //可以对队列中的结点的所有未访问的邻接结点进行访问!
DeQueue(Q,u); //取出队列第一个结点
for(w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w))
if(!Visited[w]){
Visited[w]=1; //对没有访问过的结点进行反复,并且输出!
cout<<G.Vexs[w]<<endl;
EnQueue(Q,w); //对一个结点的所有结点进行访问,并全部加入队列
}//if
}//while
}//if
};//BFSTraverse
int main(){
MGraph G; //申请并创建图
CreateUDG(G);
BFSTraverse(G); //进入函数进行遍历
return 0;
}