图的邻接矩阵与广度优先

来源:互联网 发布:折800被淘宝封了么 编辑:程序博客网 时间:2024/05/16 06:01

#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;

}