内容:
1)采用邻接矩阵/邻接表建立图;
2)采用深度优先/广度优先搜索方式遍历图
3)编程实现Dijkstra最短路径算法
实现思路:
① 定义邻接矩阵和邻接表的数据类型
② 定义visited数组存储该点是否访问
③ 编写创建图的函数
④ 编写深度优先遍历,使用递归的方法(栈)
⑤ 编写广度优先遍历,使用队列的方法
⑥ 编写Dijkstra算法,使用D[]存储起始点到某点的距离,S[]存储点是否访问过,Path[]存储某点的前一点
程序代码:
1、定义队列头文件:sqqueue.h
#ifndef SQQUEUE
#define SQQUEUE
#define MAXQAIZE 100 //队列可能达到的最大长度
typedef char QElemType;
class SqQueue
{
public:
QElemType *base; //存储空间的基地址
int front; //头指针
int rear; //尾指针
void InitQueue(); //初始化
void EnQueue(QElemType e); //入队
void DeQueue(QElemType &e); //出队
bool QueueEmpty(); //判空
};
#endif // SQQUEUE
2、头文件实现
#include "SqQueue.h"
#define MAXQAIZE 100 //队列可能达到的最大长度
typedef char QElemType;
void SqQueue::InitQueue() //初始化
{
base=new QElemType[MAXQAIZE]; //为队列分配一个最大容量为MAXQSIZE的数组空间
front=rear=0; //头指针尾指针置为零,队列为空
}
void SqQueue::EnQueue(QElemType e) //入队
{
base[rear]=e; //新元素插入队尾
rear=(rear+1)%MAXQAIZE; //尾指针后移一位
}
void SqQueue::DeQueue(QElemType &e) //出队
{
e=base[front]; //保存队头元素
front=(front+1)%MAXQAIZE; //队头指针后移一位
}
bool SqQueue::QueueEmpty()
{
if(rear==front)
return true;
return false;
}
3、主要部分实现:main.cpp
#include <iostream>
#include <windows.h>
#include <algorithm>
#include "SqQueue.h"
using namespace std;
//图的邻接矩阵存储表示
#define MaxInt 32767 //表示极大值,即∞
#define MVNum 100 //最大顶点数
typedef char VerTextType; //顶点数据类型
typedef int ArcType; //边的权值的数据类型
typedef struct
{
VerTextType vexs[MVNum]; //顶点表
ArcType arcs[MVNum][MVNum]; //邻接矩阵表
int vexnum,arcnum; //图的当前点数和边数
bool visited[MVNum]; //访问标志数组,其处置为false
}AMGraph;
typedef struct ArcNode
{
int adjvex;
struct ArcNode *nextarc;
ArcType info;
}ArcNode;
typedef struct VNode//顶点结构
{
VerTextType data; //顶点信息
ArcNode * firstarc; //指向依附该顶点的第一条弧的指针
}VNode, AdjList[MVNum];
typedef struct //图结构
{
AdjList vertics ; //邻接表
int vexnum, arcnum; //顶点数和弧数
bool visited[MVNum];
}ALGraph;
int LocateVex_AM(AMGraph G,char v) //邻接矩阵方法定位顶点
{
for(int i=0;i<G.vexnum;i++)
if(v==G.vexs[i])
return i;
return -1;
}
int LocateVex_AL(ALGraph G,char c) //邻接表方法定位顶点
{
for(int i=0;i<G.vexnum;i++)
{
if(c==G.vertics[i].data)
return i;
}
return -1;
}
void CreateUDN_AM(AMGraph &G) //采用邻接矩阵创建无向网
{
cout<<"请输入无向图的顶点数和边数:"<<endl;
cin>>G.vexnum>>G.arcnum; //输入顶点数和边数
cout<<"请输入这"<<G.vexnum<<"个顶点:"<<endl;
for(int i=0;i<G.vexnum;i++) //初始化顶点
{
cin>>G.vexs[i];
G.visited[i]=false;
}
for(int i=0;i<G.vexnum;i++) //初始化邻接矩阵,边的权值均设为最大值MaxInt
for(int j=0;j<G.vexnum;j++)
G.arcs[i][j]=MaxInt;
cout<<"请依次输入这"<<G.arcnum<<"条边已依附的顶点及权值:"<<endl;
for(int k=0;k<G.arcnum;k++) //构造邻接矩阵
{
char v1,v2;
int w;
cin>>v1>>v2>>w;
int i=LocateVex_AM(G,v1);
int j=LocateVex_AM(G,v2);
G.arcs[i][j]=w;
G.arcs[j][i]=G.arcs[i][j];
}
}
void CreateUDN_AL(ALGraph &G) //采用邻接表创建无向网
{
cout<<"请输入无向图的顶点数和边数:"<<endl;
cin>>G.vexnum>>G.arcnum; //输入总顶点数,总边数
cout<<"请输入这"<<G.vexnum<<"个顶点:"<<endl;
for(int i = 0; i<G.vexnum; ++i)
{ //输入各点,构造头结点表
cin>> G.vertics[i].data; //输入顶点值
G.vertics[i].firstarc=NULL; //初始化表头结点的指针域为NULL
}
cout<<"请依次输入这"<<G.arcnum<<"条边已依附的顶点及权值:"<<endl;
for(int k = 0; k<G.arcnum;++k)
{
char v1,v2;//输入各边,构造邻接表
int w;
cin>>v1>>v2>>w; //输入一条边依附的两个顶点
int i = LocateVex_AL(G, v1);
int j = LocateVex_AL(G, v2);
ArcNode *p1=new ArcNode; //生成一个新的边结点*p1
p1->adjvex=j;
p1->info=w;
p1->nextarc= G.vertics[i].firstarc;
G.vertics[i].firstarc=p1;
//将新结点*p1插入顶点vi的边表头部
ArcNode *p2=new ArcNode; //生成另一个对称的新的边结点*p2
p2->adjvex=i;//邻接点序号为i
p2->info=w;
p2->nextarc= G.vertics[j].firstarc;
G.vertics[j].firstarc=p2;
//将新结点*p2插入顶点vj的边表头部
}//for
}
void DFS_AM(AMGraph &G,int v_index) //深度优先遍历邻接矩阵
{
cout<<G.vexs[v_index]<<" ";
G.visited[v_index]=true;
for(int i=0;i<G.vexnum;i++)
{
if((G.arcs[v_index][i]!=MaxInt) && G.visited[i]==false)
DFS_AM(G,i);
}
}
void DFS_AL(ALGraph &G,int v_index) //深度优先遍历邻接表
{
cout<<G.vertics[v_index].data<<" ";
G.visited[v_index]=true;
ArcNode *p=G.vertics[v_index].firstarc;
while(p!=NULL)
{
int w=p->adjvex;
if(!G.visited[w])
DFS_AL(G,w);
p=p->nextarc;
}
}
void BFS_AM(AMGraph G,int v_index)
{
cout<<G.vexs[v_index]<<" ";
G.visited[v_index]=true;
SqQueue Q;
Q.InitQueue();
Q.EnQueue(G.vexs[v_index]);
while(!Q.QueueEmpty())
{
char u;
Q.DeQueue(u);
int index=LocateVex_AM(G,u);
for(int i=0;i<G.vexnum;i++)
{
if(!G.visited[i]&&G.arcs[index][i]!=MaxInt)
{
cout<<G.vexs[i]<<" ";
G.visited[i]=true;
Q.EnQueue(G.vexs[i]);
}
}
}
}
int FirstAdjVex(ALGraph G,char u)
{
int index=LocateVex_AL(G,u);
ArcNode *p=G.vertics[index].firstarc;
return p->adjvex;
}
int NextAdjVex(ALGraph G,char u,int w)
{
int index=LocateVex_AL(G,u);
ArcNode *p=G.vertics[index].firstarc;
while(p->adjvex!=w)
{
p=p->nextarc;
}
if(p->nextarc==NULL)
return -1;
else
return p->nextarc->adjvex;
}
void BFS_AL(ALGraph G,int v_index)
{
cout<<G.vertics[v_index].data<<" ";
G.visited[v_index]=true;
SqQueue Q;
Q.InitQueue();
Q.EnQueue(G.vertics[v_index].data);
while(!Q.QueueEmpty())
{
char u;
Q.DeQueue(u);
for(int w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w))
{
if(!G.visited[w])
{
cout<<G.vertics[w].data<<" ";
G.visited[w]=true;
Q.EnQueue(G.vertics[w].data);
}
}
}
}
bool S[MVNum];
ArcType D[MVNum];
int Path[MVNum];
void ShorttestPath_DIJ_AM(AMGraph G,int v0)
{
int n=G.vexnum;
for(int i=0;i<n;i++)
{
S[i]=false;
D[i]=G.arcs[v0][i];
if(D[i]<MaxInt)
Path[i]=v0;
else
Path[i]=-1;
}
S[v0]=true;
D[v0]=0;
int v;
for(int i=1;i<n;i++)
{
int min=MaxInt;
for(int w=0;w<n;w++)
{
if(!S[w]&&D[w]<min)
{
v=w;
min=D[w];
}
}
S[v]=true;
int z=v;
cout<<G.vexs[v0]<<"->"<<G.vexs[z]<<":";
string str="";
str+=G.vexs[z];
do
{
z=Path[z];
str+=",";
str+=G.vexs[z];
}while(z!=v0);
reverse(str.begin(),str.end());
cout<<"("<<str<<")"<<D[v]<<endl;
for(int w=0;w<n;w++)
{
if(!S[w]&&(D[v]+G.arcs[v][w]<D[w]))
{
D[w]=D[v]+G.arcs[v][w];
Path[w]=v;
}
}
}
}
void ShorttestPath_DIJ_AL(ALGraph G,int v0)
{
int n=G.vexnum;
for(int i=0;i<n;i++)
{
S[i]=false;
Path[i]=-1;
D[i]=MaxInt;
}
ArcNode *p=G.vertics[v0].firstarc;
while(p)
{
D[p->adjvex]=p->info;
Path[p->adjvex]=v0;
p=p->nextarc;
}
S[v0]=true;
D[v0]=0;
int v;
for(int i=1;i<n;i++)
{
int min=MaxInt;
for(int w=0;w<n;w++)
{
if(!S[w]&&D[w]<min)
{
v=w;
min=D[w];
}
}
S[v]=true;
int z=v;
cout<<G.vertics[v0].data<<"->"<<G.vertics[z].data<<":";
string str="";
str+=G.vertics[z].data;
do
{
z=Path[z];
str+=",";
str+=G.vertics[z].data;
}while(z!=v0);
reverse(str.begin(),str.end());
cout<<"("<<str<<")"<<D[v]<<endl;
ArcNode *p=G.vertics[v].firstarc;
while(p)
{
if(!S[p->adjvex]&&(D[v]+p->info<D[p->adjvex]))
{
D[p->adjvex]=D[v]+p->info;
Path[p->adjvex]=v;
}
p=p->nextarc;
}
}
}
void fun_AM_test()
{
system("cls");
AMGraph G;
CreateUDN_AM(G);
cout<<"该无向图的邻接矩阵为:"<<endl;
for(int i=0;i<G.vexnum;i++)
{
cout<<"\t"<<G.vexs[i];
}cout<<endl<<endl;
for(int i=0;i<G.vexnum;i++)
{
cout<<G.vexs[i]<<"\t";
for(int j=0;j<G.vexnum;j++)
{
cout<<G.arcs[i][j]<<"\t";
}
cout<<endl<<endl;
}
system("pause");
system("cls");
int flag=1;
while(flag)
{
cout<<"***********************************************************"<<endl;
cout<<"************** 1、深度优先遍历无向图 **************"<<endl;
cout<<"************** 2、广度优先遍历无向图 **************"<<endl;
cout<<"************** 3、Dijkstra最短路径算法 **************"<<endl;
cout<<"************** 4、程序退出 **************"<<endl;
cout<<"***********************************************************"<<endl;
int ip;
cout<<"请输入指令:";
cin>>ip;
switch(ip)
{
case 1:
{
cout<<"请输入起始顶点的下标(下标从1开始):";
int num;
cin>>num;
DFS_AM(G,num-1);cout<<endl;
for(int i=0;i<G.vexnum;i++)
{
G.visited[i]=false;
}
system("pause");
break;
}
case 2:
{
cout<<"请输入起始顶点的下标(下标从1开始):";
int num;
cin>>num;
BFS_AM(G,num-1);cout<<endl;
system("pause");
break;
}
case 3:
{
cout<<"请输入起始顶点的下标(下标从1开始):";
int num;
cin>>num;
ShorttestPath_DIJ_AM(G,num-1);
system("pause");
break;
}
case 4:
{
flag=0;
cout<<"程序退出!";
Sleep(1000);
}
}
system("cls");
}
}
void fun_AL_test()
{
system("cls");
ALGraph G;
CreateUDN_AL(G);
cout<<"该无向图的邻接表为:"<<endl;
for(int i=0;i<G.vexnum;i++)
{
cout<<G.vertics[i].data<<" ";
ArcNode *p=G.vertics[i].firstarc;
while(p)
{
cout<<G.vertics[p->adjvex].data<<" ";
p=p->nextarc;
}
cout<<endl;
}
system("pause");
system("cls");
int flag=1;
while(flag)
{
cout<<"***********************************************************"<<endl;
cout<<"************** 1、深度优先遍历无向图 **************"<<endl;
cout<<"************** 2、广度优先遍历无向图 **************"<<endl;
cout<<"************** 3、Dijkstra最短路径算法 **************"<<endl;
cout<<"************** 4、程序退出 **************"<<endl;
cout<<"***********************************************************"<<endl;
int ip;
cout<<"请输入指令:";
cin>>ip;
switch(ip)
{
case 1:
{
cout<<"请输入起始顶点的下标(下标从1开始):";
int num;
cin>>num;
DFS_AL(G,num-1);cout<<endl;
for(int i=0;i<G.vexnum;i++)
{
G.visited[i]=false;
}
system("pause");
break;
}
case 2:
{
cout<<"请输入起始顶点的下标(下标从1开始):";
int num;
cin>>num;
BFS_AL(G,num-1);cout<<endl;
system("pause");
break;
}
case 3:
{
cout<<"请输入起始顶点的下标(下标从1开始):";
int num;
cin>>num;
ShorttestPath_DIJ_AL(G,num-1);
system("pause");
break;
}
case 4:
{
flag=0;
cout<<"程序退出!";
Sleep(1000);
}
}
system("cls");
}
}
int main()
{
cout<<"***********************************************************"<<endl;
cout<<"************** 1、以邻接矩阵方法创建无向图 **************"<<endl;
cout<<"************** 2、以邻接表方法创建无向图 **************"<<endl;
cout<<"************** 3、退出 **************"<<endl;
cout<<"***********************************************************"<<endl;
cout<<"选择以哪种方式创建无向图:";
while(1)
{
int ip;
cin>>ip;
if(ip==1)
{
fun_AM_test();
break;
}
else if(ip==2)
{
fun_AL_test();
break;
}
else if(ip==3)
{
cout<<"程序退出!"<<endl;
break;
}
else
{
cout<<"指令错误,请重新输入:";
}
}
return 0;
}
/*0 2 10 0 4 30 0 5 100
1 2 5
2 3 50
3 5 10
4 3 20 4 5 60*/