idk why these stuffs get stashed for so long and I didn't ever commit them
This commit is contained in:
112
OrigFiles/6-图/6-1-1-1-MGraph(无向图)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-1-1-1-MGraph(无向图)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
130
OrigFiles/6-图/6-1-1-1-MGraph(无向图)/Mgraph.cpp
Normal file
130
OrigFiles/6-图/6-1-1-1-MGraph(无向图)/Mgraph.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "Mgraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
// 无向图
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立无向图"<<endl;
|
||||
cout<<" 2. 返回顶点在图中的位序"<<endl;
|
||||
cout<<" 3. 返回某位序的顶点"<<endl;
|
||||
cout<<" 4. 修改顶点"<<endl;
|
||||
cout<<" 5. 增加新顶点"<<endl;
|
||||
cout<<" 6. 删除顶点"<<endl;
|
||||
cout<<" 7. 增添边"<<endl;
|
||||
cout<<" 8. 删除边"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历图"<<endl;
|
||||
cout<<"10. 从第一个顶点出发广度优先遍历图"<<endl;
|
||||
cout<<"11. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k;
|
||||
MGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateUDG(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // 查询顶点位序
|
||||
cout<<"请输入您要的所要查询位序的顶点: ";
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在图中的位序为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 按位序查找顶点值
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位序: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 修改顶点
|
||||
cout<<"请输入要更改的顶点: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5: // 增加顶点
|
||||
cout<<"请输入要增加的顶点: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6: // 删除顶点
|
||||
cout<<"请输入要删除的顶点:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7: // 增加边
|
||||
cout<<"请输入要增添边的顶相邻两顶点";
|
||||
cin>>u>>v;
|
||||
if(InsertArc(G,u,v))
|
||||
cout<<"插入边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8: // 删除边
|
||||
cout<<"请输入删除的边相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"顶点边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9: // 深度优先遍历
|
||||
cout<<"从第一个顶点出发深度优先遍历图的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10: // 广度优先遍历
|
||||
cout<<"从第一个顶点出发广度优先遍历图的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"选择不合理,请重选!"<<endl;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
|
||||
309
OrigFiles/6-图/6-1-1-1-MGraph(无向图)/Mgraph.h
Normal file
309
OrigFiles/6-图/6-1-1-1-MGraph(无向图)/Mgraph.h
Normal file
@@ -0,0 +1,309 @@
|
||||
/*--------------------------无向图的邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和边数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条边信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=i+1;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<")"<<'\t';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDG(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
cout<<"请输入无向图的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向图的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=0;
|
||||
cout<<"请输入各条边的两个邻接点"<<endl; // 4.创建各条边
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条边的两个顶点:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入边的两个邻接点
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=1; // 4.3 修改邻接矩阵
|
||||
G.arcs[j][i]=1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjvex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjvex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==0 ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=0;
|
||||
G.arcs[j][G.vexnum-1]=0;
|
||||
}
|
||||
cout<<"创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值"<<endl;
|
||||
cin>>w;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在
|
||||
InsertArc(G,v,w);
|
||||
else
|
||||
cout<<w<<"顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w) // 在值为v、w顶点间加边
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
{
|
||||
cout<<"\n顶点不存在或两顶点相同,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
return false; // 不能插入边,返回false
|
||||
if(G.arcs[i][j]==1)
|
||||
{
|
||||
cout<<"\n边已存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=1;
|
||||
G.arcs[j][i]=1;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除边
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边不存在,返回false
|
||||
{
|
||||
cout<<"边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=0; // 置邻接矩阵第 i 行第 j 列为零
|
||||
G.arcs[j][i]=0; // 置邻接矩阵第 i 列第 j 行为零
|
||||
G.arcnum--; // 边数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的边
|
||||
{
|
||||
if(G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 先访问index
|
||||
cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
{
|
||||
if(G.arcs[v][w]!=0 && !visited[w] )
|
||||
DFS2(G,w);
|
||||
}
|
||||
//cout<<endl;
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS2(G,i); // 进行深度优先递归
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v]; // 访问顶点v
|
||||
visited[v]=true; // 做访问标志
|
||||
EnQueue(Q,v); // 入队
|
||||
while(!QueueEmpty(Q)) // 队非空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
cout<<G.vexs[w]; // 访问
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i); // 进行BFS遍历
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-1-1-2-Mgraph(无向网)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-1-1-2-Mgraph(无向网)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
130
OrigFiles/6-图/6-1-1-2-Mgraph(无向网)/Mgraph.cpp
Normal file
130
OrigFiles/6-图/6-1-1-2-Mgraph(无向网)/Mgraph.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "Mgraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
// 无向网
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立无向网"<<endl;
|
||||
cout<<" 2. 返回顶点在网中的位序"<<endl;
|
||||
cout<<" 3. 返回某位序的顶点"<<endl;
|
||||
cout<<" 4. 修改顶点"<<endl;
|
||||
cout<<" 5. 增加新顶点"<<endl;
|
||||
cout<<" 6. 删除顶点"<<endl;
|
||||
cout<<" 7. 增添边"<<endl;
|
||||
cout<<" 8. 删除边"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历网"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历网"<<endl;
|
||||
cout<<"11. 显示网"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k,weight;
|
||||
MGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向网
|
||||
CreateUDN(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的网为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // 查询顶点位序
|
||||
cout<<"请输入您要的所要查询位序的顶点: ";
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在网中的位序为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 按位序查找顶点值
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位序: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 修改顶点
|
||||
cout<<"请输入要更改的顶点: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修后的网:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5: // 增加顶点
|
||||
cout<<"请输入要增加的顶点: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应边后的网:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6: // 删除顶点
|
||||
cout<<"请输入要删除的顶点:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的网:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7: // 增加边
|
||||
cout<<"请输入要增添边的顶相邻两顶点和权值";
|
||||
cin>>u>>v>>weight;
|
||||
if(InsertArc(G,u,v,weight)) // 插入成功,显示网
|
||||
cout<<"插入边后的网:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8: // 删除边
|
||||
cout<<"请输入删除的边相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"顶点边后的网:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9: // 深度优先遍历
|
||||
cout<<"从第一个顶点出发深度优先遍历网的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10: // 广度优先遍历
|
||||
cout<<"从第一个顶点出发广度优先遍历网的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11: // 显示网
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"无效选择,请重选!"<<endl;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
|
||||
310
OrigFiles/6-图/6-1-1-2-Mgraph(无向网)/Mgraph.h
Normal file
310
OrigFiles/6-图/6-1-1-2-Mgraph(无向网)/Mgraph.h
Normal file
@@ -0,0 +1,310 @@
|
||||
/*--------------------------无向图网邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
#define INF 1000 // 无穷大
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息,设权值为整型
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和边数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条边信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=i+1;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=INF)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<","<<G.arcs[i][j]<<")"<<'\t';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDN(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k,weight;
|
||||
DT v1,v2;
|
||||
cout<<"请输入无向网的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向网的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=INF;
|
||||
cout<<"请输入各条边的两个邻接点"<<endl; // 4.创建各条边
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条边的两个顶点和权值:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入边的两个邻接点和边权值
|
||||
cin>>weight;
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=weight; // 4.3 修改邻接矩阵
|
||||
G.arcs[j][i]=weight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjvex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=INF) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjvex(MGraph<DT> G,int u,int w) // 查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==INF ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=INF) // 如果有非无穷元
|
||||
return j; // 第一个非穷元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j,weight;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=INF;
|
||||
G.arcs[j][G.vexnum-1]=INF;
|
||||
}
|
||||
cout<<"创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值和边的权值"<<endl;
|
||||
cin>>w>>weight;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在
|
||||
InsertArc(G,v,w,weight);
|
||||
else
|
||||
cout<<w<<"顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w,int weight) // 在值为v、w顶点间加边
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
{
|
||||
cout<<"\n顶点不存在,或两顶点相同,不能插入!"<<endl;
|
||||
return false; // 不能插入边,返回false
|
||||
}
|
||||
if(G.arcs[i][j]!=INF)
|
||||
{
|
||||
cout<<"\n边已存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=weight;
|
||||
G.arcs[j][i]=weight;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除边
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边不存在,返回false
|
||||
{
|
||||
cout<<"边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=INF; // 置邻接矩阵第 i 行第 j 列为无穷
|
||||
G.arcs[j][i]=INF; // 置邻接矩阵第 i 列第 j 行为无穷
|
||||
G.arcnum--; // 边数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的边
|
||||
{
|
||||
if(G.arcs[i][j]!=INF)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 访问v
|
||||
cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++) // 找v的未访问第1个邻接点
|
||||
{
|
||||
if(G.arcs[v][w]!=INF && !visited[w] )
|
||||
DFS2(G,w);
|
||||
}
|
||||
//cout<<endl;
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS2(G,i); // 进行深度优先递归
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v]; // 访问顶点v
|
||||
visited[v]=true; // 做访问标志
|
||||
EnQueue(Q,v); // 入队
|
||||
while(!QueueEmpty(Q)) // 队非空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
cout<<G.vexs[w]; // 访问
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i); // 进行BFS遍历
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-1-1-3-Mgraph(有向图)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-1-1-3-Mgraph(有向图)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
130
OrigFiles/6-图/6-1-1-3-Mgraph(有向图)/Mgraph.cpp
Normal file
130
OrigFiles/6-图/6-1-1-3-Mgraph(有向图)/Mgraph.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "Mgraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
// 有向图
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立有向图"<<endl;
|
||||
cout<<" 2. 返回顶点在图中的位序"<<endl;
|
||||
cout<<" 3. 返回某位序的顶点"<<endl;
|
||||
cout<<" 4. 修改顶点"<<endl;
|
||||
cout<<" 5. 增加新顶点"<<endl;
|
||||
cout<<" 6. 删除顶点弧"<<endl;
|
||||
cout<<" 7. 增添弧"<<endl;
|
||||
cout<<" 8. 删除弧"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历图"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历图"<<endl;
|
||||
cout<<"11. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k;
|
||||
MGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateDG(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // 查询顶点位序
|
||||
cout<<"请输入您要的所要查询位序的顶点: ";
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在图中的位序为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 按位序查找顶点值
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位序: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 修改顶点
|
||||
cout<<"请输入要更改的顶点: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修后的图为:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5: // 增加顶点
|
||||
cout<<"请输入要插入顶点: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应的弧后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6: // 删除顶点
|
||||
cout<<"请输入要删除的顶点:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"删除顶点后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7: // 增加弧
|
||||
cout<<"请输入要插入的弧的弧尾和弧头顶点";
|
||||
cin>>u>>v;
|
||||
if(InsertArc(G,u,v))
|
||||
cout<<"插入弧后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8: // 删除弧
|
||||
cout<<"请输入要删除的弧的弧尾和弧头: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"删除弧后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9: // 深度优先遍历
|
||||
cout<<"从第一个顶点出发深度优先遍历图的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10: // 广度优先遍历
|
||||
cout<<"从第一个顶点出发广度优先遍历图的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"无效选择,请重选!"<<endl;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
|
||||
302
OrigFiles/6-图/6-1-1-3-Mgraph(有向图)/Mgraph.h
Normal file
302
OrigFiles/6-图/6-1-1-3-Mgraph(有向图)/Mgraph.h
Normal file
@@ -0,0 +1,302 @@
|
||||
/*--------------------------有向图的邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和弧数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条弧信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<")"<<'\t';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建有向图
|
||||
template <class DT>
|
||||
void CreateDG(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
cout<<"请输入有向图的顶点数 "; // 1. 输入顶点数、弧数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入有向图的弧数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=0;
|
||||
cout<<"请输入各条弧的弧尾、弧头:"<<endl; // 4.创建各条弧
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条弧的弧尾、弧头:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入弧的两个邻接点和弧权值
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=1; // 4.3 修改邻接矩阵
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjvex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjvex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==0 ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=0;
|
||||
G.arcs[j][G.vexnum-1]=0;
|
||||
}
|
||||
cout<<"创建弧吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入弧尾、弧头:"<<endl;
|
||||
cin>>v>>w;
|
||||
InsertArc(G,v,w);
|
||||
cout<<"继续创建弧吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w) // 在值为v、w顶点间加弧
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
{
|
||||
cout<<"\n顶点不存在或不合理,不能插入!"<<endl;
|
||||
return false; // 不能插入弧,返回false
|
||||
}
|
||||
if(G.arcs[i][j]!=0) // 弧已存在,不能插入
|
||||
{
|
||||
cout<<"\n弧已存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
G.arcs[i][j]=1;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除弧
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 弧不存在,返回false
|
||||
{
|
||||
cout<<"弧不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=0; // 置邻接矩阵第 i 行第 j 列为零
|
||||
G.arcnum--; // 弧数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的弧
|
||||
{
|
||||
if(G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 先访问index
|
||||
cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
{
|
||||
if(G.arcs[v][w]!=0 && !visited[w] )
|
||||
DFS2(G,w);
|
||||
}
|
||||
//cout<<endl;
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS2(G,i); // 进行深度优先递归
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v]; // 访问顶点v
|
||||
visited[v]=true; // 做访问标志
|
||||
EnQueue(Q,v); // 入队
|
||||
while(!QueueEmpty(Q)) // 队非空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
cout<<G.vexs[w]; // 访问
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i); // 进行BFS遍历
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-1-1-4-Mgraph(有向网)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-1-1-4-Mgraph(有向网)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
130
OrigFiles/6-图/6-1-1-4-Mgraph(有向网)/Mgraph.cpp
Normal file
130
OrigFiles/6-图/6-1-1-4-Mgraph(有向网)/Mgraph.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "Mgraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
// 有向网
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立有向网"<<endl;
|
||||
cout<<" 2. 返回顶点在网中的位序"<<endl;
|
||||
cout<<" 3. 返回某位序的顶点"<<endl;
|
||||
cout<<" 4. 修改顶点"<<endl;
|
||||
cout<<" 5. 增加新顶点"<<endl;
|
||||
cout<<" 6. 删除顶点弧"<<endl;
|
||||
cout<<" 7. 增添边"<<endl;
|
||||
cout<<" 8. 删除边"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历网"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历网"<<endl;
|
||||
cout<<"11. 显示网"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k,weight;
|
||||
MGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向网
|
||||
CreateDN(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的网为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // 查询顶点位序
|
||||
cout<<"请输入您要的所要查询位序的顶点: ";
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在网中的位序为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 按位序查找顶点值
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位序: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 修改顶点
|
||||
cout<<"请输入要更改的顶点: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修后的网为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5: // 增加顶点
|
||||
cout<<"请输入要增加的顶点: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应边后的网为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6: // 删除顶点
|
||||
cout<<"请输入要删除的顶点:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的网为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7: // 增加边
|
||||
cout<<"请输入要增添边的顶相邻两顶点和权值";
|
||||
cin>>u>>v>>weight;
|
||||
if(InsertArc(G,u,v,weight))
|
||||
cout<<"插入边后的网为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8: // 删除边
|
||||
cout<<"请输入删除的边相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"顶点边后的网为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9: // 深度优先遍历
|
||||
cout<<"从第一个顶点出发深度优先遍历网的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10: // 广度优先遍历
|
||||
cout<<"从第一个顶点出发广度优先遍历网的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11: // 显示网
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"选择不合理,请重选!"<<endl;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
|
||||
304
OrigFiles/6-图/6-1-1-4-Mgraph(有向网)/Mgraph.h
Normal file
304
OrigFiles/6-图/6-1-1-4-Mgraph(有向网)/Mgraph.h
Normal file
@@ -0,0 +1,304 @@
|
||||
/*--------------------------有向网的邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
#define INF 1000 // 无穷大
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和弧数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条弧信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=INF)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<","<<G.arcs[i][j]<<")"<<'\t';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建无向图
|
||||
template <class DT>
|
||||
void CreateDN(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k,weight;
|
||||
DT v1,v2;
|
||||
cout<<"请输入有向网的顶点数 "; // 1. 输入顶点数、弧数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入有向网的弧数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=INF;
|
||||
cout<<"请输入各条弧的弧尾、弧头"<<endl; // 4.创建各条弧
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条弧的弧尾、弧头和权值:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入弧的两个邻接点和弧权值
|
||||
cin>>weight;
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=weight; // 4.3 修改邻接矩阵
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjvex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=INF) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjvex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==INF ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=INF) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j,weight;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=INF;
|
||||
G.arcs[j][G.vexnum-1]=INF;
|
||||
}
|
||||
cout<<"创建弧吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入新建弧的弧尾、弧头和权值"<<endl;
|
||||
cin>>v>>w>>weight;
|
||||
InsertArc(G,v,w,weight);
|
||||
cout<<"继续创建弧吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w,int weight) // 在值为v、w顶点间加弧
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
{
|
||||
cout<<"\n顶点不存在或不合理,不能插入!"<<endl;
|
||||
return false; // 不能插入弧,返回false
|
||||
}
|
||||
if(G.arcs[i][j]!=INF) // 弧已存在,不能插入
|
||||
{
|
||||
cout<<"\n弧已存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
G.arcs[i][j]=weight;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除弧
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 弧不存在,返回false
|
||||
{
|
||||
cout<<"弧不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=INF; // 置邻接矩阵第 i 行第 j 列为零
|
||||
G.arcnum--; // 弧数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的弧
|
||||
{
|
||||
if(G.arcs[i][j]!=INF)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 先访问index
|
||||
cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
{
|
||||
if(G.arcs[v][w]!=INF && !visited[w] )
|
||||
DFS2(G,w);
|
||||
}
|
||||
//cout<<endl;
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS2(G,i); // 进行深度优先递归
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v]; // 访问顶点v
|
||||
visited[v]=true; // 做访问标志
|
||||
EnQueue(Q,v); // 入队
|
||||
while(!QueueEmpty(Q)) // 队非空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
cout<<G.vexs[w]; // 访问
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i); // 进行BFS遍历
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
128
OrigFiles/6-图/6-1-2-1-ALGraph(无向图)/ALGraph.cpp
Normal file
128
OrigFiles/6-图/6-1-2-1-ALGraph(无向图)/ALGraph.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "ALGraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 操作选择:"<<endl;
|
||||
cout<<" 1. 建立无向图"<<endl;
|
||||
cout<<" 2. 返回顶点在图中的位置"<<endl;
|
||||
cout<<" 3. 返回某位置的顶点的值"<<endl;
|
||||
cout<<" 4. 修改顶点值"<<endl;
|
||||
cout<<" 5. 增加顶点"<<endl;
|
||||
cout<<" 6. 删除顶点"<<endl;
|
||||
cout<<" 7. 增添边"<<endl;
|
||||
cout<<" 8. 删除边"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历图"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历图"<<endl;
|
||||
cout<<"11. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k;
|
||||
ALGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateUDG(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2:
|
||||
cout<<"请输入您要的所要查询位置的顶点: "; // 查询顶点位序
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在图中的位置为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 按位序查询顶点
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位置: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 修改顶点
|
||||
cout<<"请输入要更改的顶点: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修改后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5: // 新增顶点
|
||||
cout<<"请输入要增加的顶点: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应边后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6: // 删除顶点
|
||||
cout<<"请输入要删除的顶点的值:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的图为:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7: // 新增边
|
||||
cout<<"请输入要增添边的顶相邻两顶点";
|
||||
cin>>u>>v;
|
||||
InsertArc(G,u,v);
|
||||
cout<<"插入边后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8: // 删除边
|
||||
cout<<"请输入删除的边相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"边删除后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9: // 深度优先遍历
|
||||
cout<<"从第一个顶点出发深度优先遍历图的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10: // 广度优先遍历
|
||||
cout<<"从第一个顶点出发广度优先遍历图的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"无效选择,请重选!"<<endl;
|
||||
break;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
405
OrigFiles/6-图/6-1-2-1-ALGraph(无向图)/ALGraph.h
Normal file
405
OrigFiles/6-图/6-1-2-1-ALGraph(无向图)/ALGraph.h
Normal file
@@ -0,0 +1,405 @@
|
||||
/*----------------------图的邻接表示存储------------------------*/
|
||||
//无向图
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
struct ArcNode{
|
||||
int adjvex; // 该弧所指向的顶点的位置
|
||||
ArcNode *nextarc; // 指向下一条弧的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct VNode{
|
||||
DT data; // 顶点信息
|
||||
ArcNode *firstarc; // 指向第一条依附该顶点的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct ALGraph{
|
||||
VNode<DT> vertices[MAX_VEXNUM]; // 顶点集
|
||||
int vexnum; // 顶点数
|
||||
int arcnum; // 边数
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
void DispG(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
ArcNode *p;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl; // 输出顶点
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
cout<<G.vertices[i].data<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条边:"<<endl;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
if(i<p->adjvex) // 避免了无向的时候一条边被输出两次
|
||||
{
|
||||
cout<<"("<<G.vertices[i].data<<","
|
||||
<<G.vertices[p->adjvex].data<<")"<<'\t';
|
||||
}
|
||||
p = p->nextarc;
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
//算法6.4 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(ALGraph<DT> G, DT v)
|
||||
{
|
||||
for(int i=0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vertices[i].data == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//算法6.5 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDG(ALGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
ArcNode *p;
|
||||
cout<<"请输入无向图的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向图的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化顶点结点
|
||||
{
|
||||
cin>>G.vertices[i].data;
|
||||
G.vertices[i].firstarc = NULL;
|
||||
}
|
||||
for(k=0;k<G.arcnum;k++) // 构造表结点链表
|
||||
{
|
||||
cout<<"请输入边的两个顶点值: "<<endl;
|
||||
cin>>v1>>v2;
|
||||
i = LocateVex(G,v1);
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
p = new ArcNode; // 创建一个新的边
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; // 在v1链表表头插入新边结点
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode; // 创建一个新的边
|
||||
p->adjvex = i;
|
||||
p->nextarc = G.vertices[j].firstarc; // 在v2链表表头插入新边结点
|
||||
G.vertices[j].firstarc = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DestroyGraph(ALGraph<DT> G) // 销毁边结点
|
||||
{
|
||||
int i;
|
||||
ArcNode *p,*q;
|
||||
for(i = 0;i<G.vexnum;i++) // 从顶点序号为0的顶点开始依次释放掉相应的邻接表
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
q = p->nextarc;
|
||||
delete p; // 删除边结点
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
G.arcnum = 0;
|
||||
G.vexnum = 0;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(ALGraph<DT> G, int k,DT &v) // 获取第 k 个顶点的值
|
||||
{
|
||||
if(k<0||k>=G.vexnum) // 顶点不存在,返回false
|
||||
return false;
|
||||
v=G.vertices[k].data; // 顶点存在,获取第 k 个顶点的值
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(ALGraph<DT> &G, DT &u,DT v) // 修改顶点 u 的值
|
||||
{
|
||||
int k = LocateVex(G,u);
|
||||
if(k<0) // 顶点 u 不存在
|
||||
return false;
|
||||
G.vertices[k].data = v; // 重置顶点u的值
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int FirstAdjVex(ALGraph<DT> G, int u) // 求顶点 u 的第一个邻接点
|
||||
{
|
||||
ArcNode * p;
|
||||
if(u<0 || u>=G.vexnum) // 顶点 u 不存在
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 顶点u存在,有邻接点,p 为第一个邻接点位序
|
||||
if(p)
|
||||
{
|
||||
return p->adjvex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjVex(ALGraph<DT> G, int u,int w) // 求顶点 u 相对于 w 的下一个邻接点
|
||||
{
|
||||
ArcNode *p;
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum ) // 参数不合理
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 从 u 的边链表出发
|
||||
while( p && (p->adjvex!=w)) // 找 w 边结点
|
||||
{
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(!p||!p->nextarc) // 没找到 w 或 w 是最后一个顶点
|
||||
return -1;
|
||||
else // 否则,返回下一个邻接点位序
|
||||
{
|
||||
return p->nextarc->adjvex;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(ALGraph<DT> &G, DT v) // 增加顶点
|
||||
{
|
||||
char ans;
|
||||
DT w;
|
||||
int j;
|
||||
if(G.vexnum > MAX_VEXNUM) // 顶点数为最多顶点数,不能增加新顶点
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vertices[G.vexnum].data = v; // 在顶点信息表中新增顶点
|
||||
G.vertices[G.vexnum].firstarc = NULL;
|
||||
G.vexnum++; // 顶点数增1
|
||||
cout<<"创建边吗(Y/N)?"<<endl; // 创建顶点相关的边
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值:"<<endl; // 输入边另一相邻顶点
|
||||
cin>>w;
|
||||
j=LocateVex(G,w);
|
||||
if(j<0)
|
||||
cout<<"顶点不存在,不能创建边!"<<endl;
|
||||
else
|
||||
InsertArc(G,v,w);
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(ALGraph<DT> &G, DT v,DT w) // 增加边(v,w)
|
||||
{
|
||||
ArcNode *p;
|
||||
int i,j;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0 || i==j) // 顶点不存在或两端点相同,不能插入
|
||||
{
|
||||
cout<<"\n顶点不存在或两顶点相同,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=G.vertices[i].firstarc; // 边已存在,不能新增
|
||||
while(p)
|
||||
{
|
||||
if(p->adjvex==j)
|
||||
{
|
||||
cout<<"边存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
G.arcnum++; // 边数增 1
|
||||
p = new ArcNode;
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; // (v,w)边结点插在第i条链表表头
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode;
|
||||
p->adjvex = i; // (w,v)边结点插在第j链表表头
|
||||
p->nextarc = G.vertices[j].firstarc;
|
||||
G.vertices[j].firstarc = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(ALGraph<DT> &G, DT v,DT w) // 删除边(v,w)
|
||||
{
|
||||
ArcNode *p,*q;
|
||||
int i,j;
|
||||
cout<<"Hello DeleteArc!"<<endl;
|
||||
cout<<"删除边顶点为:"<<endl;
|
||||
cout<<"("<<v<<","<<w<<")"<<endl;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边(v,w)不存在,不能删除
|
||||
{
|
||||
cout<<"\n边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc; // 寻找边(v,w)的边结点
|
||||
while(p && p->adjvex!=j) // p 不空且 p 指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p&&p->adjvex ==j) // 找到边(v,w)
|
||||
{
|
||||
if(p == G.vertices[i].firstarc) // 第 1 个边结点
|
||||
{
|
||||
G.vertices[i].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第 1 个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
G.arcnum--;
|
||||
p = G.vertices[j].firstarc;
|
||||
while(p&&p->adjvex!=i) // p不空且q指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p == G.vertices[j].firstarc) // 第 1 个边结点
|
||||
{
|
||||
G.vertices[j].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第1个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
}
|
||||
cout<<"Bye-bye DeleteArc!"<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(ALGraph<DT> &G, DT v) // 删除顶点v
|
||||
{
|
||||
int i,j;
|
||||
ArcNode *p;
|
||||
DT w;
|
||||
i = LocateVex(G,v);
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p) // 删除以 v 为邻接点边
|
||||
{
|
||||
j=p->adjvex;
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
p=G.vertices[i].firstarc;
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 顶点v后面的顶点前移
|
||||
{
|
||||
G.vertices[j-1].data = G.vertices[j].data;
|
||||
G.vertices[j-1].firstarc=G.vertices[j].firstarc;
|
||||
}
|
||||
G.vexnum--; // 顶点数减一
|
||||
return true;
|
||||
}
|
||||
|
||||
// 算法6.8
|
||||
template <class DT>
|
||||
void DFS(ALGraph<DT> G, int v) // 连通图的深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 标识已访问
|
||||
cout<<G.vertices[v].data; // 访问顶点
|
||||
for(w = FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w)) // 遍历v的邻接点w
|
||||
{
|
||||
if(!visited[w]) // 未访问,调用DFS
|
||||
DFS(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(ALGraph<DT> G) // 邻接表存储的图的深度优先遍历
|
||||
{
|
||||
int i ;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行DFS
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS(G,i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 算法6.13
|
||||
template <class DT>
|
||||
void BFS(ALGraph<DT> G, int v) // 连通图的广度优先遍历
|
||||
{
|
||||
int w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
cout<<G.vertices[v].data;
|
||||
visited[v]=true;
|
||||
EnQueue(Q,v);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,v);
|
||||
p=G.vertices[v].firstarc;
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w])
|
||||
{
|
||||
cout<<G.vertices[w].data;
|
||||
visited[w]=true;
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool BFSTraverse(ALGraph<DT> G) // 邻接表存储的图的广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行BFS
|
||||
if(!visited[i])
|
||||
BFS(G,i);
|
||||
//cout<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-1-2-1-ALGraph(无向图)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-1-2-1-ALGraph(无向图)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
128
OrigFiles/6-图/6-1-2-2-ALGraph(无向网)/ALGraph.cpp
Normal file
128
OrigFiles/6-图/6-1-2-2-ALGraph(无向网)/ALGraph.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "ALGraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 操作选择:"<<endl;
|
||||
cout<<" 1. 建立无向网"<<endl;
|
||||
cout<<" 2. 返回顶点在图中的位置"<<endl;
|
||||
cout<<" 3. 返回某位置的顶点的值"<<endl;
|
||||
cout<<" 4. 修改顶点值"<<endl;
|
||||
cout<<" 5. 增加顶点"<<endl;
|
||||
cout<<" 6. 删除顶点"<<endl;
|
||||
cout<<" 7. 增添边"<<endl;
|
||||
cout<<" 8. 删除边"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历图"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历图"<<endl;
|
||||
cout<<"11. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k,weight;
|
||||
ALGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateUDN(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2:
|
||||
cout<<"请输入您要的所要查询位置的顶点: "; // 查询顶点位序
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在图中的位置为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 按位序查询顶点
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位置: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 修改顶点
|
||||
cout<<"请输入要更改的顶点: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修改后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5: // 新增顶点
|
||||
cout<<"请输入要增加的顶点: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应边后的图:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6: // 删除顶点
|
||||
cout<<"请输入要删除的顶点的值:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的图为:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7: // 新增边
|
||||
cout<<"请输入要增添边的顶相邻两顶点和边权值";
|
||||
cin>>u>>v>>weight;
|
||||
InsertArc(G,u,v,weight);
|
||||
cout<<"插入边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8: // 删除边
|
||||
cout<<"请输入删除的边相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"顶点边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9: // 深度优先遍历
|
||||
cout<<"从第一个顶点出发深度优先遍历图的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10: // 广度优先遍历
|
||||
cout<<"从第一个顶点出发广度优先遍历图的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"无效选择,请重选!"<<endl;
|
||||
break;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
409
OrigFiles/6-图/6-1-2-2-ALGraph(无向网)/ALGraph.h
Normal file
409
OrigFiles/6-图/6-1-2-2-ALGraph(无向网)/ALGraph.h
Normal file
@@ -0,0 +1,409 @@
|
||||
/*----------------------无向网的邻接表示存储------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
struct ArcNode{
|
||||
int adjvex; // 该边所指向的顶点的位置
|
||||
int weight; // 权值,设为整型
|
||||
ArcNode *nextarc; // 指向下一条边的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct VNode{
|
||||
DT data; // 顶点信息
|
||||
ArcNode *firstarc; // 指向第一条依附该顶点的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct ALGraph{
|
||||
VNode<DT> vertices[MAX_VEXNUM]; // 顶点集
|
||||
int vexnum; // 顶点数
|
||||
int arcnum; // 边数
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
void DispG(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
ArcNode *p;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl; // 输出顶点
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
cout<<G.vertices[i].data<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条边(边):"<<endl;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
if(i<p->adjvex) // 避免了无向的时候一条边被输出两次
|
||||
{
|
||||
cout<<"("<<G.vertices[i].data<<","
|
||||
<<G.vertices[p->adjvex].data<<","<<p->weight<<")"<<'\t';
|
||||
}
|
||||
p = p->nextarc;
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
//算法6.4 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(ALGraph<DT> G, DT v)
|
||||
{
|
||||
for(int i=0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vertices[i].data == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//算法6.5 创建无向网
|
||||
template <class DT>
|
||||
void CreateUDN(ALGraph<DT> &G)
|
||||
{
|
||||
int i,j,k,weight;
|
||||
DT v1,v2;
|
||||
ArcNode *p;
|
||||
cout<<"请输入无向网的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向网的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化顶点结点
|
||||
{
|
||||
cin>>G.vertices[i].data;
|
||||
G.vertices[i].firstarc = NULL;
|
||||
}
|
||||
for(k=0;k<G.arcnum;k++) //构造表结点链表
|
||||
{
|
||||
cout<<"请输入边的两个顶点值和边的权值: "<<endl;
|
||||
cin>>v1>>v2>>weight;
|
||||
i = LocateVex(G,v1);
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
p = new ArcNode; // 创建一个新的边
|
||||
p->adjvex = j;
|
||||
p->weight=weight;
|
||||
p->nextarc = G.vertices[i].firstarc; // 在v1链表表头插入新边结点
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode; // 创建一个新的边
|
||||
p->adjvex = i;
|
||||
p->weight=weight;
|
||||
p->nextarc = G.vertices[j].firstarc; // 在v2链表表头插入新边结点
|
||||
G.vertices[j].firstarc = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DestroyGraph(ALGraph<DT> G) // 销毁边结点
|
||||
{
|
||||
int i;
|
||||
ArcNode *p,*q;
|
||||
for(i = 0;i<G.vexnum;i++) // 从顶点序号为0的顶点开始依次释放掉相应的邻接表
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
q = p->nextarc;
|
||||
delete p; // 删除边结点
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
G.arcnum = 0;
|
||||
G.vexnum = 0;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(ALGraph<DT> G, int k,DT &v) // 获取第 k 个顶点的值
|
||||
{
|
||||
if(k<0||k>=G.vexnum) // 顶点不存在,返回false
|
||||
return false;
|
||||
v=G.vertices[k].data; // 顶点存在,获取第 k 个顶点的值
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(ALGraph<DT> &G, DT &u,DT v) // 修改顶点 u 的值
|
||||
{
|
||||
int k = LocateVex(G,u);
|
||||
if(k<0) // 顶点 u 不存在
|
||||
return false;
|
||||
G.vertices[k].data = v; // 重置顶点u的值
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int FirstAdjVex(ALGraph<DT> G, int u) // 求顶点 u 的第一个邻接点
|
||||
{
|
||||
ArcNode * p;
|
||||
if(u<0 || u>=G.vexnum) // 顶点 u 不存在
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 顶点u存在,有邻接点,p 为第一个邻接点位序
|
||||
if(p)
|
||||
{
|
||||
return p->adjvex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjVex(ALGraph<DT> G, int u,int w) // 求顶点 u 相对于 w 的下一个邻接点
|
||||
{
|
||||
ArcNode *p;
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum ) // 参数不合理
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 从 u 的边链表出发
|
||||
while( p && (p->adjvex!=w)) // 找 w 边结点
|
||||
{
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(!p||!p->nextarc) // 没找到 w 或 w 是最后一个顶点
|
||||
return -1;
|
||||
else // 否则,返回下一个邻接点位序
|
||||
{
|
||||
return p->nextarc->adjvex;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(ALGraph<DT> &G, DT v) // 增加顶点
|
||||
{
|
||||
int j,weight;
|
||||
char ans;
|
||||
DT w;
|
||||
if(G.vexnum > MAX_VEXNUM) // 顶点数为最多顶点数,不能增加新顶点
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vertices[G.vexnum].data = v; // 在顶点信息表中新增顶点
|
||||
G.vertices[G.vexnum].firstarc = NULL;
|
||||
G.vexnum++; // 顶点数增1
|
||||
cout<<"创建边吗(Y/N)?"<<endl; // 创建顶点相关的边
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值和边权值:"<<endl; // 输入边另一相邻顶点
|
||||
cin>>w>>weight;
|
||||
j=LocateVex(G,w);
|
||||
if(j<0)
|
||||
cout<<"顶点不存在,不能创建边!"<<endl;
|
||||
else
|
||||
InsertArc(G,v,w,weight);
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(ALGraph<DT> &G, DT v,DT w,int weight) // 增加边(v,w)
|
||||
{
|
||||
ArcNode *p;
|
||||
int i,j;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0 || i==j) // 顶点不存在或两端点相同,不能插入
|
||||
{
|
||||
cout<<"\n顶点不存在或两顶点相同,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=G.vertices[i].firstarc; // 边已存在,不能新增
|
||||
while(p)
|
||||
{
|
||||
if(p->adjvex==j)
|
||||
{
|
||||
cout<<"边存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
G.arcnum++; // 边数增 1
|
||||
p = new ArcNode;
|
||||
p->adjvex = j;
|
||||
p->weight=weight;
|
||||
p->nextarc = G.vertices[i].firstarc; // (v,w)边结点插在第i条链表表头
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode;
|
||||
p->adjvex = i; // (w,v)边结点插在第j链表表头
|
||||
p->weight=weight;
|
||||
p->nextarc = G.vertices[j].firstarc;
|
||||
G.vertices[j].firstarc = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(ALGraph<DT> &G, DT v,DT w) // 删除边(v,w)
|
||||
{
|
||||
ArcNode *p,*q;
|
||||
int i,j;
|
||||
cout<<"Hello DeleteArc!"<<endl;
|
||||
cout<<"删除边顶点为:"<<endl;
|
||||
cout<<"("<<v<<","<<w<<")"<<endl;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边(v,w)不存在,不能删除
|
||||
{
|
||||
cout<<"\n边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc; // 寻找边(v,w)的边结点
|
||||
while(p && p->adjvex!=j) // p 不空且 p 指向的不是待删边结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p&&p->adjvex ==j) // 找到边(v,w)
|
||||
{
|
||||
if(p == G.vertices[i].firstarc) // 第 1 个边结点
|
||||
{
|
||||
G.vertices[i].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第 1 个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
G.arcnum--;
|
||||
p = G.vertices[j].firstarc;
|
||||
while(p&&p->adjvex!=i) // p不空且q指向的不是待删边结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p == G.vertices[j].firstarc) // 第 1 个边结点
|
||||
{
|
||||
G.vertices[j].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第1个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
}
|
||||
cout<<"Bye-bye DeleteArc!"<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(ALGraph<DT> &G, DT v) // 删除顶点v
|
||||
{
|
||||
int i,j;
|
||||
ArcNode *p;
|
||||
DT w;
|
||||
i = LocateVex(G,v);
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p) // 删除以 v 为邻接点边
|
||||
{
|
||||
j=p->adjvex;
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
p=G.vertices[i].firstarc;
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 顶点v后面的顶点前移
|
||||
{
|
||||
G.vertices[j-1].data = G.vertices[j].data;
|
||||
G.vertices[j-1].firstarc=G.vertices[j].firstarc;
|
||||
}
|
||||
G.vexnum--; // 顶点数减一
|
||||
return true;
|
||||
}
|
||||
|
||||
// 算法6.8
|
||||
template <class DT>
|
||||
void DFS(ALGraph<DT> G, int v) // 连通网的深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 标识已访问
|
||||
cout<<G.vertices[v].data; // 访问顶点
|
||||
for(w = FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w)) // 遍历v的邻接点w
|
||||
{
|
||||
if(!visited[w]) // 未访问,调用DFS
|
||||
DFS(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(ALGraph<DT> G) // 邻接表存储的网的深度优先遍历
|
||||
{
|
||||
int i ;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行DFS
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS(G,i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 算法6.13
|
||||
template <class DT>
|
||||
void BFS(ALGraph<DT> G, int v) // 连通网的广度优先遍历
|
||||
{
|
||||
int w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
cout<<G.vertices[v].data;
|
||||
visited[v]=true;
|
||||
EnQueue(Q,v);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,v);
|
||||
p=G.vertices[v].firstarc;
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w])
|
||||
{
|
||||
cout<<G.vertices[w].data;
|
||||
visited[w]=true;
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool BFSTraverse(ALGraph<DT> G) // 邻接表存储的网的广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行BFS
|
||||
if(!visited[i])
|
||||
BFS(G,i);
|
||||
//cout<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-1-2-2-ALGraph(无向网)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-1-2-2-ALGraph(无向网)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
130
OrigFiles/6-图/6-1-2-3-ALGraph(有向图)/ALGraph.cpp
Normal file
130
OrigFiles/6-图/6-1-2-3-ALGraph(有向图)/ALGraph.cpp
Normal file
@@ -0,0 +1,130 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "ALGraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 操作选择:"<<endl;
|
||||
cout<<" 1. 建立有向图"<<endl;
|
||||
cout<<" 2. 返回顶点在图中的位置"<<endl;
|
||||
cout<<" 3. 返回某位置的顶点的值"<<endl;
|
||||
cout<<" 4. 修改顶点值"<<endl;
|
||||
cout<<" 5. 增加顶点"<<endl;
|
||||
cout<<" 6. 删除顶点"<<endl;
|
||||
cout<<" 7. 增添弧"<<endl;
|
||||
cout<<" 8. 删除弧"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历图"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历图"<<endl;
|
||||
cout<<"11. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k;
|
||||
ALGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建有向图
|
||||
CreateDN(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2:
|
||||
cout<<"请输入您要的所要查询位置的顶点: "; // 查询顶点位序
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在图中的位置为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 按位序查询顶点
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位置: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 修改顶点
|
||||
cout<<"请输入要更改的顶点: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5: // 新增顶点
|
||||
cout<<"请输入要增加的顶点: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应弧后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6: // 删除顶点
|
||||
cout<<"请输入要删除的顶点的值:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的图为:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7: // 新增弧
|
||||
cout<<"请输入要增添弧相邻两顶点和弧权值";
|
||||
cin>>u>>v;
|
||||
InsertArc(G,u,v);
|
||||
cout<<"插入弧后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8: // 删除弧
|
||||
cout<<"请输入删除的弧相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"顶点弧后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9: // 深度优先遍历
|
||||
cout<<"从第一个顶点出发深度优先遍历图的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10: // 广度优先遍历
|
||||
cout<<"从第一个顶点出发广度优先遍历图的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"无效选择,请重选!"<<endl;
|
||||
break;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
374
OrigFiles/6-图/6-1-2-3-ALGraph(有向图)/ALGraph.h
Normal file
374
OrigFiles/6-图/6-1-2-3-ALGraph(有向图)/ALGraph.h
Normal file
@@ -0,0 +1,374 @@
|
||||
/*----------------------有向图的邻接表示存储------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
struct ArcNode{
|
||||
int adjvex; // 该弧所指向的顶点的位置
|
||||
ArcNode *nextarc; // 指向下一条弧的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct VNode{
|
||||
DT data; // 顶点信息
|
||||
ArcNode *firstarc; // 指向第一条依附该顶点的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct ALGraph{
|
||||
VNode<DT> vertices[MAX_VEXNUM]; // 顶点集
|
||||
int vexnum; // 顶点数
|
||||
int arcnum; // 弧数
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
void DispG(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
ArcNode *p;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl; // 输出顶点
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
cout<<G.vertices[i].data<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条弧(弧):"<<endl;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
cout<<"("<<G.vertices[i].data<<","
|
||||
<<G.vertices[p->adjvex].data<<")"<<'\t';
|
||||
p = p->nextarc;
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
//算法6.4 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(ALGraph<DT> G, DT v)
|
||||
{
|
||||
for(int i=0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vertices[i].data == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//算法6.5 创建无向网
|
||||
template <class DT>
|
||||
void CreateDN(ALGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
ArcNode *p;
|
||||
cout<<"请输入无向网的顶点数 "; // 1. 输入顶点数、弧数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向网的弧数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化顶点结点
|
||||
{
|
||||
cin>>G.vertices[i].data;
|
||||
G.vertices[i].firstarc = NULL;
|
||||
}
|
||||
for(k=0;k<G.arcnum;k++) //构造表结点链表
|
||||
{
|
||||
cout<<"请输入弧的两个顶点值: "<<endl;
|
||||
cin>>v1>>v2;
|
||||
i = LocateVex(G,v1);
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
p = new ArcNode; // 创建一个新的弧
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; // 在v1链表表头插入新弧结点
|
||||
G.vertices[i].firstarc = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DestroyGraph(ALGraph<DT> G) // 销毁弧结点
|
||||
{
|
||||
int i;
|
||||
ArcNode *p,*q;
|
||||
for(i = 0;i<G.vexnum;i++) // 从顶点序号为0的顶点开始依次释放掉相应的邻接表
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
q = p->nextarc;
|
||||
delete p; // 删除弧结点
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
G.arcnum = 0;
|
||||
G.vexnum = 0;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(ALGraph<DT> G, int k,DT &v) // 获取第 k 个顶点的值
|
||||
{
|
||||
if(k<0||k>=G.vexnum) // 顶点不存在,返回false
|
||||
return false;
|
||||
v=G.vertices[k].data; // 顶点存在,获取第 k 个顶点的值
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(ALGraph<DT> &G, DT &u,DT v) // 修改顶点 u 的值
|
||||
{
|
||||
int k = LocateVex(G,u);
|
||||
if(k<0) // 顶点 u 不存在
|
||||
return false;
|
||||
G.vertices[k].data = v; // 重置顶点u的值
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int FirstAdjVex(ALGraph<DT> G, int u) // 求顶点 u 的第一个邻接点
|
||||
{
|
||||
ArcNode * p;
|
||||
if(u<0 || u>=G.vexnum) // 顶点 u 不存在
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 顶点u存在,有邻接点,p 为第一个邻接点位序
|
||||
if(p)
|
||||
{
|
||||
return p->adjvex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjVex(ALGraph<DT> G, int u,int w) // 求顶点 u 相对于 w 的下一个邻接点
|
||||
{
|
||||
ArcNode *p;
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum ) // 参数不合理
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 从 u 的弧链表出发
|
||||
while( p && (p->adjvex!=w)) // 找 w 弧结点
|
||||
{
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(!p||!p->nextarc) // 没找到 w 或 w 是最后一个顶点
|
||||
return -1;
|
||||
else // 否则,返回下一个邻接点位序
|
||||
{
|
||||
return p->nextarc->adjvex;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(ALGraph<DT> &G, DT v) // 增加顶点
|
||||
{
|
||||
int j;
|
||||
char ans;
|
||||
DT w;
|
||||
if(G.vexnum > MAX_VEXNUM) // 顶点数为最多顶点数,不能增加新顶点
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vertices[G.vexnum].data = v; // 在顶点信息表中新增顶点
|
||||
G.vertices[G.vexnum].firstarc = NULL;
|
||||
G.vexnum++; // 顶点数增1
|
||||
cout<<"创建弧吗(Y/N)?"<<endl; // 创建顶点相关的弧
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入弧的两顶点:"<<endl; // 输入弧另一相邻顶点
|
||||
cin>>v>>w;
|
||||
InsertArc(G,v,w);
|
||||
cout<<"继续创建弧吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(ALGraph<DT> &G, DT v,DT w) // 增加弧(v,w)
|
||||
{
|
||||
ArcNode *p;
|
||||
int i,j;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0 || i==j) // 顶点不存在或两端点相同,不能插入
|
||||
{
|
||||
cout<<"\n顶点不存在或两顶点相同,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=G.vertices[i].firstarc; // 弧已存在,不能新增
|
||||
while(p)
|
||||
{
|
||||
if(p->adjvex==j)
|
||||
{
|
||||
cout<<"弧存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
G.arcnum++; // 弧数增 1
|
||||
p = new ArcNode;
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; // (v,w)弧结点插在第i条链表表头
|
||||
G.vertices[i].firstarc = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(ALGraph<DT> &G, DT v,DT w) // 删除弧(v,w)
|
||||
{
|
||||
ArcNode *p,*q;
|
||||
int i,j;
|
||||
cout<<"Hello DeleteArc!"<<endl;
|
||||
cout<<"删除弧顶点为:"<<endl;
|
||||
cout<<"("<<v<<","<<w<<")"<<endl;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 弧(v,w)不存在,不能删除
|
||||
{
|
||||
cout<<"\n弧不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc; // 寻找弧(v,w)的弧结点
|
||||
while(p && p->adjvex!=j) // p 不空且 p 指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p&&p->adjvex ==j) // 找到弧(v,w)
|
||||
{
|
||||
if(p == G.vertices[i].firstarc) // 第 1 个弧结点
|
||||
{
|
||||
G.vertices[i].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第 1 个弧结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
G.arcnum--;
|
||||
}
|
||||
//cout<<"Bye-bye DeleteArc!"<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(ALGraph<DT> &G, DT v) // 删除顶点v
|
||||
{
|
||||
int i,j;
|
||||
ArcNode *p;
|
||||
DT w;
|
||||
i = LocateVex(G,v);
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p) // 删除以 v 为邻接点弧
|
||||
{
|
||||
j=p->adjvex;
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
p=G.vertices[i].firstarc;
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 顶点v后面的顶点前移
|
||||
{
|
||||
G.vertices[j-1].data = G.vertices[j].data;
|
||||
G.vertices[j-1].firstarc=G.vertices[j].firstarc;
|
||||
}
|
||||
G.vexnum--; // 顶点数减一
|
||||
return true;
|
||||
}
|
||||
|
||||
// 算法6.8
|
||||
template <class DT>
|
||||
void DFS(ALGraph<DT> G, int v) // 连通网的深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 标识已访问
|
||||
cout<<G.vertices[v].data; // 访问顶点
|
||||
for(w = FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w)) // 遍历v的邻接点w
|
||||
{
|
||||
if(!visited[w]) // 未访问,调用DFS
|
||||
DFS(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(ALGraph<DT> G) // 邻接表存储的网的深度优先遍历
|
||||
{
|
||||
int i ;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行DFS
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS(G,i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 算法6.13
|
||||
template <class DT>
|
||||
void BFS(ALGraph<DT> G, int v) // 连通网的广度优先遍历
|
||||
{
|
||||
int w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
cout<<G.vertices[v].data;
|
||||
visited[v]=true;
|
||||
EnQueue(Q,v);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,v);
|
||||
p=G.vertices[v].firstarc;
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w])
|
||||
{
|
||||
cout<<G.vertices[w].data;
|
||||
visited[w]=true;
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool BFSTraverse(ALGraph<DT> G) // 邻接表存储的网的广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行BFS
|
||||
if(!visited[i])
|
||||
BFS(G,i);
|
||||
//cout<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
113
OrigFiles/6-图/6-1-2-3-ALGraph(有向图)/LinkQueue.h
Normal file
113
OrigFiles/6-图/6-1-2-3-ALGraph(有向图)/LinkQueue.h
Normal file
@@ -0,0 +1,113 @@
|
||||
|
||||
// 链队
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
128
OrigFiles/6-图/6-1-2-4-ALGraph(有向网)/ALGraph.cpp
Normal file
128
OrigFiles/6-图/6-1-2-4-ALGraph(有向网)/ALGraph.cpp
Normal file
@@ -0,0 +1,128 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "ALGraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 操作选择:"<<endl;
|
||||
cout<<" 1. 建立有向网"<<endl;
|
||||
cout<<" 2. 返回顶点在图中的位置"<<endl;
|
||||
cout<<" 3. 返回某位置的顶点的值"<<endl;
|
||||
cout<<" 4. 修改顶点值"<<endl;
|
||||
cout<<" 5. 增加顶点"<<endl;
|
||||
cout<<" 6. 删除顶点"<<endl;
|
||||
cout<<" 7. 增添弧"<<endl;
|
||||
cout<<" 8. 删除弧"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历图"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历图"<<endl;
|
||||
cout<<"11. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k,weight;
|
||||
ALGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateUDN(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2:
|
||||
cout<<"请输入您要的所要查询位置的顶点: "; // 查询顶点位序
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在图中的位置为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 按位序查询顶点
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位置: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 修改顶点
|
||||
cout<<"请输入要更改的顶点: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5: // 新增顶点
|
||||
cout<<"请输入要增加的顶点: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应弧后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6: // 删除顶点
|
||||
cout<<"请输入要删除的顶点的值:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的图为:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7: // 新增弧
|
||||
cout<<"请输入要增添弧相邻两顶点和弧权值";
|
||||
cin>>u>>v>>weight;
|
||||
InsertArc(G,u,v,weight);
|
||||
cout<<"插入弧后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8: // 删除弧
|
||||
cout<<"请输入删除的弧相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"顶点弧后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9: // 深度优先遍历
|
||||
cout<<"从第一个顶点出发深度优先遍历图的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10: // 广度优先遍历
|
||||
cout<<"从第一个顶点出发广度优先遍历图的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"无效选择,请重选!"<<endl;
|
||||
break;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
377
OrigFiles/6-图/6-1-2-4-ALGraph(有向网)/ALGraph.h
Normal file
377
OrigFiles/6-图/6-1-2-4-ALGraph(有向网)/ALGraph.h
Normal file
@@ -0,0 +1,377 @@
|
||||
/*----------------------有向网的邻接表示存储------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
struct ArcNode{
|
||||
int adjvex; // 该弧所指向的顶点的位置
|
||||
int weight; // 权值,设为整型
|
||||
ArcNode *nextarc; // 指向下一条弧的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct VNode{
|
||||
DT data; // 顶点信息
|
||||
ArcNode *firstarc; // 指向第一条依附该顶点的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct ALGraph{
|
||||
VNode<DT> vertices[MAX_VEXNUM]; // 顶点集
|
||||
int vexnum; // 顶点数
|
||||
int arcnum; // 弧数
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
void DispG(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
ArcNode *p;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl; // 输出顶点
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
cout<<G.vertices[i].data<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条弧(弧):"<<endl;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
cout<<"("<<G.vertices[i].data<<","
|
||||
<<G.vertices[p->adjvex].data<<","<<p->weight<<")"<<'\t';
|
||||
p = p->nextarc;
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
//算法6.4 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(ALGraph<DT> G, DT v)
|
||||
{
|
||||
for(int i=0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vertices[i].data == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//算法6.5 创建无向网
|
||||
template <class DT>
|
||||
void CreateUDN(ALGraph<DT> &G)
|
||||
{
|
||||
int i,j,k,weight;
|
||||
DT v1,v2;
|
||||
ArcNode *p;
|
||||
cout<<"请输入无向网的顶点数 "; // 1. 输入顶点数、弧数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向网的弧数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化顶点结点
|
||||
{
|
||||
cin>>G.vertices[i].data;
|
||||
G.vertices[i].firstarc = NULL;
|
||||
}
|
||||
for(k=0;k<G.arcnum;k++) //构造表结点链表
|
||||
{
|
||||
cout<<"请输入弧的两个顶点值和弧的权值: "<<endl;
|
||||
cin>>v1>>v2>>weight;
|
||||
i = LocateVex(G,v1);
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
p = new ArcNode; // 创建一个新的弧
|
||||
p->adjvex = j;
|
||||
p->weight=weight;
|
||||
p->nextarc = G.vertices[i].firstarc; // 在v1链表表头插入新弧结点
|
||||
G.vertices[i].firstarc = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DestroyGraph(ALGraph<DT> G) // 销毁弧结点
|
||||
{
|
||||
int i;
|
||||
ArcNode *p,*q;
|
||||
for(i = 0;i<G.vexnum;i++) // 从顶点序号为0的顶点开始依次释放掉相应的邻接表
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
q = p->nextarc;
|
||||
delete p; // 删除弧结点
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
G.arcnum = 0;
|
||||
G.vexnum = 0;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(ALGraph<DT> G, int k,DT &v) // 获取第 k 个顶点的值
|
||||
{
|
||||
if(k<0||k>=G.vexnum) // 顶点不存在,返回false
|
||||
return false;
|
||||
v=G.vertices[k].data; // 顶点存在,获取第 k 个顶点的值
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(ALGraph<DT> &G, DT &u,DT v) // 修改顶点 u 的值
|
||||
{
|
||||
int k = LocateVex(G,u);
|
||||
if(k<0) // 顶点 u 不存在
|
||||
return false;
|
||||
G.vertices[k].data = v; // 重置顶点u的值
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int FirstAdjVex(ALGraph<DT> G, int u) // 求顶点 u 的第一个邻接点
|
||||
{
|
||||
ArcNode * p;
|
||||
if(u<0 || u>=G.vexnum) // 顶点 u 不存在
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 顶点u存在,有邻接点,p 为第一个邻接点位序
|
||||
if(p)
|
||||
{
|
||||
return p->adjvex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjVex(ALGraph<DT> G, int u,int w) // 求顶点 u 相对于 w 的下一个邻接点
|
||||
{
|
||||
ArcNode *p;
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum ) // 参数不合理
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 从 u 的弧链表出发
|
||||
while( p && (p->adjvex!=w)) // 找 w 弧结点
|
||||
{
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(!p||!p->nextarc) // 没找到 w 或 w 是最后一个顶点
|
||||
return -1;
|
||||
else // 否则,返回下一个邻接点位序
|
||||
{
|
||||
return p->nextarc->adjvex;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(ALGraph<DT> &G, DT v) // 增加顶点
|
||||
{
|
||||
int j,weight;
|
||||
char ans;
|
||||
DT w;
|
||||
if(G.vexnum > MAX_VEXNUM) // 顶点数为最多顶点数,不能增加新顶点
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vertices[G.vexnum].data = v; // 在顶点信息表中新增顶点
|
||||
G.vertices[G.vexnum].firstarc = NULL;
|
||||
G.vexnum++; // 顶点数增1
|
||||
cout<<"创建弧吗(Y/N)?"<<endl; // 创建顶点相关的弧
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入弧的两顶点和权值:"<<endl; // 输入弧另一相邻顶点
|
||||
cin>>v>>w>>weight;
|
||||
InsertArc(G,v,w,weight);
|
||||
cout<<"继续创建弧吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(ALGraph<DT> &G, DT v,DT w,int weight) // 增加弧(v,w)
|
||||
{
|
||||
ArcNode *p;
|
||||
int i,j;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0 || i==j) // 顶点不存在或两端点相同,不能插入
|
||||
{
|
||||
cout<<"\n顶点不存在或两顶点相同,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=G.vertices[i].firstarc; // 弧已存在,不能新增
|
||||
while(p)
|
||||
{
|
||||
if(p->adjvex==j)
|
||||
{
|
||||
cout<<"弧存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
G.arcnum++; // 弧数增 1
|
||||
p = new ArcNode;
|
||||
p->adjvex = j;
|
||||
p->weight=weight;
|
||||
p->nextarc = G.vertices[i].firstarc; // (v,w)弧结点插在第i条链表表头
|
||||
G.vertices[i].firstarc = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(ALGraph<DT> &G, DT v,DT w) // 删除弧(v,w)
|
||||
{
|
||||
ArcNode *p,*q;
|
||||
int i,j;
|
||||
cout<<"Hello DeleteArc!"<<endl;
|
||||
cout<<"删除弧顶点为:"<<endl;
|
||||
cout<<"("<<v<<","<<w<<")"<<endl;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 弧(v,w)不存在,不能删除
|
||||
{
|
||||
cout<<"\n弧不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc; // 寻找弧(v,w)的弧结点
|
||||
while(p && p->adjvex!=j) // p 不空且 p 指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p&&p->adjvex ==j) // 找到弧(v,w)
|
||||
{
|
||||
if(p == G.vertices[i].firstarc) // 第 1 个弧结点
|
||||
{
|
||||
G.vertices[i].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第 1 个弧结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
G.arcnum--;
|
||||
}
|
||||
//cout<<"Bye-bye DeleteArc!"<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(ALGraph<DT> &G, DT v) // 删除顶点v
|
||||
{
|
||||
int i,j;
|
||||
ArcNode *p;
|
||||
DT w;
|
||||
i = LocateVex(G,v);
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p) // 删除以 v 为邻接点弧
|
||||
{
|
||||
j=p->adjvex;
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
p=G.vertices[i].firstarc;
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 顶点v后面的顶点前移
|
||||
{
|
||||
G.vertices[j-1].data = G.vertices[j].data;
|
||||
G.vertices[j-1].firstarc=G.vertices[j].firstarc;
|
||||
}
|
||||
G.vexnum--; // 顶点数减一
|
||||
return true;
|
||||
}
|
||||
|
||||
// 算法6.8
|
||||
template <class DT>
|
||||
void DFS(ALGraph<DT> G, int v) // 连通网的深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 标识已访问
|
||||
cout<<G.vertices[v].data; // 访问顶点
|
||||
for(w = FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w)) // 遍历v的邻接点w
|
||||
{
|
||||
if(!visited[w]) // 未访问,调用DFS
|
||||
DFS(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(ALGraph<DT> G) // 邻接表存储的网的深度优先遍历
|
||||
{
|
||||
int i ;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行DFS
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS(G,i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 算法6.13
|
||||
template <class DT>
|
||||
void BFS(ALGraph<DT> G, int v) // 连通网的广度优先遍历
|
||||
{
|
||||
int w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
cout<<G.vertices[v].data;
|
||||
visited[v]=true;
|
||||
EnQueue(Q,v);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,v);
|
||||
p=G.vertices[v].firstarc;
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w])
|
||||
{
|
||||
cout<<G.vertices[w].data;
|
||||
visited[w]=true;
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool BFSTraverse(ALGraph<DT> G) // 邻接表存储的网的广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行BFS
|
||||
if(!visited[i])
|
||||
BFS(G,i);
|
||||
//cout<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-1-2-4-ALGraph(有向网)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-1-2-4-ALGraph(有向网)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
112
OrigFiles/6-图/6-3-1-MGTraverseApp/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-3-1-MGTraverseApp/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
107
OrigFiles/6-图/6-3-1-MGTraverseApp/MGTraverseApp.cpp
Normal file
107
OrigFiles/6-图/6-3-1-MGTraverseApp/MGTraverseApp.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
//#include<string>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "MGraph.h"
|
||||
#include "LinkQueue.h"
|
||||
using namespace std;
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立图"<<endl;
|
||||
cout<<" 2. 判断两顶点的连通性"<<endl;
|
||||
cout<<" 3. 判断图的连通性"<<endl;
|
||||
cout<<" 4. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//算法6.14 判断两顶点是否连通
|
||||
template<class DT>
|
||||
bool IsConected(MGraph<DT> G, int i, int j)
|
||||
{
|
||||
int k;
|
||||
for(k=0;k<G.vexnum;k++)
|
||||
visited[i]=false;
|
||||
DFS2(G,i);
|
||||
if(visited[j]==false)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 算法6.15 判断图的连通性
|
||||
template<class DT>
|
||||
bool IsGraphConected(MGraph<DT> G)
|
||||
{
|
||||
int i,flag=1;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
DFS2(G,0); // 遍历图
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
if(visited[i]==0) // 如果未遍历到所有顶点
|
||||
{
|
||||
flag=0;break; // 图不连通
|
||||
}
|
||||
return flag; // 否则,图连通
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int i,j,k;
|
||||
MGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateUDG(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // 判断两顶点的连通性
|
||||
cout<<"请输入两顶点值: ";
|
||||
cin>>u>>v;
|
||||
i=LocateVex(G,u);
|
||||
j=LocateVex(G,v);
|
||||
if(i==-1 ||j==-1 || i==j) // 顶点不存在
|
||||
cout<<"\n顶点不存在或两顶点相同 "<<endl;
|
||||
else
|
||||
{
|
||||
if(IsConected(G,i,j))
|
||||
cout<<"\n"<<u<<"和"<<v<<"之间连通!"<<endl;
|
||||
else
|
||||
cout<<"\n"<<u<<"和"<<v<<"之间不连通!"<<endl;
|
||||
}
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 判断图的连通性
|
||||
if(IsGraphConected(G))
|
||||
cout<<"\n此图连通! "<<v<<endl;
|
||||
else
|
||||
cout<<"\n此图不连通!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"\n结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"\n选择不合理,请重选!"<<endl;
|
||||
}
|
||||
}while(choice!=0);
|
||||
}
|
||||
299
OrigFiles/6-图/6-3-1-MGTraverseApp/Mgraph.h
Normal file
299
OrigFiles/6-图/6-3-1-MGTraverseApp/Mgraph.h
Normal file
@@ -0,0 +1,299 @@
|
||||
/*--------------------------无向图的邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和边数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条边信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=i+1;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<")"<<'\t';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDG(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
cout<<"请输入无向图的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向图的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=0;
|
||||
cout<<"请输入各条边的两个邻接点"<<endl; // 4.创建各条边
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条边的两个顶点:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入边的两个邻接点
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=1; // 4.3 修改邻接矩阵
|
||||
G.arcs[j][i]=1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjvex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjvex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==0 ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=0;
|
||||
G.arcs[j][G.vexnum-1]=0;
|
||||
}
|
||||
cout<<"创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值"<<endl;
|
||||
cin>>w;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在
|
||||
InsertArc(G,v,w);
|
||||
else
|
||||
cout<<w<<"顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w) // 在值为v、w顶点间加边
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
return false; // 不能插入边,返回false
|
||||
G.arcs[i][j]=1;
|
||||
G.arcs[j][i]=1;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除边
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边不存在,返回false
|
||||
{
|
||||
cout<<"边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=0; // 置邻接矩阵第 i 行第 j 列为零
|
||||
G.arcs[j][i]=0; // 置邻接矩阵第 i 列第 j 行为零
|
||||
G.arcnum--; // 边数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的边
|
||||
{
|
||||
if(G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 先访问index
|
||||
//cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
{
|
||||
if(G.arcs[v][w]!=0 && !visited[w] )
|
||||
DFS2(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS2(G,i); // 进行深度优先递归
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v]; // 访问顶点v
|
||||
visited[v]=true; // 做访问标志
|
||||
EnQueue(Q,v); // 入队
|
||||
while(!QueueEmpty(Q)) // 队非空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
cout<<G.vexs[w]; // 访问
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=false;
|
||||
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i); // 进行BFS遍历
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
132
OrigFiles/6-图/6-3-2-ALGTraverseApp/ALGTraverseApp.cpp
Normal file
132
OrigFiles/6-图/6-3-2-ALGTraverseApp/ALGTraverseApp.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
//#include<string>
|
||||
#include <iostream>
|
||||
#include "ALGraph.h"
|
||||
#include "LinkQueue.h"
|
||||
using namespace std;
|
||||
|
||||
void DispMenu()图的连通信息
|
||||
{
|
||||
cout<<"\n请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立无向图"<<endl;
|
||||
cout<<" 2. 图的连通信息"<<endl;
|
||||
cout<<" 3. 求顶点v最远点"<<endl;
|
||||
cout<<" 4. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//算法6.16
|
||||
template<class DT>
|
||||
void DFS3(ALGraph<DT> G,int v) // 连接表存储的图的深度优先遍历
|
||||
{
|
||||
int w;
|
||||
ArcNode* p;
|
||||
visited[v]=true; // 做访问标志
|
||||
cout<<G.vertices[v].data; // 输出顶点
|
||||
p=G.vertices[v].firstarc; // 找第一未访问邻接点
|
||||
while(p) // 顶点非空
|
||||
{
|
||||
w=p->adjvex; // 未被访问过
|
||||
if(!visited[w])
|
||||
DFS3(G,w); // DFS遍历
|
||||
p=p->nextarc; // 新启点,DFS遍历
|
||||
}
|
||||
}
|
||||
|
||||
template<class DT>
|
||||
void ConnectVex(ALGraph<DT> G) // 图的连通信息
|
||||
{
|
||||
int k,num=0; // num连通分量计数
|
||||
for(k=0;k<G.vexnum;k++) // 访问标志初始化
|
||||
visited[k]=false;
|
||||
for(k=0;k<G.vexnum;k++) // 连通图遍历调用次数为连通分量数
|
||||
if(!visited[k])
|
||||
{
|
||||
num++;
|
||||
cout<<"\n第"<<num<<"个连通分量序列为:";
|
||||
DFS3(G,k);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 算法6.17 求距离最远顶点
|
||||
template<class DT>
|
||||
int Maxdist( ALGraph<DT> G, int v)
|
||||
{
|
||||
int i,w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=false;
|
||||
EnQueue(Q,v); // v入队
|
||||
visited[v]=true; // 做访问标志
|
||||
while(!QueueEmpty(Q)) // 队不空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
p=G.vertices[v].firstarc; // 遍历 v 的邻接点
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
p=p->nextarc; // 下一个邻接点
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k;
|
||||
ALGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateUDG(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // 图的连通信息
|
||||
ConnectVex(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 求距离最远顶点
|
||||
cout<<"\n输入顶点信息v:"<<endl;
|
||||
cin>>v;
|
||||
k=LocateVex(G,v);
|
||||
if(k==-1)
|
||||
cout<<"\n顶点"<<v<<"不存在!"<<endl;
|
||||
else
|
||||
{
|
||||
k=Maxdist(G, k);
|
||||
GetVex(G,k,u);
|
||||
cout<<"离"<<v<<"的最远点为"<<u<<endl;
|
||||
}
|
||||
break;
|
||||
case 4: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"\n结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"\n无效选择,请重选!"<<endl;
|
||||
}
|
||||
}while(choice!=0);
|
||||
}
|
||||
405
OrigFiles/6-图/6-3-2-ALGTraverseApp/ALGraph.h
Normal file
405
OrigFiles/6-图/6-3-2-ALGTraverseApp/ALGraph.h
Normal file
@@ -0,0 +1,405 @@
|
||||
/*----------------------图的邻接表示存储------------------------*/
|
||||
//无向图
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
struct ArcNode{
|
||||
int adjvex; // 该弧所指向的顶点的位置
|
||||
ArcNode *nextarc; // 指向下一条弧的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct VNode{
|
||||
DT data; // 顶点信息
|
||||
ArcNode *firstarc; // 指向第一条依附该顶点的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct ALGraph{
|
||||
VNode<DT> vertices[MAX_VEXNUM]; //顶点集
|
||||
int vexnum;//顶点数
|
||||
int arcnum;//边数
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
void DispG(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
ArcNode *p;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl; //输出顶点
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
cout<<G.vertices[i].data<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条弧(边):"<<endl;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
if(i<p->adjvex) //避免了无向的时候一条边被输出两次
|
||||
{
|
||||
cout<<"("<<G.vertices[i].data<<","
|
||||
<<G.vertices[p->adjvex].data<<")"<<'\t';
|
||||
}
|
||||
p = p->nextarc;
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
//算法6.4 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(ALGraph<DT> G, DT v)
|
||||
{
|
||||
for(int i=0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vertices[i].data == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//算法6.5 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDG(ALGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
ArcNode *p;
|
||||
cout<<"请输入无向图的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向图的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化顶点结点
|
||||
{
|
||||
cin>>G.vertices[i].data;
|
||||
G.vertices[i].firstarc = NULL;
|
||||
}
|
||||
for(k=0;k<G.arcnum;k++) //构造表结点链表
|
||||
{
|
||||
cout<<"请输入边的两个顶点值: "<<endl;
|
||||
cin>>v1>>v2;
|
||||
i = LocateVex(G,v1);
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
p = new ArcNode; // 创建一个新的边
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; // 在v1链表表头插入新边结点
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode; // 创建一个新的边
|
||||
p->adjvex = i;
|
||||
p->nextarc = G.vertices[j].firstarc; // 在v2链表表头插入新边结点
|
||||
G.vertices[j].firstarc = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DestroyGraph(ALGraph<DT> G) // 销毁边结点
|
||||
{
|
||||
int i;
|
||||
ArcNode *p,*q;
|
||||
for(i = 0;i<G.vexnum;i++) // 从顶点序号为0的顶点开始依次释放掉相应的邻接表
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
q = p->nextarc;
|
||||
delete p; // 删除边结点
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
G.arcnum = 0;
|
||||
G.vexnum = 0;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(ALGraph<DT> G, int k,DT &v) // 获取第 k 个顶点的值
|
||||
{
|
||||
if(k<0||k>=G.vexnum) // 顶点不存在,返回false
|
||||
return false;
|
||||
v=G.vertices[k].data; // 顶点存在,获取第 k 个顶点的值
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(ALGraph<DT> &G, DT &u,DT v) // 修改顶点 u 的值
|
||||
{
|
||||
int k = LocateVex(G,u);
|
||||
if(k<0) // 顶点 u 不存在
|
||||
return false;
|
||||
G.vertices[k].data = v; // 重置顶点u的值
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int FirstAdjVex(ALGraph<DT> G, int u) // 求顶点 u 的第一个邻接点
|
||||
{
|
||||
ArcNode * p;
|
||||
if(u<0 || u>=G.vexnum) // 顶点 u 不存在
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 顶点u存在,有邻接点,p 为第一个邻接点位序
|
||||
if(p)
|
||||
{
|
||||
return p->adjvex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjVex(ALGraph<DT> G, int u,int w) // 求顶点 u 相对于 w 的下一个邻接点
|
||||
{
|
||||
ArcNode *p;
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum ) // 参数不合理
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 从 u 的边链表出发
|
||||
while( p && (p->adjvex!=w)) // 找 w 边结点
|
||||
{
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(!p||!p->nextarc) // 没找到 w 或 w 是最后一个顶点
|
||||
return -1;
|
||||
else // 否则,返回下一个邻接点位序
|
||||
{
|
||||
return p->nextarc->adjvex;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(ALGraph<DT> &G, DT v) // 增加顶点
|
||||
{
|
||||
int j;
|
||||
char ans;
|
||||
DT w;
|
||||
if(G.vexnum > MAX_VEXNUM) // 顶点数为最多顶点数,不能增加新顶点
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vertices[G.vexnum].data = v; // 在顶点信息表中新增顶点
|
||||
G.vertices[G.vexnum].firstarc = NULL;
|
||||
G.vexnum++; // 顶点数增1
|
||||
cout<<"创建边吗(Y/N)?"<<endl; // 创建顶点相关的边
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值:"<<endl; // 输入边另一相邻顶点
|
||||
cin>>w;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在,增加边
|
||||
InsertArc(G,v,w);
|
||||
else
|
||||
cout<<w<<"\n顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(ALGraph<DT> &G, DT v,DT w) // 增加边(v,w)
|
||||
{
|
||||
ArcNode *p;
|
||||
int i,j;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0 || i==j) // 顶点不存在或两端点相同,不能插入
|
||||
{
|
||||
cout<<"\n顶点不存在或两顶点相同,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=G.vertices[i].firstarc; // 边已存在,不能新增
|
||||
while(p)
|
||||
{
|
||||
if(p->adjvex==j)
|
||||
{
|
||||
cout<<"边存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
G.arcnum++; // 边数增 1
|
||||
p = new ArcNode;
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; // (v,w)边结点插在第i条链表表头
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode;
|
||||
p->adjvex = i; // (w,v)边结点插在第j链表表头
|
||||
p->nextarc = G.vertices[j].firstarc;
|
||||
G.vertices[j].firstarc = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(ALGraph<DT> &G, DT v,DT w) // 删除边(v,w)
|
||||
{
|
||||
ArcNode *p,*q;
|
||||
int i,j;
|
||||
cout<<"Hello DeleteArc!"<<endl;
|
||||
cout<<"删除边顶点为:"<<endl;
|
||||
cout<<"("<<v<<","<<w<<")"<<endl;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边(v,w)不存在,不能删除
|
||||
{
|
||||
cout<<"\n边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc; // 寻找边(v,w)的边结点
|
||||
while(p && p->adjvex!=j) // p 不空且 p 指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p&&p->adjvex ==j) // 找到边(v,w)
|
||||
{
|
||||
if(p == G.vertices[i].firstarc) // 第 1 个边结点
|
||||
{
|
||||
G.vertices[i].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第 1 个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
G.arcnum--;
|
||||
p = G.vertices[j].firstarc;
|
||||
while(p&&p->adjvex!=i) // p不空且q指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p == G.vertices[j].firstarc) // 第 1 个边结点
|
||||
{
|
||||
G.vertices[j].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第1个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
}
|
||||
cout<<"Bye-bye DeleteArc!"<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(ALGraph<DT> &G, DT v) // 删除顶点v
|
||||
{
|
||||
int i,j;
|
||||
ArcNode *p;
|
||||
DT w;
|
||||
i = LocateVex(G,v);
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p) // 删除以 v 为邻接点边
|
||||
{
|
||||
j=p->adjvex;
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
p=G.vertices[i].firstarc;
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 顶点v后面的顶点前移
|
||||
{
|
||||
G.vertices[j-1].data = G.vertices[j].data;
|
||||
G.vertices[j-1].firstarc=G.vertices[j].firstarc;
|
||||
}
|
||||
G.vexnum--; // 顶点数减一
|
||||
return true;
|
||||
}
|
||||
|
||||
// 算法6.8
|
||||
template <class DT>
|
||||
void DFS(ALGraph<DT> G, int v) // 连通图的深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 标识已访问
|
||||
cout<<G.vertices[v].data; // 访问顶点
|
||||
for(w = FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w)) // 遍历v的邻接点w
|
||||
{
|
||||
if(!visited[w]) // 未访问,调用DFS
|
||||
DFS(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(ALGraph<DT> G) // 邻接表存储的图的深度优先遍历
|
||||
{
|
||||
int i ;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行DFS
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS(G,i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 算法6.13
|
||||
template <class DT>
|
||||
void BFS(ALGraph<DT> G, int v) // 连通图的广度优先遍历
|
||||
{
|
||||
int w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
cout<<G.vertices[v].data;
|
||||
visited[v]=true;
|
||||
EnQueue(Q,v);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,v);
|
||||
p=G.vertices[v].firstarc;
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w])
|
||||
{
|
||||
cout<<G.vertices[w].data;
|
||||
visited[w]=true;
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool BFSTraverse(ALGraph<DT> G) // 邻接表存储的图的广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行BFS
|
||||
if(!visited[i])
|
||||
BFS(G,i);
|
||||
//cout<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-3-2-ALGTraverseApp/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-3-2-ALGTraverseApp/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
132
OrigFiles/6-图/6-3-ALGTraverseApp/ALGTraverseApp.cpp
Normal file
132
OrigFiles/6-图/6-3-ALGTraverseApp/ALGTraverseApp.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
//#include<string>
|
||||
#include <iostream>
|
||||
#include "ALGraph.h"
|
||||
#include "LinkQueue.h"
|
||||
using namespace std;
|
||||
|
||||
void DispMenu()图的连通信息
|
||||
{
|
||||
cout<<"\n请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立无向图"<<endl;
|
||||
cout<<" 2. 图的连通信息"<<endl;
|
||||
cout<<" 3. 求顶点v最远点"<<endl;
|
||||
cout<<" 4. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//算法6.16
|
||||
template<class DT>
|
||||
void DFS3(ALGraph<DT> G,int v) // 连接表存储的图的深度优先遍历
|
||||
{
|
||||
int w;
|
||||
ArcNode* p;
|
||||
visited[v]=true; // 做访问标志
|
||||
cout<<G.vertices[v].data; // 输出顶点
|
||||
p=G.vertices[v].firstarc; // 找第一未访问邻接点
|
||||
while(p) // 顶点非空
|
||||
{
|
||||
w=p->adjvex; // 未被访问过
|
||||
if(!visited[w])
|
||||
DFS3(G,w); // DFS遍历
|
||||
p=p->nextarc; // 新启点,DFS遍历
|
||||
}
|
||||
}
|
||||
|
||||
template<class DT>
|
||||
void ConnectVex(ALGraph<DT> G) // 图的连通信息
|
||||
{
|
||||
int k,num=0; // num连通分量计数
|
||||
for(k=0;k<G.vexnum;k++) // 访问标志初始化
|
||||
visited[k]=false;
|
||||
for(k=0;k<G.vexnum;k++) // 连通图遍历调用次数为连通分量数
|
||||
if(!visited[k])
|
||||
{
|
||||
num++;
|
||||
cout<<"\n第"<<num<<"个连通分量序列为:";
|
||||
DFS3(G,k);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 算法6.17 求距离最远顶点
|
||||
template<class DT>
|
||||
int Maxdist( ALGraph<DT> G, int v)
|
||||
{
|
||||
int i,w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=false;
|
||||
EnQueue(Q,v); // v入队
|
||||
visited[v]=true; // 做访问标志
|
||||
while(!QueueEmpty(Q)) // 队不空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
p=G.vertices[v].firstarc; // 遍历 v 的邻接点
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
p=p->nextarc; // 下一个邻接点
|
||||
}
|
||||
}
|
||||
return v;
|
||||
}
|
||||
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k;
|
||||
ALGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateUDG(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // 图的连通信息
|
||||
ConnectVex(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 求距离最远顶点
|
||||
cout<<"\n输入顶点信息v:"<<endl;
|
||||
cin>>v;
|
||||
k=LocateVex(G,v);
|
||||
if(k==-1)
|
||||
cout<<"\n顶点"<<v<<"不存在!"<<endl;
|
||||
else
|
||||
{
|
||||
k=Maxdist(G, k);
|
||||
GetVex(G,k,u);
|
||||
cout<<"离"<<v<<"的最远点为"<<u<<endl;
|
||||
}
|
||||
break;
|
||||
case 4: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"\n结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"\n无效选择,请重选!"<<endl;
|
||||
}
|
||||
}while(choice!=0);
|
||||
}
|
||||
405
OrigFiles/6-图/6-3-ALGTraverseApp/ALGraph.h
Normal file
405
OrigFiles/6-图/6-3-ALGTraverseApp/ALGraph.h
Normal file
@@ -0,0 +1,405 @@
|
||||
/*----------------------图的邻接表示存储------------------------*/
|
||||
//无向图
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
struct ArcNode{
|
||||
int adjvex; // 该弧所指向的顶点的位置
|
||||
ArcNode *nextarc; // 指向下一条弧的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct VNode{
|
||||
DT data; // 顶点信息
|
||||
ArcNode *firstarc; // 指向第一条依附该顶点的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct ALGraph{
|
||||
VNode<DT> vertices[MAX_VEXNUM]; //顶点集
|
||||
int vexnum;//顶点数
|
||||
int arcnum;//边数
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
void DispG(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
ArcNode *p;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl; //输出顶点
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
cout<<G.vertices[i].data<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条弧(边):"<<endl;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
if(i<p->adjvex) //避免了无向的时候一条边被输出两次
|
||||
{
|
||||
cout<<"("<<G.vertices[i].data<<","
|
||||
<<G.vertices[p->adjvex].data<<")"<<'\t';
|
||||
}
|
||||
p = p->nextarc;
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
//算法6.4 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(ALGraph<DT> G, DT v)
|
||||
{
|
||||
for(int i=0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vertices[i].data == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//算法6.5 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDG(ALGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
ArcNode *p;
|
||||
cout<<"请输入无向图的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向图的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化顶点结点
|
||||
{
|
||||
cin>>G.vertices[i].data;
|
||||
G.vertices[i].firstarc = NULL;
|
||||
}
|
||||
for(k=0;k<G.arcnum;k++) //构造表结点链表
|
||||
{
|
||||
cout<<"请输入边的两个顶点值: "<<endl;
|
||||
cin>>v1>>v2;
|
||||
i = LocateVex(G,v1);
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
p = new ArcNode; // 创建一个新的边
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; // 在v1链表表头插入新边结点
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode; // 创建一个新的边
|
||||
p->adjvex = i;
|
||||
p->nextarc = G.vertices[j].firstarc; // 在v2链表表头插入新边结点
|
||||
G.vertices[j].firstarc = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DestroyGraph(ALGraph<DT> G) // 销毁边结点
|
||||
{
|
||||
int i;
|
||||
ArcNode *p,*q;
|
||||
for(i = 0;i<G.vexnum;i++) // 从顶点序号为0的顶点开始依次释放掉相应的邻接表
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
q = p->nextarc;
|
||||
delete p; // 删除边结点
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
G.arcnum = 0;
|
||||
G.vexnum = 0;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(ALGraph<DT> G, int k,DT &v) // 获取第 k 个顶点的值
|
||||
{
|
||||
if(k<0||k>=G.vexnum) // 顶点不存在,返回false
|
||||
return false;
|
||||
v=G.vertices[k].data; // 顶点存在,获取第 k 个顶点的值
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(ALGraph<DT> &G, DT &u,DT v) // 修改顶点 u 的值
|
||||
{
|
||||
int k = LocateVex(G,u);
|
||||
if(k<0) // 顶点 u 不存在
|
||||
return false;
|
||||
G.vertices[k].data = v; // 重置顶点u的值
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int FirstAdjVex(ALGraph<DT> G, int u) // 求顶点 u 的第一个邻接点
|
||||
{
|
||||
ArcNode * p;
|
||||
if(u<0 || u>=G.vexnum) // 顶点 u 不存在
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 顶点u存在,有邻接点,p 为第一个邻接点位序
|
||||
if(p)
|
||||
{
|
||||
return p->adjvex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjVex(ALGraph<DT> G, int u,int w) // 求顶点 u 相对于 w 的下一个邻接点
|
||||
{
|
||||
ArcNode *p;
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum ) // 参数不合理
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc; // 从 u 的边链表出发
|
||||
while( p && (p->adjvex!=w)) // 找 w 边结点
|
||||
{
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(!p||!p->nextarc) // 没找到 w 或 w 是最后一个顶点
|
||||
return -1;
|
||||
else // 否则,返回下一个邻接点位序
|
||||
{
|
||||
return p->nextarc->adjvex;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(ALGraph<DT> &G, DT v) // 增加顶点
|
||||
{
|
||||
int j;
|
||||
char ans;
|
||||
DT w;
|
||||
if(G.vexnum > MAX_VEXNUM) // 顶点数为最多顶点数,不能增加新顶点
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vertices[G.vexnum].data = v; // 在顶点信息表中新增顶点
|
||||
G.vertices[G.vexnum].firstarc = NULL;
|
||||
G.vexnum++; // 顶点数增1
|
||||
cout<<"创建边吗(Y/N)?"<<endl; // 创建顶点相关的边
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值:"<<endl; // 输入边另一相邻顶点
|
||||
cin>>w;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在,增加边
|
||||
InsertArc(G,v,w);
|
||||
else
|
||||
cout<<w<<"\n顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(ALGraph<DT> &G, DT v,DT w) // 增加边(v,w)
|
||||
{
|
||||
ArcNode *p;
|
||||
int i,j;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0 || i==j) // 顶点不存在或两端点相同,不能插入
|
||||
{
|
||||
cout<<"\n顶点不存在或两顶点相同,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=G.vertices[i].firstarc; // 边已存在,不能新增
|
||||
while(p)
|
||||
{
|
||||
if(p->adjvex==j)
|
||||
{
|
||||
cout<<"边存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
G.arcnum++; // 边数增 1
|
||||
p = new ArcNode;
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; // (v,w)边结点插在第i条链表表头
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode;
|
||||
p->adjvex = i; // (w,v)边结点插在第j链表表头
|
||||
p->nextarc = G.vertices[j].firstarc;
|
||||
G.vertices[j].firstarc = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(ALGraph<DT> &G, DT v,DT w) // 删除边(v,w)
|
||||
{
|
||||
ArcNode *p,*q;
|
||||
int i,j;
|
||||
cout<<"Hello DeleteArc!"<<endl;
|
||||
cout<<"删除边顶点为:"<<endl;
|
||||
cout<<"("<<v<<","<<w<<")"<<endl;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边(v,w)不存在,不能删除
|
||||
{
|
||||
cout<<"\n边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc; // 寻找边(v,w)的边结点
|
||||
while(p && p->adjvex!=j) // p 不空且 p 指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p&&p->adjvex ==j) // 找到边(v,w)
|
||||
{
|
||||
if(p == G.vertices[i].firstarc) // 第 1 个边结点
|
||||
{
|
||||
G.vertices[i].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第 1 个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
G.arcnum--;
|
||||
p = G.vertices[j].firstarc;
|
||||
while(p&&p->adjvex!=i) // p不空且q指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p == G.vertices[j].firstarc) // 第 1 个边结点
|
||||
{
|
||||
G.vertices[j].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第1个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
}
|
||||
cout<<"Bye-bye DeleteArc!"<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(ALGraph<DT> &G, DT v) // 删除顶点v
|
||||
{
|
||||
int i,j;
|
||||
ArcNode *p;
|
||||
DT w;
|
||||
i = LocateVex(G,v);
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p) // 删除以 v 为邻接点边
|
||||
{
|
||||
j=p->adjvex;
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
p=G.vertices[i].firstarc;
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 顶点v后面的顶点前移
|
||||
{
|
||||
G.vertices[j-1].data = G.vertices[j].data;
|
||||
G.vertices[j-1].firstarc=G.vertices[j].firstarc;
|
||||
}
|
||||
G.vexnum--; // 顶点数减一
|
||||
return true;
|
||||
}
|
||||
|
||||
// 算法6.8
|
||||
template <class DT>
|
||||
void DFS(ALGraph<DT> G, int v) // 连通图的深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 标识已访问
|
||||
cout<<G.vertices[v].data; // 访问顶点
|
||||
for(w = FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w)) // 遍历v的邻接点w
|
||||
{
|
||||
if(!visited[w]) // 未访问,调用DFS
|
||||
DFS(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(ALGraph<DT> G) // 邻接表存储的图的深度优先遍历
|
||||
{
|
||||
int i ;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行DFS
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS(G,i);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// 算法6.13
|
||||
template <class DT>
|
||||
void BFS(ALGraph<DT> G, int v) // 连通图的广度优先遍历
|
||||
{
|
||||
int w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
cout<<G.vertices[v].data;
|
||||
visited[v]=true;
|
||||
EnQueue(Q,v);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,v);
|
||||
p=G.vertices[v].firstarc;
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w])
|
||||
{
|
||||
cout<<G.vertices[w].data;
|
||||
visited[w]=true;
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool BFSTraverse(ALGraph<DT> G) // 邻接表存储的图的广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化访问标志
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) // 对每个未被访问的顶点进行BFS
|
||||
if(!visited[i])
|
||||
BFS(G,i);
|
||||
//cout<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-3-ALGTraverseApp/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-3-ALGTraverseApp/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
112
OrigFiles/6-图/6-3-MGTraverseApp/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-3-MGTraverseApp/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
107
OrigFiles/6-图/6-3-MGTraverseApp/MGTraverseApp.cpp
Normal file
107
OrigFiles/6-图/6-3-MGTraverseApp/MGTraverseApp.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
//#include<string>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "MGraph.h"
|
||||
#include "LinkQueue.h"
|
||||
using namespace std;
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立图"<<endl;
|
||||
cout<<" 2. 判断两顶点的连通性"<<endl;
|
||||
cout<<" 3. 判断图的连通性"<<endl;
|
||||
cout<<" 4. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//算法6.14 判断两顶点是否连通
|
||||
template<class DT>
|
||||
bool IsConected(MGraph<DT> G, int i, int j)
|
||||
{
|
||||
int k;
|
||||
for(k=0;k<G.vexnum;k++)
|
||||
visited[i]=false;
|
||||
BFS(G,i);
|
||||
if(visited[j]==false)
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 算法6.15 判断图的连通性
|
||||
template<class DT>
|
||||
bool IsGraphConected(MGraph<DT> G)
|
||||
{
|
||||
int i,flag=1;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
DFS2(G,0); // 遍历图
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
if(visited[i]==0) // 如果未遍历到所有顶点
|
||||
{
|
||||
flag=0;break; // 图不连通
|
||||
}
|
||||
return flag; // 否则,图连通
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int i,j,k;
|
||||
MGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向图
|
||||
CreateUDG(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // 判断两顶点的连通性
|
||||
cout<<"请输入两顶点值: ";
|
||||
cin>>u>>v;
|
||||
i=LocateVex(G,u);
|
||||
j=LocateVex(G,v);
|
||||
if(i==-1 ||j==-1 || i==j) // 顶点不存在
|
||||
cout<<"\n顶点不存在或两顶点相同 "<<endl;
|
||||
else
|
||||
{
|
||||
if(IsConected(G,i,j))
|
||||
cout<<"\n"<<u<<"和"<<v<<"之间连通!"<<endl;
|
||||
else
|
||||
cout<<"\n"<<u<<"和"<<v<<"之间不连通!"<<endl;
|
||||
}
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3: // 判断图的连通性
|
||||
if(IsGraphConected(G))
|
||||
cout<<"\n此图连通! "<<v<<endl;
|
||||
else
|
||||
cout<<"\n此图不连通!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 显示图
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"\n结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"\n选择不合理,请重选!"<<endl;
|
||||
}
|
||||
}while(choice!=0);
|
||||
}
|
||||
299
OrigFiles/6-图/6-3-MGTraverseApp/Mgraph.h
Normal file
299
OrigFiles/6-图/6-3-MGTraverseApp/Mgraph.h
Normal file
@@ -0,0 +1,299 @@
|
||||
/*--------------------------无向图的邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和边数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条边信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=i+1;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<")"<<'\t';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDG(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
cout<<"请输入无向图的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向图的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=0;
|
||||
cout<<"请输入各条边的两个邻接点"<<endl; // 4.创建各条边
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条边的两个顶点:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入边的两个邻接点
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=1; // 4.3 修改邻接矩阵
|
||||
G.arcs[j][i]=1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjvex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjvex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==0 ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=0;
|
||||
G.arcs[j][G.vexnum-1]=0;
|
||||
}
|
||||
cout<<"创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值"<<endl;
|
||||
cin>>w;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在
|
||||
InsertArc(G,v,w);
|
||||
else
|
||||
cout<<w<<"顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w) // 在值为v、w顶点间加边
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
return false; // 不能插入边,返回false
|
||||
G.arcs[i][j]=1;
|
||||
G.arcs[j][i]=1;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除边
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边不存在,返回false
|
||||
{
|
||||
cout<<"边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=0; // 置邻接矩阵第 i 行第 j 列为零
|
||||
G.arcs[j][i]=0; // 置邻接矩阵第 i 列第 j 行为零
|
||||
G.arcnum--; // 边数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的边
|
||||
{
|
||||
if(G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 先访问index
|
||||
//cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
{
|
||||
if(G.arcs[v][w]!=0 && !visited[w] )
|
||||
DFS2(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS2(G,i); // 进行深度优先递归
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v]; // 访问顶点v
|
||||
visited[v]=true; // 做访问标志
|
||||
EnQueue(Q,v); // 入队
|
||||
while(!QueueEmpty(Q)) // 队非空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
cout<<G.vexs[w]; // 访问
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i); // 进行BFS遍历
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-4-1-MinTree(最小生成树)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-4-1-MinTree(最小生成树)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
310
OrigFiles/6-图/6-4-1-MinTree(最小生成树)/Mgraph.h
Normal file
310
OrigFiles/6-图/6-4-1-MinTree(最小生成树)/Mgraph.h
Normal file
@@ -0,0 +1,310 @@
|
||||
/*--------------------------无向图的邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
#define INF 1000 // 无穷大
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和边数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条边信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=i+1;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=INF)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<","<<G.arcs[i][j]<<")"<<'\t';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDN(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k,weight;
|
||||
DT v1,v2;
|
||||
cout<<"请输入无向网的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向网的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=INF;
|
||||
cout<<"请输入各条边的两个邻接点"<<endl; // 4.创建各条边
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条边的两个顶点和权值:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入边的两个邻接点和边权值
|
||||
cin>>weight;
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=weight; // 4.3 修改邻接矩阵
|
||||
G.arcs[j][i]=weight;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjvex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=INF) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjvex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==INF ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=INF) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j,weight;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=INF;
|
||||
G.arcs[j][G.vexnum-1]=INF;
|
||||
}
|
||||
cout<<"创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值和边的权值"<<endl;
|
||||
cin>>w>>weight;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在
|
||||
InsertArc(G,v,w,weight);
|
||||
else
|
||||
cout<<w<<"顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w,int weight) // 在值为v、w顶点间加边
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
{
|
||||
cout<<"\n顶点不存在,或两顶点相同,不能插入!"<<endl;
|
||||
return false; // 不能插入边,返回false
|
||||
}
|
||||
if(G.arcs[i][j]!=INF)
|
||||
{
|
||||
cout<<"\n边已存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=weight;
|
||||
G.arcs[j][i]=weight;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除边
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边不存在,返回false
|
||||
{
|
||||
cout<<"边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=INF; // 置邻接矩阵第 i 行第 j 列为零
|
||||
G.arcs[j][i]=INF; // 置邻接矩阵第 i 列第 j 行为零
|
||||
G.arcnum--; // 边数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的边
|
||||
{
|
||||
if(G.arcs[i][j]!=INF)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 先访问index
|
||||
cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
{
|
||||
if(G.arcs[v][w]!=INF && !visited[w] )
|
||||
DFS2(G,w);
|
||||
}
|
||||
//cout<<endl;
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS2(G,i); // 进行深度优先递归
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v]; // 访问顶点v
|
||||
visited[v]=true; // 做访问标志
|
||||
EnQueue(Q,v); // 入队
|
||||
while(!QueueEmpty(Q)) // 队非空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
cout<<G.vexs[w]; // 访问
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i); // 进行BFS遍历
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
217
OrigFiles/6-图/6-4-1-MinTree(最小生成树)/MinTree.cpp
Normal file
217
OrigFiles/6-图/6-4-1-MinTree(最小生成树)/MinTree.cpp
Normal file
@@ -0,0 +1,217 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "Mgraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
const MAX_ARCNUM=50;
|
||||
|
||||
// 最小生成树
|
||||
//算法6.18 Prim算法
|
||||
struct CEdge // 候选边存储
|
||||
{
|
||||
int adjvex; // U中集合点
|
||||
int lowcost; // 最小边的权值
|
||||
};
|
||||
|
||||
int minEdge(CEdge closeEdge[],int n)
|
||||
{
|
||||
int i, k=0;
|
||||
int min = INF;
|
||||
for ( i=0; i<n; i++) //求出与U权值最小的点 权值为0的代表在集合U
|
||||
{
|
||||
if (closeEdge[i].lowcost != 0 && closeEdge[i].lowcost<min)
|
||||
{
|
||||
min = closeEdge[i].lowcost;
|
||||
k = i;
|
||||
}
|
||||
}
|
||||
return k;
|
||||
}
|
||||
|
||||
|
||||
template<class DT>
|
||||
bool Prim_MST(MGraph<DT> G, DT v) // 从顶点v开始计算的最小生成树
|
||||
{
|
||||
CEdge closeEdge[MAX_VEXNUM];
|
||||
int i,j,k,mincost = 0;
|
||||
k=LocateVex(G,v);
|
||||
if(k==-1) // 顶点不存在
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
for (i = 0; i < G.vexnum; i++) // 辅助数组初始化
|
||||
if(i!=k)
|
||||
{
|
||||
closeEdge[i].adjvex = k; // u中的点
|
||||
closeEdge[i].lowcost = G.arcs[k][i];
|
||||
}
|
||||
closeEdge[k].lowcost=0; // 初始 U={v}
|
||||
cout << "\n Prim最小生成树的边:"<< endl;
|
||||
for (i = 1; i < G.vexnum; i++) // 选择其余G.vexnum-1个顶点
|
||||
{
|
||||
k=minEdge(closeEdge,G.vexnum); // 输出选择的权值最小的边
|
||||
cout << "(" <<G.vexs[closeEdge[k].adjvex]<< "," << G.vexs[k]
|
||||
<<"): "<<closeEdge[k].lowcost<<endl;
|
||||
mincost+=closeEdge[k].lowcost;
|
||||
closeEdge[k].lowcost=0;
|
||||
for (j = 0; j<G.vexnum; j++) // 更新最小边
|
||||
{
|
||||
if (closeEdge[j].lowcost != 0 && G.arcs[k][j]<closeEdge[j].lowcost)
|
||||
{
|
||||
closeEdge[j].adjvex = k;
|
||||
closeEdge[j].lowcost= G.arcs[k][j];
|
||||
}
|
||||
}
|
||||
}
|
||||
cout << "\n Prim最小生成树权值之和:" << mincost << endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Kruskal算法
|
||||
struct Edge{ // 存储边的信息
|
||||
int u,v;
|
||||
int cost;
|
||||
};
|
||||
|
||||
//Edge edge[MAX_ARCNUM];
|
||||
|
||||
void Sort(Edge edge[],int n) // 冒泡排序
|
||||
{
|
||||
int i,j;
|
||||
//int k;
|
||||
Edge temp;
|
||||
bool exchange;
|
||||
for(i=0,exchange=true;i<n-1 && exchange; i++) // 一趟排序工作如下:
|
||||
{
|
||||
exchange=false; // 1.设置交换标志初值为无交换
|
||||
for(j=0;j<n-i-1;j++) // 2.从表首开始两两比较
|
||||
{
|
||||
if (edge[j].cost>edge[j+1].cost) // 2.1相邻元素逆序,互换位置
|
||||
{
|
||||
temp=edge[j];edge[j]=edge[j+1];edge[j+1]=temp; // R[j]<-->R[j+1]
|
||||
exchange=true; // 2.2 交换标志改为true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int parent[MAX_VEXNUM];
|
||||
void Connect(int &x,int &y) // 连通分量标识
|
||||
{
|
||||
if(x<y)
|
||||
y=x;
|
||||
else
|
||||
x=y;
|
||||
}
|
||||
|
||||
//算法6.19 克鲁斯卡尔(Kruskal)算法
|
||||
template <class DT>
|
||||
bool Kruskal_MST(MGraph<DT> G) // 返回生成代价
|
||||
{
|
||||
int mincost=0,Num_Edge=0;
|
||||
char u,v;
|
||||
int i,j,k=0;
|
||||
Edge edge[MAX_ARCNUM];
|
||||
for(i=0;i<G.vexnum;i++) // 从邻接矩阵获取边信息
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
{
|
||||
if(i<j && G.arcs[i][j]!=INF)
|
||||
{
|
||||
edge[k].u=i; // 存储边的信息
|
||||
edge[k].v=j;
|
||||
edge[k].cost=G.arcs[i][j];
|
||||
k++;
|
||||
}
|
||||
}
|
||||
Sort(edge,G.arcnum); // 边排序
|
||||
for(i=0;i<G.vexnum;i++) // 连通分量初始化
|
||||
{
|
||||
parent[i]=i;
|
||||
}
|
||||
cout << "\n Kruskal 最小生成树的边:"<< endl;
|
||||
for(i=0;i<G.arcnum;i++) // 从小到考察选取n-1条边
|
||||
{
|
||||
j=edge[i].u;
|
||||
k=edge[i].v;
|
||||
int vx1=parent[j]; // 获取边起点、终点所在的连通分量标志
|
||||
int vx2=parent[k];
|
||||
if(vx1!=vx2) // 如果不属于同一个连通分量, 生成边
|
||||
{
|
||||
GetVex(G,j,u);
|
||||
GetVex(G,k,v);
|
||||
cout<<"("<<u<<","<<v<<"):"<<G.arcs[j][k]<<endl;
|
||||
Connect(parent[j],parent[k]); // 合并连通分量
|
||||
mincost+=edge[i].cost;
|
||||
Num_Edge++; // 已找到的边数+1
|
||||
if(Num_Edge==G.vexnum-1)
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
if(Num_Edge!=G.vexnum-1) // 判断最小生成树的查找情况
|
||||
{
|
||||
cout<<"非连通图,无最小生成树!"<<endl;
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
cout<<"\nKruskal最小生树权值为:"<<mincost<<endl;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n 请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立无向网"<<endl;
|
||||
cout<<" 2. Prinmt算法"<<endl;
|
||||
cout<<" 3. Kruskal算法"<<endl;
|
||||
cout<<" 4. 显示网"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char v;
|
||||
//int k,weight;
|
||||
MGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向网
|
||||
CreateUDN(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的网为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // Prinmt算法
|
||||
cout<<"请输入起始计算顶点: ";
|
||||
cin>>v;
|
||||
Prim_MST(G,v);
|
||||
break;
|
||||
case 3: // Kruskal算法
|
||||
Kruskal_MST(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 显示网
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"选择不合理,请重选!"<<endl;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
|
||||
112
OrigFiles/6-图/6-4-2-ShorDistance(最短距离)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-4-2-ShorDistance(最短距离)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
308
OrigFiles/6-图/6-4-2-ShorDistance(最短距离)/Mgraph.h
Normal file
308
OrigFiles/6-图/6-4-2-ShorDistance(最短距离)/Mgraph.h
Normal file
@@ -0,0 +1,308 @@
|
||||
/*--------------------------有向网的邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
#define INF 1000 // 无穷大
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和弧数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条弧信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=INF)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<"):"<<G.arcs[i][j]<<" ";
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建无向图
|
||||
template <class DT>
|
||||
void CreateDN(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k,weight;
|
||||
DT v1,v2;
|
||||
cout<<"请输入有向网的顶点数 "; // 1. 输入顶点数、弧数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入有向网的弧数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=INF;
|
||||
cout<<"请输入各条弧的两个邻接点"<<endl; // 4.创建各条弧
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条弧的两个顶点和权值:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入弧的两个邻接点和弧权值
|
||||
cin>>weight;
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=weight; // 4.3 修改邻接矩阵
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjvex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=INF) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjvex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==INF ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=INF) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j,weight;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=INF;
|
||||
G.arcs[j][G.vexnum-1]=INF;
|
||||
}
|
||||
cout<<"创建弧吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值和弧的权值"<<endl;
|
||||
cin>>w>>weight;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在
|
||||
InsertArc(G,v,w,weight);
|
||||
else
|
||||
cout<<w<<"顶点不存在!";
|
||||
cout<<"继续创建弧吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w,int weight) // 在值为v、w顶点间加弧
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
{
|
||||
cout<<"\n顶点不存在或边已存在,不能插入!"<<endl;
|
||||
return false; // 不能插入弧,返回false
|
||||
}
|
||||
if(G.arcs[i][j]!=INF) // 弧已存在,不能插入
|
||||
{
|
||||
cout<<"\n弧已存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
G.arcs[i][j]=weight;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除弧
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 弧不存在,返回false
|
||||
{
|
||||
cout<<"弧不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=INF; // 置邻接矩阵第 i 行第 j 列为零
|
||||
G.arcnum--; // 弧数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的弧
|
||||
{
|
||||
if(G.arcs[i][j]!=INF)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 先访问index
|
||||
cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
{
|
||||
if(G.arcs[v][w]!=INF && !visited[w] )
|
||||
DFS2(G,w);
|
||||
}
|
||||
//cout<<endl;
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS2(G,i); // 进行深度优先递归
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q; // 创建一个队列
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v]; // 访问顶点v
|
||||
visited[v]=true; // 做访问标志
|
||||
EnQueue(Q,v); // 入队
|
||||
while(!QueueEmpty(Q)) // 队非空
|
||||
{
|
||||
DeQueue(Q,v); // 出队
|
||||
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
|
||||
if(!visited[w]) // 未被访问
|
||||
{
|
||||
cout<<G.vexs[w]; // 访问
|
||||
visited[w]=true; // 做访问标志
|
||||
EnQueue(Q,w); // 入队
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++) // 访问标志初始化
|
||||
visited[i]=0;
|
||||
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i); // 进行BFS遍历
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
211
OrigFiles/6-图/6-4-2-ShorDistance(最短距离)/ShortDistance.cpp
Normal file
211
OrigFiles/6-图/6-4-2-ShorDistance(最短距离)/ShortDistance.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "Mgraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
const MAX_ARCNUM=50;
|
||||
|
||||
//算法6.20 Dijkstra算法
|
||||
template<class DT>
|
||||
void ShortestPath_DIJ(MGraph<DT> G, int v0) // 从顶点v开始计算的最小生成树
|
||||
{
|
||||
int v,i,w,min;
|
||||
bool S[MAX_VEXNUM]={false}; // 记载S集合中的顶点
|
||||
int D[MAX_VEXNUM]; // 源点到其它各顶点的距离
|
||||
int P[MAX_VEXNUM]={-1}; // 源点互其它各顶点的路径信息
|
||||
for(v=0;v<G.vexnum;v++) // 初始化
|
||||
{
|
||||
S[v]=false; //
|
||||
D[v]=G.arcs[v0][v];
|
||||
if(D[v]<INF) // 源点可直达顶点的距离
|
||||
P[v]=v0;
|
||||
else
|
||||
P[v]=-1;
|
||||
}
|
||||
D[v0]=0; // 源点到自身的距离为0
|
||||
S[v0]=true;
|
||||
for(i=1;i<G.vexnum;i++) // 求n-1条最短路径
|
||||
{
|
||||
min=INF;
|
||||
for(w=0;w<G.vexnum;++w) // 在源点到未选目的地顶点距离中选路径最小的顶点
|
||||
if(!S[w] && D[w]<min)
|
||||
{
|
||||
v=w; min=D[w];
|
||||
}
|
||||
S[v]=true; // 加入S
|
||||
for(w=0;w<G.vexnum;++w) // 考量经过新求出最短路径有否比原先路径短的
|
||||
if(!S[w]&&(D[v]+G.arcs[v][w]<D[w])) // 如果有
|
||||
{
|
||||
D[w]=D[v]+G.arcs[v][w]; // 更新D[]值
|
||||
P[w]=v; // 更新P[]值
|
||||
}
|
||||
}
|
||||
cout<<G.vexs[v0]<<"到其余各顶点的距离为:"<<endl; // 输入D[]
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
cout<<D[w]<<" ";
|
||||
cout<<"\n路径距径P为:"<<endl; // 输出P[]
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
cout<<P[w]<<" ";
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
// 算法6.21 Floyd算法
|
||||
template <class DT>
|
||||
void ShortestPath_Floyd(MGraph<DT> G) // 返回生成代价
|
||||
{
|
||||
int k,i,j;
|
||||
int D[MAX_VEXNUM][MAX_VEXNUM]; // D[i][j]表示顶点i和顶点j的最短距离
|
||||
int P[MAX_VEXNUM][MAX_VEXNUM]; // 记载最短距离的路径信息
|
||||
for(i=0;i<G.vexnum;i++) // 初始化D[][]
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
{
|
||||
|
||||
// 初始化P[][]
|
||||
//if(i==j)
|
||||
//D[i][j]=0;
|
||||
if(D[i][j]<INF && i!=j) // 顶点 i 和顶点 j 之间存在路径
|
||||
P[i][j]=i;
|
||||
else P[i][j]=-1; // 顶点 i 和顶点 j 之间不存在路径
|
||||
}
|
||||
cout<<"\nD-1和P-1:"<<endl; // 显示D、P
|
||||
DispPath_Floyd(D,G.vexnum,P);
|
||||
|
||||
for(k=0;k<G.vexnum;k++) //以k为中间点对所有顶点对{i,j}进行检测
|
||||
{
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
{
|
||||
if(i!=j && D[i][k]+D[k][j]<D[i][j]) // 如果满足修改条件
|
||||
{
|
||||
D[i][j]=D[i][k]+D[k][j]; // 修改D[i][j]
|
||||
P[i][j]=P[k][j]; // 修改路径
|
||||
}
|
||||
}
|
||||
}
|
||||
cout<<"\n第"<<k+1<<"次替代后的D和P"<<endl;
|
||||
DispPath_Floyd(D,G.vexnum,P);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DispPath_Floyd(int D[][MAX_VEXNUM],int n,int P[][MAX_VEXNUM]) // 距离信息和路径信息显示
|
||||
{
|
||||
int i,j;
|
||||
cout<<"\nD:"<<endl;
|
||||
for(i=0;i<n;i++) // 输出第一趟D[]
|
||||
{
|
||||
for(j=0;j<n;j++)
|
||||
cout<<D[i][j]<<'\t';
|
||||
cout<<endl;
|
||||
}
|
||||
cout<<"\nP:"<<endl;
|
||||
for(i=0;i<n;i++) // 输出第一趟D[]
|
||||
{
|
||||
for(j=0;j<n;j++)
|
||||
cout<<P[i][j]<<'\t';
|
||||
cout<<endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"\n如果不创建图,可使用测试图!"<<endl;
|
||||
cout<<"\n 请选择你要的操作"<<endl;
|
||||
cout<<" 1. " <<endl;
|
||||
cout<<" 2. 建立有向网Dijkstra算法" <<endl;
|
||||
cout<<" 3. Floyd算法" << endl;
|
||||
cout<<" 4. 显示网"<< endl;
|
||||
cout<<" 0. 退出"<< endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
int i,j,v0;
|
||||
char w;
|
||||
MGraph<char> G,G1,G2;
|
||||
G1.vexnum=5; // Dijkstra算法测试图
|
||||
G1.arcnum=7;
|
||||
G1.vexs[0]='A';G1.vexs[1]='B';G1.vexs[2]='C';
|
||||
G1.vexs[3]='D';G1.vexs[4]='E';
|
||||
for(i=0;i<G1.vexnum;i++) // 邻接矩阵初始化
|
||||
for(j=0;j<G1.vexnum;j++)
|
||||
G1.arcs[i][j]=INF;
|
||||
G1.arcs[0][1]=10;
|
||||
G1.arcs[0][3]=50;
|
||||
G1.arcs[0][4]=45;
|
||||
G1.arcs[1][4]=30;
|
||||
G1.arcs[3][4]=15;
|
||||
G1.arcs[1][2]=4;
|
||||
G1.arcs[2][4]=11;
|
||||
cout<<"\n测试图为G1:"<<endl;
|
||||
DispG(G1);
|
||||
|
||||
G2.vexnum=3; // Floyd算法测试图
|
||||
G2.arcnum=5;
|
||||
G2.vexs[0]='A';G2.vexs[1]='B';G2.vexs[2]='C';
|
||||
for(i=0;i<G2.vexnum;i++) // 邻接矩阵初始化
|
||||
for(j=0;j<G2.vexnum;j++)
|
||||
G2.arcs[i][j]=INF;
|
||||
G2.arcs[0][1]=4;
|
||||
G2.arcs[1][0]=6;
|
||||
G2.arcs[0][2]=11;
|
||||
G2.arcs[2][0]=3;
|
||||
G2.arcs[1][2]=2;
|
||||
cout<<"\n测试图为G2:"<<endl;
|
||||
DispG(G2);
|
||||
|
||||
bool f=false; // 是否创建网,缺省为未创建
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1: // 创建无向网
|
||||
f=true;
|
||||
CreateDN(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的有向网为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2: // Dijkstra算法
|
||||
cout<<"请输入起始计算顶点: ";
|
||||
cin>>w;
|
||||
v0=LocateVex(G1,w);
|
||||
if(v0==-1)
|
||||
cout<<"顶点不存在!"<<endl;
|
||||
else
|
||||
{
|
||||
if(!f) // 使用测试图
|
||||
ShortestPath_DIJ(G1,v0);
|
||||
else
|
||||
ShortestPath_DIJ(G,v0);
|
||||
}
|
||||
break;
|
||||
case 3: // Floyd算法
|
||||
if(!f) // 使用测试图
|
||||
ShortestPath_Floyd(G2);
|
||||
else
|
||||
ShortestPath_Floyd(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4: // 显示网
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"无效选择,请重选!"<<endl;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
|
||||
127
OrigFiles/6-图/6-ALGraph(无向图的邻接表存储)/ALGraph.cpp
Normal file
127
OrigFiles/6-图/6-ALGraph(无向图的邻接表存储)/ALGraph.cpp
Normal file
@@ -0,0 +1,127 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "ALGraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立图"<<endl;
|
||||
cout<<" 2. 返回顶点在图中的位置"<<endl;
|
||||
cout<<" 3. 返回某位置的顶点的值"<<endl;
|
||||
cout<<" 4. 修改顶点值"<<endl;
|
||||
cout<<" 5. 增加顶点"<<endl;
|
||||
cout<<" 6. 删除顶点"<<endl;
|
||||
cout<<" 7. 增添边"<<endl;
|
||||
cout<<" 8. 删除边"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历图"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历图"<<endl;
|
||||
cout<<"11. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k;
|
||||
ALGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1:
|
||||
CreateUDG(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2:
|
||||
cout<<"请输入您要的所要查询位置的顶点的名称: ";
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在图中的位置为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3:
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位置: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4:
|
||||
cout<<"请输入要更改的顶点值: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点的值: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5:
|
||||
cout<<"请输入要增加的顶点的值: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6:
|
||||
cout<<"请输入要删除的顶点的值:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的图为:"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7:
|
||||
cout<<"请输入要增添边的顶相邻两顶点";
|
||||
cin>>u>>v;
|
||||
InsertArc(G,u,v);
|
||||
cout<<"插入边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8:
|
||||
cout<<"请输入删除的边相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"顶点边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9:
|
||||
cout<<"从第一个顶点出发深度优先遍历图的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10:
|
||||
cout<<"从第一个顶点出发广度优先遍历图的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11:
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"选择不合理,请重选!"<<endl;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
415
OrigFiles/6-图/6-ALGraph(无向图的邻接表存储)/ALGraph.h
Normal file
415
OrigFiles/6-图/6-ALGraph(无向图的邻接表存储)/ALGraph.h
Normal file
@@ -0,0 +1,415 @@
|
||||
/*----------------------图的邻接表示存储------------------------*/
|
||||
//无向图
|
||||
|
||||
#define MAX_VEXNUM 20 //最大顶点数
|
||||
|
||||
struct ArcNode{
|
||||
int adjvex; //该弧所指向的顶点的位置
|
||||
ArcNode *nextarc; //指向下一条弧的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct VNode{
|
||||
DT data; //顶点信息
|
||||
ArcNode *firstarc;//指向第一条依附该顶点的指针
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
struct ALGraph{
|
||||
VNode<DT> vertices[MAX_VEXNUM];//顶点集
|
||||
int vexnum;//顶点数
|
||||
int arcnum;//边数
|
||||
};
|
||||
|
||||
template <class DT>
|
||||
void DispG(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
ArcNode *p;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;//输出顶点
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
cout<<G.vertices[i].data<<" ";
|
||||
}
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条弧(边):"<<endl;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
if(i<p->adjvex) //避免了无向的时候一条边被输出两次
|
||||
{
|
||||
cout<<"("<<G.vertices[i].data<<","
|
||||
<<G.vertices[p->adjvex].data<<")"<<'\t';
|
||||
}
|
||||
p = p->nextarc;
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
int LocateVex(ALGraph<DT> G, DT v)
|
||||
{
|
||||
for(int i=0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vertices[i].data == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
void CreateUDG(ALGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
ArcNode *p;
|
||||
cout<<"请输入无向图的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向图的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++) // 初始化顶点结点
|
||||
{
|
||||
cin>>G.vertices[i].data;
|
||||
G.vertices[i].firstarc = NULL;
|
||||
}
|
||||
//cout<<"请输入每条边两个邻接点: "<<endl;
|
||||
for(k=0;k<G.arcnum;k++) //构造表结点链表
|
||||
{
|
||||
cout<<"请输入边的两个顶点值: "<<endl;
|
||||
cin>>v1>>v2;
|
||||
i = LocateVex(G,v1);
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
p = new ArcNode; //创建一个新的弧结点
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; //插在表头
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode; //创建一个新的弧结点
|
||||
p->adjvex = i;
|
||||
p->nextarc = G.vertices[j].firstarc; //插在表头
|
||||
G.vertices[j].firstarc = p;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DestroyGraph(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
ArcNode *p,*q;
|
||||
for(i = 0;i<G.vexnum;i++)//从顶点序号为0的顶点开始依次释放掉相应的邻接表
|
||||
{
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
q = p->nextarc;
|
||||
delete p;//删除弧结点
|
||||
p = q;
|
||||
}
|
||||
}
|
||||
G.arcnum = 0;
|
||||
G.vexnum = 0;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(ALGraph<DT> G, int k,DT &v)
|
||||
{
|
||||
if(k<0||k>=G.vexnum) //顶点不存在
|
||||
return false;
|
||||
v=G.vertices[k].data;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(ALGraph<DT> &G, DT &u,DT v)
|
||||
{
|
||||
int k = LocateVex(G,u);
|
||||
if(k<0) //该顶点不存在
|
||||
return false;
|
||||
G.vertices[k].data = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int FirstAdjVex(ALGraph<DT> G, int u)
|
||||
{
|
||||
ArcNode * p;
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc;//p指向下标为i的第一个邻接点
|
||||
if(p)
|
||||
{
|
||||
return p->adjvex;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjVex(ALGraph<DT> G, int u,int w)
|
||||
{
|
||||
ArcNode *p;
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum ) // 参数不合理
|
||||
return -1;
|
||||
p = G.vertices[u].firstarc;
|
||||
while(p &&(p->adjvex!=w))
|
||||
//让p指向顶点w
|
||||
{
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(!p||!p->nextarc) //没找到w或w是最后一个顶点
|
||||
return -1;
|
||||
else
|
||||
//找到w且w不是最后一个顶点
|
||||
{
|
||||
return p->nextarc->adjvex;
|
||||
}
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(ALGraph<DT> &G, DT v)
|
||||
{
|
||||
int j;
|
||||
char ans;
|
||||
DT w;
|
||||
if(G.vexnum > MAX_VEXNUM)
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vertices[G.vexnum].data = v;
|
||||
G.vertices[G.vexnum].firstarc = NULL;
|
||||
G.vexnum++;
|
||||
cout<<"创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值:"<<endl;
|
||||
cin>>w;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在
|
||||
InsertArc(G,v,w);
|
||||
else
|
||||
cout<<w<<"\n顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(ALGraph<DT> &G, DT v,DT w)
|
||||
{
|
||||
ArcNode *p;
|
||||
int i,j;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
if(i<0||j<0 || i==j) // 顶点不存在或两端点相同,不能插入
|
||||
{
|
||||
cout<<"\n顶点不存在或两顶点相同,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=G.vertices[i].firstarc;
|
||||
while(p)
|
||||
{
|
||||
if(p->adjvex==j)
|
||||
{
|
||||
cout<<"边存在,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
G.arcnum++;
|
||||
p = new ArcNode;
|
||||
p->adjvex = j;
|
||||
p->nextarc = G.vertices[i].firstarc; //(v,w)边结点插在第i条链表表头
|
||||
G.vertices[i].firstarc = p;
|
||||
p = new ArcNode;
|
||||
p->adjvex = i; //(w,v)边结点插在第j链表表头
|
||||
p->nextarc = G.vertices[j].firstarc;
|
||||
G.vertices[j].firstarc = p;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(ALGraph<DT> &G, DT v,DT w)
|
||||
{
|
||||
ArcNode *p,*q;
|
||||
int i,j;
|
||||
cout<<"Hello DeleteArc!"<<endl;
|
||||
cout<<"删除边顶点为:"<<endl;
|
||||
cout<<"("<<v<<","<<w<<")"<<endl;
|
||||
i = LocateVex(G,v);
|
||||
j = LocateVex(G,w);
|
||||
cout<<"删除边顶点序号为:"<<endl;
|
||||
cout<<"("<<i<<","<<j<<")"<<endl;
|
||||
if(i<0||j<0||i == j)
|
||||
{
|
||||
cout<<"\n边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p && p->adjvex!=j) // p不空且p指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p&&p->adjvex ==j) // 找到边<v,w>
|
||||
{
|
||||
if(p == G.vertices[i].firstarc) // 第1个边结点
|
||||
{
|
||||
G.vertices[i].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第1个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
G.arcnum--;
|
||||
p = G.vertices[j].firstarc;
|
||||
while(p&&p->adjvex!=i) // p不空且q指向的不是待删弧结点
|
||||
{
|
||||
q = p;
|
||||
p = p->nextarc;
|
||||
}
|
||||
if(p == G.vertices[j].firstarc) // 第1个边结点
|
||||
{
|
||||
G.vertices[j].firstarc = p->nextarc;
|
||||
}
|
||||
else // 非第1个边结点
|
||||
{
|
||||
q->nextarc = p->nextarc;
|
||||
}
|
||||
delete p;
|
||||
}
|
||||
cout<<"Bye-bye DeleteArc!"<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(ALGraph<DT> &G, DT v)
|
||||
{
|
||||
int i,j;
|
||||
ArcNode *p;
|
||||
DT w;
|
||||
i = LocateVex(G,v);
|
||||
cout<<"将删除第"<<i<<"个顶点!"<<endl;
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
p = G.vertices[i].firstarc;
|
||||
while(p) // 删除以v为邻接点边
|
||||
{
|
||||
j=p->adjvex;
|
||||
cout<<"删除边顶点序号为:"<<endl;
|
||||
cout<<"("<<i<<","<<j<<")"<<endl;
|
||||
GetVex(G,j,w);
|
||||
cout<<"删除边顶点为:"<<endl;
|
||||
cout<<"("<<v<<","<<w<<")"<<endl;
|
||||
DeleteArc(G,v,w);
|
||||
p=G.vertices[i].firstarc;
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 顶点v后面的顶点前移
|
||||
{
|
||||
G.vertices[j-1].data = G.vertices[j].data;
|
||||
G.vertices[j-1].firstarc=G.vertices[j].firstarc;
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
// 算法6.8
|
||||
template <class DT>
|
||||
void DFS(ALGraph<DT> G, int v)
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 已访问
|
||||
cout<<G.vertices[v].data; // 访问顶点
|
||||
for(w = FirstAdjVex(G,v);w>=0;w=NextAdjVex(G,v,w))
|
||||
{
|
||||
if(!visited[w])
|
||||
DFS(G,w);
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(ALGraph<DT> G)
|
||||
{
|
||||
int i ;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++) //对每个未被访问的顶点进行深度优先遍历
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS(G,i);
|
||||
}
|
||||
//cout<<endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// 算法6.13
|
||||
template <class DT>
|
||||
void BFS(ALGraph<DT> G, int v)
|
||||
{
|
||||
int w;
|
||||
ArcNode *p;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
cout<<G.vertices[v].data;
|
||||
visited[v]=true;
|
||||
EnQueue(Q,v);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,v);
|
||||
p=G.vertices[v].firstarc;
|
||||
while(p)
|
||||
{
|
||||
w=p->adjvex;
|
||||
if(!visited[w])
|
||||
{
|
||||
cout<<G.vertices[w].data;
|
||||
visited[w]=true;
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
p=p->nextarc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool BFSTraverse(ALGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
visited[i] = false;
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
if(!visited[i])
|
||||
BFS(G,i);
|
||||
//cout<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
112
OrigFiles/6-图/6-ALGraph(无向图的邻接表存储)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-ALGraph(无向图的邻接表存储)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
112
OrigFiles/6-图/6-MGraph(无向图邻接矩阵存储)/LinkQueue.h
Normal file
112
OrigFiles/6-图/6-MGraph(无向图邻接矩阵存储)/LinkQueue.h
Normal file
@@ -0,0 +1,112 @@
|
||||
|
||||
template <class DT>
|
||||
struct QNode //结点
|
||||
{
|
||||
DT data; //数据域,存储数据元素值
|
||||
QNode *next;//指针域,指向下一个结点
|
||||
};
|
||||
|
||||
template<class DT>
|
||||
struct LinkQueue
|
||||
{
|
||||
QNode<DT> * front;
|
||||
QNode<DT> * rear;
|
||||
};
|
||||
|
||||
|
||||
//【算法3.19】
|
||||
template <class DT>
|
||||
void InitQueue(LinkQueue<DT> &Q)//创建空队列
|
||||
{
|
||||
Q.front=new QNode<DT>; //创建头结点
|
||||
if(!Q.front) exit(1); //创建失败,结束运行
|
||||
Q.front->next=NULL;
|
||||
Q.rear=Q.front;
|
||||
}
|
||||
|
||||
//【算法3.20】
|
||||
template <class DT>
|
||||
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
|
||||
{
|
||||
QNode<DT> *p;
|
||||
while(Q.front)//从头结点开始,依次释放结点
|
||||
{
|
||||
p=Q.front;
|
||||
Q.front=Q.front->next;
|
||||
delete p;
|
||||
}
|
||||
}
|
||||
|
||||
//【算法3.21】 入队
|
||||
template<class DT>
|
||||
bool EnQueue(LinkQueue<DT> &Q,DT e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=new QNode<DT>; // 创建新结点
|
||||
if(!p) return false; // 创建失败,结束运行
|
||||
p->data=e; // 新结点赋值
|
||||
p->next=NULL; // 链在队尾
|
||||
Q.rear->next=p;
|
||||
Q.rear=p;
|
||||
return true; // 入队成功,返回true
|
||||
}
|
||||
|
||||
//【算法3.22】 出队
|
||||
template<class DT>
|
||||
bool DeQueue(LinkQueue<DT> &Q,DT &e)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
if(Q.front==Q.rear) return false; //队空,返回false
|
||||
p=Q.front->next; // 取出队元素
|
||||
e=p->data;
|
||||
Q.front->next=p->next; //队首元素出队
|
||||
if(Q.rear==p) //只有一个元素时出队,
|
||||
Q.rear=Q.front; // 修改队尾
|
||||
delete p;
|
||||
return true; // 出队成功,返回true
|
||||
}
|
||||
|
||||
|
||||
//【算法3.23】 取队头元素
|
||||
template<class DT>
|
||||
bool GetHead(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) return false; // 队空,返回false
|
||||
e=Q.front->next->data;
|
||||
return true; // 删除成功,返回true
|
||||
}
|
||||
|
||||
//取队尾元素
|
||||
template<class DT>
|
||||
bool GetTail(LinkQueue<DT> Q,DT &e)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return false; // 返回false
|
||||
e=Q.rear->data; // 获取队尾元素
|
||||
return true; // 返回true
|
||||
}
|
||||
|
||||
//测队空
|
||||
template<class DT>
|
||||
bool QueueEmpty(LinkQueue<DT> Q)
|
||||
{
|
||||
if(Q.front==Q.rear) // 队空
|
||||
return true; //返回true
|
||||
else //非空
|
||||
return false; //返回false
|
||||
}
|
||||
|
||||
//显示队列内容
|
||||
template<class DT>
|
||||
void DispQueue(LinkQueue<DT> Q)
|
||||
{
|
||||
QNode<DT> *p;
|
||||
p=Q.front->next;
|
||||
while(p)
|
||||
{
|
||||
cout<<p->data<<"\t";
|
||||
p=p->next;
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
132
OrigFiles/6-图/6-MGraph(无向图邻接矩阵存储)/Mgraph.cpp
Normal file
132
OrigFiles/6-图/6-MGraph(无向图邻接矩阵存储)/Mgraph.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
#include<string>
|
||||
#include "LinkQueue.h"
|
||||
#include "Mgraph.h"
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
|
||||
|
||||
// 无向图
|
||||
|
||||
void DispMenu()
|
||||
{
|
||||
cout<<"请选择你要的操作"<<endl;
|
||||
cout<<" 1. 建立图"<<endl;
|
||||
cout<<" 2. 返回顶点在图中的位置"<<endl;
|
||||
cout<<" 3. 返回某位置的顶点的值"<<endl;
|
||||
cout<<" 4. 修改顶点值"<<endl;
|
||||
cout<<" 5. 增加新顶点"<<endl;
|
||||
cout<<" 6. 删除顶点弧"<<endl;
|
||||
cout<<" 7. 增添边"<<endl;
|
||||
cout<<" 8. 删除边"<<endl;
|
||||
cout<<" 9. 从第一个顶点出发深度优先遍历图"<<endl;
|
||||
cout<<"10. 从第一个顶点广度优先遍历图"<<endl;
|
||||
cout<<"11. 显示图"<<endl;
|
||||
cout<<" 0. 退出"<<endl;
|
||||
}
|
||||
|
||||
bool visited[MAX_VEXNUM]={false};
|
||||
|
||||
void main()
|
||||
{
|
||||
char u,v;
|
||||
int k;
|
||||
MGraph<char> G;
|
||||
int choice;
|
||||
do
|
||||
{
|
||||
DispMenu();
|
||||
cin>>choice;
|
||||
switch(choice)
|
||||
{
|
||||
case 1:
|
||||
CreateUDN(G);
|
||||
cout<<endl;
|
||||
cout<<"创建的图为:"<<endl;
|
||||
DispG(G);
|
||||
break;
|
||||
case 2:
|
||||
cout<<"请输入您要的所要查询位置的顶点的名称: ";
|
||||
cin>>u;
|
||||
k=LocateVex(G,u);
|
||||
if(k!=-1)
|
||||
cout<<"顶点"<<u<<"在图中的位置为: "<<k<<endl;
|
||||
else
|
||||
cout<<"顶点"<<u<<"不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 3:
|
||||
int index;
|
||||
cout<<"请输入您要的所要查询顶点的位置: ";
|
||||
cin>>index;
|
||||
if(GetVex(G,index,v))
|
||||
cout<<"位置为"<<index<<"的顶点为: "<<v<<endl;
|
||||
else
|
||||
cout<<"第"<<index<<"顶点不存在!"<<endl;
|
||||
cout<<endl;
|
||||
break;
|
||||
case 4:
|
||||
cout<<"请输入要更改的顶点值: ";
|
||||
cin>>u;
|
||||
cout<<"请输入更改后顶点的值: ";
|
||||
cin>>v;
|
||||
PutVex(G,u,v);
|
||||
cout<<"顶点值修后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 5:
|
||||
cout<<"请输入要增加的顶点的值: ";
|
||||
cin>>v;
|
||||
InsertVex(G,v);
|
||||
cout<<"插入顶点和相应边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 6:
|
||||
cout<<"请输入要删除的顶点的值:";
|
||||
cin>>v;
|
||||
DeleteVex(G,v);
|
||||
cout<<"顶点删除后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 7:
|
||||
cout<<"请输入要增添边的顶相邻两顶点";
|
||||
cin>>u>>v;
|
||||
InsertArc(G,u,v);
|
||||
cout<<"插入边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 8:
|
||||
cout<<"请输入删除的边相邻两顶点: ";
|
||||
cin>>u>>v;
|
||||
DeleteArc(G,u,v);
|
||||
cout<<"顶点边后的图为“"<<endl;
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 9:
|
||||
cout<<"从第一个顶点出发深度优先遍历图的序列为: "<<endl;
|
||||
DFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 10:
|
||||
cout<<"从第一个顶点出发广度优先遍历图的序列为: "<<endl;
|
||||
BFSTraverse(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 11:
|
||||
DispG(G);
|
||||
cout<<endl;
|
||||
break;
|
||||
case 0:
|
||||
cout<<"结束运行,Bye-Bye!"<<endl;
|
||||
break;
|
||||
default:
|
||||
cout<<"选择不合理,请重选!"<<endl;
|
||||
}//case
|
||||
}while(choice!=0);
|
||||
}//main
|
||||
|
||||
334
OrigFiles/6-图/6-MGraph(无向图邻接矩阵存储)/Mgraph.h
Normal file
334
OrigFiles/6-图/6-MGraph(无向图邻接矩阵存储)/Mgraph.h
Normal file
@@ -0,0 +1,334 @@
|
||||
/*--------------------------无向图的邻接矩阵表示-----------------------------*/
|
||||
|
||||
#define MAX_VEXNUM 20 // 最大顶点数
|
||||
|
||||
template <class DT>
|
||||
struct MGraph // 图的邻接矩阵表示存储定义
|
||||
{
|
||||
DT vexs[MAX_VEXNUM]; // 顶点信息
|
||||
int arcs[MAX_VEXNUM][MAX_VEXNUM];
|
||||
int vexnum,arcnum; // 顶点数和边数
|
||||
};
|
||||
|
||||
|
||||
template <class DT>
|
||||
void DispG(MGraph<DT> G) // 显示图信息
|
||||
{
|
||||
int i,j;
|
||||
DT u,v;
|
||||
cout<<G.vexnum<<"个顶点:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
cout<<G.vexs[i]<<" ";
|
||||
cout<<endl;
|
||||
cout<<G.arcnum<<"条边信息如下:"<<endl;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
for(j=i+1;j<G.vexnum;j++)
|
||||
if (G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,i,u);
|
||||
GetVex(G,j,v);
|
||||
cout<<'('<<u<<","<<v<<")"<<'\t';
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
}
|
||||
|
||||
|
||||
//算法6.1 顶点定位
|
||||
template <class DT>
|
||||
int LocateVex(MGraph<DT> G,DT v)
|
||||
{
|
||||
for(int i = 0;i<G.vexnum;i++)
|
||||
{
|
||||
if(G.vexs[i] == v)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//6.2 创建无向图
|
||||
template <class DT>
|
||||
void CreateUDN(MGraph<DT> &G)
|
||||
{
|
||||
int i,j,k;
|
||||
DT v1,v2;
|
||||
cout<<"请输入无向图的顶点数 "; // 1. 输入顶点数、边数
|
||||
cin>>G.vexnum ;
|
||||
cout<<"请输入无向图的边数 ";
|
||||
cin>>G.arcnum ;
|
||||
cout<<"请输入"<<G.vexnum<<"个顶点的值"<<endl; // 2. 输入顶点值
|
||||
for(i = 0;i<G.vexnum;i++)
|
||||
cin>>G.vexs[i];
|
||||
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
|
||||
for(j=0;j<G.vexnum;j++)
|
||||
G.arcs[i][j]=0;
|
||||
cout<<"请输入各条边的两个邻接点"<<endl; // 4.创建各条边
|
||||
for( k=0;k<G.arcnum;k++)
|
||||
{
|
||||
cout<<"输入第"<<k<<"条边的两个顶点:"<<endl;
|
||||
cin>>v1>>v2; // 4.1 输入边的两个邻接点
|
||||
i = LocateVex(G,v1); // 4.2 定位两个邻接点
|
||||
j = LocateVex(G,v2);
|
||||
if(i<0 || j<0 || i==j)
|
||||
{
|
||||
cout<<"顶点信息错,重新输入!"<<endl;
|
||||
k--;
|
||||
continue;
|
||||
}
|
||||
G.arcs[i][j]=1; // 4.3 修改邻接矩阵
|
||||
G.arcs[j][i]=1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
|
||||
{
|
||||
if(k<0 || k>=G.vexnum) // u不存在,返回false
|
||||
return false;
|
||||
else
|
||||
{
|
||||
v=G.vexs[k];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
|
||||
{
|
||||
int k;
|
||||
k=LocateVex(G,u);
|
||||
if(k<0 ) // u不存在,返回false
|
||||
return false;
|
||||
else // u存在,赋值
|
||||
{
|
||||
G.vexs[k] = v;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
//算法6.3 按值查找第一邻接点
|
||||
template <class DT>
|
||||
int FirstAdjVex(MGraph<DT> G,int u)
|
||||
{
|
||||
if(u<0 || u>=G.vexnum) // 顶点不存在
|
||||
return -1; // 无邻接点,返回-1
|
||||
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则,无邻接点,返回-1
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
int NextAdjVex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
|
||||
{
|
||||
if(u<0 || u>=G.vexnum || w<0
|
||||
|| w>=G.vexnum || G.arcs[u][w]==0 ) // 参数不合理
|
||||
return -1; // 无邻接点
|
||||
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
|
||||
if(G.arcs[u][j]!=0) // 如果有非零元,
|
||||
return j; // 第一个非零元所在列号,为其邻接点序号
|
||||
return -1; // 否则无邻接点,返回-1
|
||||
}
|
||||
|
||||
|
||||
template <class DT>
|
||||
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
|
||||
{
|
||||
DT w;
|
||||
int j;
|
||||
char ans;
|
||||
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
|
||||
{
|
||||
cout<<"无存储空间,不能插入!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中,顶点数增1
|
||||
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
|
||||
{
|
||||
G.arcs[G.vexnum-1][j]=0;
|
||||
G.arcs[j][G.vexnum-1]=0;
|
||||
}
|
||||
cout<<"创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
while(ans=='Y'|| ans=='y')
|
||||
{
|
||||
cout<<"输入另一个顶点值"<<endl;
|
||||
cin>>w;
|
||||
j=LocateVex(G,w);
|
||||
if(j>=0) // 顶点存在
|
||||
InsertArc(G,v,w);
|
||||
else
|
||||
cout<<w<<"顶点不存在!";
|
||||
cout<<"继续创建边吗(Y/N)?"<<endl;
|
||||
cin>>ans;
|
||||
};
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool InsertArc(MGraph<DT> &G,DT v,DT w) // 在值为v、w顶点间加边
|
||||
{ int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
|
||||
return false; // 不能插入边,返回false
|
||||
G.arcs[i][j]=1;
|
||||
G.arcs[j][i]=1;
|
||||
G.arcnum++;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除边
|
||||
{
|
||||
int i = LocateVex(G,v);
|
||||
int j = LocateVex(G,w);
|
||||
if(i<0||j<0||i == j) // 边不存在,返回false
|
||||
{
|
||||
cout<<"边不存在!"<<endl;
|
||||
return false;
|
||||
}
|
||||
G.arcs[i][j]=0; // 置邻接矩阵第 i 行第 j 列为零
|
||||
G.arcs[j][i]=0; // 置邻接矩阵第 i 列第 j 行为零
|
||||
G.arcnum--; // 边数减1
|
||||
return true;
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
|
||||
{
|
||||
int i,j;
|
||||
DT w;
|
||||
i = LocateVex(G,v); // 顶点定位
|
||||
if(i<0)
|
||||
{
|
||||
cout<<"顶点不存在!"<<endl; // 顶点不存在
|
||||
return false;
|
||||
}
|
||||
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的边
|
||||
{
|
||||
if(G.arcs[i][j]!=0)
|
||||
{
|
||||
GetVex(G,j,w);
|
||||
DeleteArc(G,v,w);
|
||||
}
|
||||
}
|
||||
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
|
||||
{
|
||||
G.vexs[j-1] = G.vexs[j];
|
||||
}
|
||||
G.vexnum--;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// 算法6.10
|
||||
template <class DT>
|
||||
void DFS(MGraph<DT> G,int v) // 连通图深度优先遍历
|
||||
{
|
||||
int w;
|
||||
visited[v] = true; // 先访问index
|
||||
cout<<G.vexs[v];
|
||||
for(w=0;w<G.vexnum;w++)
|
||||
{
|
||||
if(G.arcs[v][w]!=0 && !visited[w] )
|
||||
DFS(G,w);
|
||||
}
|
||||
//cout<<endl;
|
||||
}
|
||||
|
||||
// 算法6.9
|
||||
template <class DT>
|
||||
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
visited[i]=0;
|
||||
for( i=0;i<G.vexnum;i++) //对每个顶点进行深度递归
|
||||
{
|
||||
if(!visited[i])
|
||||
DFS(G,i);
|
||||
}
|
||||
cout<<endl;
|
||||
return ;
|
||||
}
|
||||
|
||||
// 算法 6.11 广度优先遍历
|
||||
template <class DT>
|
||||
void BFS(MGraph<DT> G,int v)
|
||||
{
|
||||
int w;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
cout<<G.vexs[v];
|
||||
visited[v]=ture;
|
||||
EnQueue(Q,v);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,u);
|
||||
for(w=Firstadjvex(G,u);w>=0;w=Nextadjvex(G,u,w)))
|
||||
if(!visited[w])
|
||||
{
|
||||
cout<<G.vexs[w];
|
||||
visited[w]=true;
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 算法6.12
|
||||
template <class DT>
|
||||
void BFSTranverse(MGraph<DT> G)
|
||||
{
|
||||
int i;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
visited[i]=0;
|
||||
for(i=0;i<G.vexnum;i++)
|
||||
{
|
||||
if(!visited[i])
|
||||
BFS(G,i);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template <class DT>
|
||||
bool BFSTraverse(MGraph<DT> G) // 广度优先遍历
|
||||
{
|
||||
int i;
|
||||
int u,w;
|
||||
LinkQueue<int> Q;
|
||||
InitQueue(Q);
|
||||
for(i = 0;i<G.vexnum;i++) //访问标识向量初始化
|
||||
visited[i] = false;
|
||||
for( i=0;i<G.vexnum;i++) //对每个未被访问的顶点进行广度优先遍历
|
||||
{
|
||||
if(!visited[i])
|
||||
{
|
||||
visited[i] = true;
|
||||
cout<<G.vexs[i]<<" ";
|
||||
EnQueue(Q,i);
|
||||
while(!QueueEmpty(Q))
|
||||
{
|
||||
DeQueue(Q,u);
|
||||
for(w=FirstAdjVex(G,u);w>=0;w=NextAdjVex(G,u,w))
|
||||
{
|
||||
if(!visited[w])
|
||||
{
|
||||
visited[w] = true;
|
||||
cout<<G.vexs[w];
|
||||
EnQueue(Q,w);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
cout<<endl;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user