目录
一、功能函数(fun.cpp)
#include <iostream>
#include "before.h"
using namespace std;
//***********************************//
//队列的相关函数定义
//初始化空队列、判断队空、求队列的长度、取队首、入队列、出队列
status InitQueue(LinkQueue &Q)
{
Q.front = Q.rear = new QNode;
Q.front->next = NULL;
return OK;
}//初始化
bool QueueEmpty(LinkQueue Q)
{
if(Q.front == Q.rear ) return true;
else return false;
}//判断队列是否为空
status EnQueue(LinkQueue &Q,QElemType e)
{
QueuePtr p = new QNode;
p->data = e;
p->next = NULL;
Q.rear->next = p;
Q.rear = p;
return OK;
}//入队列
status DeQueue(LinkQueue &Q,QElemType &e)
{
QueuePtr p = Q.front->next;
if(Q.front == Q.rear )return ERROR;
e = p->data;
Q.front->next = p->next; //不能用p因为p不能代表Q.front->next
if(Q.rear == p)Q.rear = Q.front;
delete p;
return OK;
}//删除头元素
//*************************************//
//邻接矩阵存储图的相关函数定义
status CreateUDG(AMGragh &G)
{
cout << "---请输入总顶点数、总边数:";
cin >> G.vexnum >> G.arcnum; //输入总顶点数、总边数
cout << "---请依次输入点的信息:" << endl;
for(int i = 0;i < G.vexnum;i ++)
cin >> G.Vex[i]; //依次输入点的信息
for(int i = 0;i < G.vexnum;i ++)
for(int j = 0;j < G.vexnum;j ++)
G.Arc[i][j] = MaxInt;
for(int k = 0;k < G.arcnum;k ++)
{
VertexType v1,v2;
cout << "---请输入有边的两个顶点值:";
cin >> v1 >> v2;
int i = LocateVex(G,v1);int j = LocateVex(G,v2);//确定v1,v2在G中的位置
G.Arc[i][j] = 1;
G.Arc[j][i] = G.Arc[i][j];
}
return OK;
}//邻接矩阵的无向图的创建
status CreateDG(AMGragh &G)
{
cout << "---请输入总顶点数、总边数:";
cin >> G.vexnum >> G.arcnum; //输入总顶点数、总边数
cout << "---请依次输入点的信息:" << endl;
for(int i = 0;i < G.vexnum;i ++)
cin >> G.Vex[i]; //依次输入点的信息
for(int i = 0;i < G.vexnum;i ++)
for(int j = 0;j < G.vexnum;j ++)
G.Arc[i][j] = MaxInt;
for(int k = 0;k < G.arcnum;k ++)
{
VertexType v1,v2;
cout << "---请输入有向的边的顶点值:";
cin >> v1 >> v2;
int i = LocateVex(G,v1);int j = LocateVex(G,v2);//确定v1,v2在G中的位置
G.Arc[i][j] = 1;
}
return OK;
}//邻接矩阵的有向图的创建
status LocateVex(AMGragh G,VertexType v)
{
for(int i = 0;i < G.vexnum;i ++)
{
if(G.Vex[i] == v) return i; //存在该顶点就返回其下标
}
return OVERFLOW; //不存在该顶点
}//查找顶点值在顶点表的下标
status CountDe_UDG(AMGragh G,VertexType v)
{
int index = LocateVex(G,v); //定位顶点在顶点表中的下标
if(index == OVERFLOW) return OVERFLOW; //无
int sum = 0;
for(int i = 0;i < G.vexnum;i ++)
sum += G.Arc[index][i];
return sum; //返回对应的度
}//计算无向图顶点的度
status CountDeIn_DG(AMGragh G,VertexType v)
{
int j = LocateVex(G,v); //定位顶点在顶点表中的下标
if(j == OVERFLOW) return OVERFLOW; //无
int sum = 0;
for(int i = 0;i < G.vexnum;i ++)
sum += G.Arc[i][j];
return sum; //返回有向图入度
}//有向图入度的计算
status CountDeOut_DG(AMGragh G,VertexType v)
{
int i = LocateVex(G,v); //定位顶点在顶点表的下标
int sum = 0;
for(int j = 0;j < G.vexnum;j ++)
sum += G.Arc[i][j];
return sum; //返回有向图的出度
}//有向图出度的计算
status CountDe_DG(AMGragh G,VertexType v)
{
return CountDeIn_DG(G,v)+CountDeOut_DG(G,v);
}//有向图顶点度的计算
bool visit[MaxVertexNum];
void DFS(AMGragh G,int v)
{
cout << G.Vex[v];
visit[v] = true; //访问第v个顶点
for(int j = 0;j < G.vexnum;j ++)
{
if((G.Arc[v][j]!=0) && (!visit[j])) DFS(G,j);
}
}//邻接矩阵的深度优先搜索算法
void DFSTraverse(AMGragh G)
{
for(int i = 0;i < G.vexnum;i ++) visit[i] = false;
for(int i = 0;i < G.vexnum;i ++)
{
if(!visit[i]) DFS(G,i);
}
}
void BFS(AMGragh G,int v)
{
int i,j;
int k;
LinkQueue Q;
for(i=0;i<G.vexnum;i++) visit[i] = 0; //初始化标记符
InitQueue(Q); //队列初始化
for (i = 0; i < G.vexnum; i++)
{
if (!visit[i]) //判断以这个顶点为基准,有连接的其他顶点
{
visit[i] = 1; //标记遍历的这个顶点
printf("%c ", G.Vex[i]);
EnQueue(Q, i); //入队
while (!QueueEmpty(Q)) //队列中还有数据,说明这个顶点连接的其他顶点还没有遍历完
{
DeQueue(Q,i); //出队
for (j = 0; j < G.vexnum; j++)
{
//以这个顶点为基准,遍历其他连接的顶点
if (!visit[j] && G.Arc[i][j] != 0)
{
visit[j] = 1; //与之连接的顶点作上标记,便于后序顶点跳过相同的遍历
printf("%c ", G.Vex[j]);//输出与之相邻连接的顶点
EnQueue(Q, j); //让与之连接的顶点其位置入队
}
}
}
}
}
}//邻接矩阵的广度优先搜索算法
void BFSTraverse(AMGragh G)
{
for(int i = 0;i < G.vexnum;i ++) visit[i] = false;
for(int i = 0;i < G.vexnum;i ++)
{
if(!visit[i]) BFS(G,i);
}
}
void PrintAMG(AMGragh G)
{
for(int i = 0;i < G.vexnum;i ++)
{
for(int j = 0;j < G.vexnum;j ++)
{
cout << G.Arc[i][j] << " ";
}
cout << endl;
}
}//邻接矩阵的遍历
//*****************************************//
//邻接表的相关函数的定义
status CreateUDG_AdjList(ALGragh &G)
{
cout << "---请输入总定点数、总边数:";
cin >> G.vexnum >> G.arcnum; //输入总顶点数、总边数
cout << "---请依次输入顶点的值:" << endl;
for(int i = 0;i < G.vexnum;i ++) //构造表头节点表
{
cin >> G.vertices[i].data; //输入顶点的值
G.vertices[i].firstarc = NULL; //初始化顶点的头节点为空
}
for(int k = 0;k < G.arcnum;k ++) //构造边表
{
VertexType v1,v2;
cout << "---请输入边的相关顶点:";
cin >> v1 >> v2; //输入一条边依附的两个顶点
int i = LocateVex_AdjList(G,v1);
int j = LocateVex_AdjList(G,v2);
ArcNode *p1 = new ArcNode; //生成一个新的边节点
p1->adjvex = j;
p1->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p1; //将新节点p1插入顶点vi的边表头部
ArcNode *p2 = new ArcNode; //生成一个对称的新边节点
p2->adjvex = i;
p2->nextarc = G.vertices[j].firstarc;
G.vertices[j].firstarc = p2; //将新节点p2插入顶点vj的边表头部
}
return OK;
}//创建无向图的邻接表
status CreateDG_AdjList(ALGragh &G)
{
cout << "---请输入总定点数、总边数:";
cin >> G.vexnum >> G.arcnum; //输入总顶点数、总边数
cout << "---请依次输入顶点的值:" << endl;
for(int i = 0;i < G.vexnum;i ++) //构造表头节点表
{
cin >> G.vertices[i].data; //输入顶点的值
G.vertices[i].firstarc = NULL; //初始化顶点的头节点为空
}
for(int k = 0;k < G.arcnum;k ++) //构造边表
{
VertexType v1,v2;
cout << "---请按顺序输入边的顶点:";
cin >> v1 >> v2; //输入一条边依附的两个顶点
int i = LocateVex_AdjList(G,v1);
int j = LocateVex_AdjList(G,v2);
ArcNodeList p1 = new ArcNode; //生成一个新的边节点
p1->adjvex = j;
p1->nextarc = G.vertices[i].firstarc;
G.vertices[i].firstarc = p1; //将新节点p1插入顶点vi的边表头部
}
return OK;
}//创建有向图的邻接表
status LocateVex_AdjList(ALGragh G,VertexType v)
{
for(int i = 0;i < G.vexnum;i ++)
{
if(v == G.vertices[i].data) return i; //找到后返回下标值
}
return OVERFLOW; //未找到
}//查找某节点在头节点表的下标
status CountDe_UDG_AdjList(ALGragh G,VertexType v)
{
int index = LocateVex_AdjList(G,v);
if(index == OVERFLOW) return OVERFLOW; //无该节点,返回
int sum = 0;
ArcNode *p; //有几个节点就是几度
p = G.vertices[index].firstarc;
while(p != NULL)
{
sum ++;
p = p->nextarc;
}
return sum; //返回度
}//计算无向图的度
status CountDeIn_DG_AdjList(ALGragh G,VertexType v)
{
int index = LocateVex_AdjList(G,v);
if(index == OVERFLOW) return OVERFLOW; //无该节点,返回
ArcNode *p;
int sum = 0;
for(int i = 0;i < G.vexnum;i ++)
{
p = G.vertices[i].firstarc;
while(p != NULL)
{
int j = p->adjvex;
if(v == G.vertices[j].data) sum ++;
p = p->nextarc;
}
}
return sum; //返回入度
}//计算有向图的入度
status CountDeOut_DG_AdjList(ALGragh G,VertexType v)
{
int index = LocateVex_AdjList(G,v);
if(index == OVERFLOW) return OVERFLOW; //无该节点,返回
int sum = 0;
ArcNode *p; //有几个节点就是几度
p = G.vertices[index].firstarc;
while(p != NULL)
{
sum ++;
p = p->nextarc;
}
return sum; //返回出度
}//计算有向图的出度
status CountDe_DG_AdjList(ALGragh G,VertexType v)
{
int index = LocateVex_AdjList(G,v);
if(index == OVERFLOW) return OVERFLOW; //无该节点,返回
return CountDeIn_DG_AdjList(G,v)+CountDeOut_DG_AdjList(G,v);
}//计算有向图的度
void DFS_AdjList(ALGragh G,int v)
{
ArcNodeList p; //指向边链表结点指针
if(!visit[v]) cout << G.vertices[v].data;
visit[v]=true; //辅助数组该位置设置为1
p=G.vertices[v].firstarc; //指向边链表结点首结点
while(p != NULL) //指针不为空继续循环
{
if(!visit[p->adjvex]) DFS_AdjList(G,p->adjvex);
p=p->nextarc; //继续指向下一个结点
}
}//有向图的深度优先搜索算法
void DFSTraverse_AdjList(ALGragh G)
{
// 对图G进行深度优先搜索
for(int i = 0;i < G.vexnum;i ++) visit[i] = false;
for(int i = 0;i < G.vexnum;i ++)
{
if(!visit[i]) DFS_AdjList(G,i);
}
}
void BFS_AdjList(ALGragh G,int v)
{
// 从顶点v出发,对图G进行广度优先搜索
int u;
LinkQueue Q;
ArcNode *p;
InitQueue(Q);
cout<<G.vertices[v].data;
visit[v] = true;
EnQueue(Q,v);
while(!QueueEmpty(Q))
{
DeQueue(Q,u);
for(p = G.vertices[u].firstarc;p != NULL;p = p->nextarc)
{
if(!visit[p->adjvex])
{
cout << G.vertices[p->adjvex].data;
visit[p->adjvex] = true;
EnQueue(Q,p->adjvex);
}
}
}
}//BFS图的遍历:广度优先搜索
void BFSTraverse(ALGragh G)
{
// 对图G进行广度优先搜索
for(int i = 0;i < G.vexnum;i ++) visit[i] = false;
for(int i = 0;i < G.vexnum;i ++)
{
if(!visit[i])
{
BFS_AdjList(G,i);
}
}
}//BFSTraverse
void PrintAdjList(ALGragh G)
{
for(int i = 0;i < G.vexnum;++ i)
{
cout << G.vertices[i].data;
if(G.vertices[i].firstarc != NULL)
{
ArcNode *p = G.vertices[i].firstarc;//从顶点开始遍历
while(p)
{
cout << "->" << G.vertices[p->adjvex].data;
p = p->nextarc;
}
cout << "->NULL" << endl;
}
else cout << "->NULL" <<endl;
}
}//遍历邻接表
//调用菜单
void Menu()
{
printf("\t\t\t************************此为图的表示法的菜单**************************\n");
printf("\t\t\t\t1、邻接矩阵 2、邻接表 \n");
printf("\t\t\t\t0、退出当前操作系统 \n");
printf("\t\t\t********************************************************************\n");
}//调用菜单的打印
void Menu_AMGragh()
{
printf("\t\t\t************************此为邻接矩阵的菜单*****************************\n");
printf("\t\t\t\t1、无向图的创建 2、有向图的创建 \n");
printf("\t\t\t\t3、无向图的度 4、有向图某节点的入度 \n");
printf("\t\t\t\t5、有向图某节点的出度 6、有向图某节点的度 \n");
printf("\t\t\t\t7、无向图的深度优先搜索算法 8、无向图的广度优先搜索算法 \n");
printf("\t\t\t\t0、退出当前操作系统 \n");
printf("\t\t\t**********************************************************************\n");
}//邻接矩阵菜单的打印
void Menu_ALGragh()
{
printf("\t\t\t*************************此为邻接表的菜单******************************\n");
printf("\t\t\t\t1、无向图的创建 2、有向图的创建 \n");
printf("\t\t\t\t3、无向图的度 4、有向图某节点的入度 \n");
printf("\t\t\t\t5、有向图某节点的出度 6、有向图某节点的度 \n");
printf("\t\t\t\t7、有向图的深度优先搜索算法 8、有向图的广度优先算法 \n");
printf("\t\t\t\t0、退出当前操作系统 \n");
printf("\t\t\t**********************************************************************\n");
}//邻接表菜单的打印
//
//Created by somewon on 2022/11/22.
//
二、主函数(main.cpp)
#include <iostream>
#include "before.h"
using namespace std;
int main()
{
int CH;
do {
Menu();
cout << "---请输入你的选择:";
cin >> CH;
int fine,order = -1;
if(CH == 1) //邻接矩阵的相关函数调用
{
int ch;
do {
Menu_AMGragh();
cout << "---请输入你的选择:";
cin >> ch;
AMGragh G,T;
VertexType v;
switch(ch)
{
case 1:
fine = CreateUDG(G);
if(fine == OK)
{
cout << "无向图G的邻接矩阵创建完成!" << endl;
cout << "当前无向图G的邻接矩阵遍历为:" << endl;
PrintAMG(G);
}
else cout << "创建失败!请重新进行操作!" << endl;
break;
case 2:
fine = CreateDG(T);
if(fine == OK)
{
cout << "有向图T的邻接矩阵创建完成!" << endl;
cout << "当前有向图T的邻接矩阵遍历为:" << endl;
PrintAMG(G);
}
else cout << "创建失败!请重新进行操作!" << endl;
break;
case 3:
cout << "---请输入你需要查看的节点值:";
cin >> v;
fine = CountDe_UDG(G,v);
if(fine == OVERFLOW) cout << "该节点的值不存在于无向图G中!" << endl;
else cout << "当前无向图G的所求节点的度为:" << fine << endl;
break;
case 4:
cout << "---请输入你需要查看的节点值:";
cin >> v;
fine = CountDeIn_DG(T,v);
if(fine == OVERFLOW) cout << "该节点的值不存在于有向图T中!" << endl;
else cout << "当前有向图T的所求节点的入度为:" << fine << endl;
break;
case 5:
cout << "---请输入你需要查看的节点值:";
cin >> v;
fine = CountDeOut_DG(T,v);
if(fine == OVERFLOW) cout << "该节点的值不存在于有向图T中!" << endl;
else cout << "当前有向图T的所求节点的出度为:" << fine << endl;
break;
case 6:
cout << "---请输入你需要查看的节点值:";
cin >> v;
fine = CountDe_DG(T,v);
if(fine == OVERFLOW) cout << "该节点的值不存在于有向图T中!" << endl;
else cout << "当前有向图T的所求节点的度为:" << fine << endl;
break;
case 7:
cout << "无向图的深度优先搜索算法遍历为:" << endl;
DFSTraverse(G);
cout << endl;
break;
case 8:
cout << "无向图的广度优先搜索算法遍历为:" << endl;
BFSTraverse(G);
cout << endl;
break;
case 0:
goto END;
}
}while(ch);
}
else if(CH == 2) //邻接表的相关函数调用
{
int ch;
do {
Menu_ALGragh();
cout << "---请输入你的选择:";
cin >> ch;
ALGragh G,T;
VertexType v;
switch(ch)
{
case 1:
fine = CreateUDG_AdjList(G);
if(fine == OK)
{
cout << "无向图G的邻接表创建完成!" << endl;
cout << "当前无向图G的邻接表遍历为:" << endl;
PrintAdjList(G);
}
else cout << "创建失败!请重新进行操作!" << endl;
break;
case 2:
fine = CreateDG_AdjList(T);
if(fine == OK)
{
cout << "有向图T的邻接表创建完成!" << endl;
cout << "当前有向图T的邻接表遍历为:" << endl;
PrintAdjList(T);
}
else cout << "创建失败!请重新进行操作!" << endl;
break;
case 3:
cout << "---请输入你需要查看的节点值:";
cin >> v;
fine = CountDe_UDG_AdjList(G,v);
if(fine == OVERFLOW) cout << "该节点的值不存在于无向图G中!" << endl;
else cout << "当前无向图G的所求节点的度为:" << fine << endl;
break;
case 4:
cout << "---请输入你需要查看的节点值:";
cin >> v;
fine = CountDeIn_DG_AdjList(T,v);
if(fine == OVERFLOW) cout << "该节点的值不存在于有向图T中!" << endl;
else cout << "当前有向图T的所求节点的入度为:" << fine << endl;
break;
case 5:
cout << "---请输入你需要查看的节点值:";
cin >> v;
fine = CountDeOut_DG_AdjList(T,v);
if(fine == OVERFLOW) cout << "该节点的值不存在于有向图T中!" << endl;
else cout << "当前有向图T的所求节点的出度为:" << fine << endl;
break;
case 6:
cout << "---请输入你需要查看的节点值:";
cin >> v;
fine = CountDe_DG_AdjList(T,v);
if(fine == OVERFLOW) cout << "该节点的值不存在于有向图T中!" << endl;
else cout << "当前有向图T的所求节点的度为:" << fine << endl;
break;
case 7:
cout << "有向图的深度优先搜索算法遍历为:" << endl;
DFSTraverse_AdjList(T);
cout << endl;
break;
case 8:
cout << "有向图的广度优先搜索算法遍历为:" << endl;
BFSTraverse(T);
cout << endl;
break;
case 0:
goto END;
}
}while(ch);
}
else if(CH == 0) goto ENDD;
else cout << "无该选择!" << endl;
END:
cout << "退出当前操作系统成功!" << endl;
}while(CH != 0);
ENDD:
cout << "当前项目运行完毕!" << endl;
return 0;
}
//
//Created by somewon on 2022/11/22.
//
三、头文件(before.h)
#ifndef _BEFORE_H
#define _BEFORE_H
#define OK 1
#define ERROR 0
#define OVERFLOW (-1)
#define MaxVertexNum 100 //顶点数目的最大值
#define MaxInt 0 //初始化极大值
typedef int status; //函数返回数据类型
typedef char VertexType; //顶点数据类型
typedef int ArcType; //带权图边上权值的类型、边表数据类型
//typedef int OtherInfo; //邻接表中边相关的信息
//邻接矩阵法
typedef struct{
VertexType Vex[MaxVertexNum]; //顶点表
ArcType Arc[MaxVertexNum][MaxVertexNum]; //邻接矩阵、边表
int vexnum,arcnum; //图的当前顶点数和边数/弧数
}AMGragh;
//邻接矩阵的图的相关函数的声明
status CreateUDG(AMGragh &G); //邻接矩阵的无向图图的创建
status CreateDG(AMGragh &G); //有向图的创建
status LocateVex(AMGragh G,VertexType v); //查找顶点值在顶点表的下标
status CountDe_UDG(AMGragh G,VertexType v); //无向图顶点度的计算
status CountDeIn_DG(AMGragh G,VertexType v); //有向图顶点入度的计算
status CountDeOut_DG(AMGragh G,VertexType v); //有向图顶点出度的计算
status CountDe_DG(AMGragh G,VertexType v); //有向图顶点的度的计算
void DFS(AMGragh G,int v); //邻接矩阵的深度优先搜索算法
void DFSTraverse(AMGragh G);
void BFS(AMGragh G,int v); //邻接矩阵的广度优先搜索算法
void BFSTraverse(AMGragh G);
void PrintAMG(AMGragh G);
//邻接表法
typedef struct ArcNode //边结点
{
int adjvex; //该边所指向的顶点的位置
struct ArcNode * nextarc; //指向下一条边的指针
// OtherInfo info; //和边相关的信息
}ArcNode , *ArcNodeList;
typedef struct VNode //顶点信息
{
VertexType data; //顶点信息
ArcNode *firstarc; //指向第一条边/弧
}VNode,AdjList[MaxVertexNum]; //AdjList存储顶点
typedef struct
{
AdjList vertices; //顶点数组
int vexnum,arcnum; //当前图的顶点数、边数
}ALGragh;
//邻接表的图的相关函数的声明
status CreateUDG_AdjList(ALGragh &G); //无向图的创建
status CreateDG_AdjList(ALGragh &G); //有向图的创建
status LocateVex_AdjList(ALGragh G,VertexType v); //查找顶点在顶点表中的下标
status CountDe_UDG_AdjList(ALGragh G,VertexType v); //计算无向图某顶点的度
status CountDeIn_DG_AdjList(ALGragh G,VertexType v); //计算有向图某顶点的入度
status CountDeOut_DG_AdjList(ALGragh G,VertexType v); //计算有向图某顶点的出度
status CountDe_DG_AdjList(ALGragh G,VertexType v); //计算有向图某顶点的度
void DFS_AdjList(ALGragh G,int v); //邻接表的深度优先搜索算法
void DFSTraverse_AdjList(ALGragh G);
void BFS_AdjList(ALGragh G,int v); //邻接表的广度优先搜索算法
void BFSTraverse(ALGragh G);
void PrintAdjList(ALGragh G);
//队列的相关函数声明
typedef int QElemType;
typedef struct QNode
{
QElemType data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct{
QueuePtr front;//队头指针
QueuePtr rear; //队尾指针
}LinkQueue;
status InitQueue(LinkQueue &Q);
bool QueueEmpty(LinkQueue Q);
status EnQueue(LinkQueue &Q,QElemType e);
status DeQueue(LinkQueue &Q,QElemType &e);
//相关菜单的函数声明
void Menu(); //大菜单
void Menu_AMGragh(); //邻接矩阵的菜单
void Menu_ALGragh(); //邻接表的菜单
#endif
//
//Created by somewon on 2022/11/22.
//
四、运行结果截图展示
所测试样例(有向图无向图均为此)
1、邻接矩阵
无向图的深度优先搜索算法
无向图的节点度的相关计算
有向图的相关节点度的计算
2、邻接表
有向图的节点相关度的计算
无向图的节点的相关度的计算
有向图的深度优先搜索算法