数据结构实验—图与景区信息管理系统

利用图论中典型算法,实现下述功能:
1.创建景区景点图
2.查询景点信息
3.旅游景点导航(DFS 深度优先搜索)
4.搜索最短路径(迪杰斯特拉算法)
5.铺设电路规划(prim/kruscal算法)
main.cpp

#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include"Tourism.h"
#include"Graph.h"
using namespace std;
int main(void)
{
 int choice;
 while (true)
 {
  cout << "==== 景区管理系统 ====" << endl;
  cout << "1.创建景区景点图" << endl;
  cout << "2.查询景点信息" << endl;
  cout << "3.旅游景点导航" << endl;
  cout << "4.搜索最短路径" << endl;
  cout << "5.铺设电路规划" << endl;
  cout << "0.退出" << endl;
  cout << "请输入操作编号(0~5):" << endl;
  cin >> choice;
  switch (choice)
  {
  case 1:
   system("cls");
   CreateGraph();
   system("pause");
   break;
  case 2:
   system("cls");
   GetSpotInfo();
   system("pause");
   break;
  case 3:
   system("cls");
   TravelPath();
   system("pause");
   break;
  case 4:
   system("cls");
   FindShortPath();
   system("pause");
   break;
  case 5:
   system("cls");
   DesignPath();
   system("pause");
   break;
  case 0:
   cout << "退出系统" << endl;
   exit(0);
   break;
  default:
   cout << "输入错误编号 默认退出系统" << endl;
   exit(0);
   break;
  }
 }
}

Graph.h

#ifndef GRAPH_H_INCLUDED
#define GRAPH_H_INCLUDED
struct Vex
{
 int num;
 char name[20];
 char desc[1024];
};
struct Edge
{
 int vex1;
 int vex2;
 int weight;
};
struct CCgraph
{
 int m_aAdjMatrix[20][20];//邻接矩阵
 Vex m_aVexs[20];//顶点信息 里面有景点编号、名字、描述
 int m_nVexNum;//顶点个数
};//Graph对象,用于存储景区景点图
typedef struct Path
{
 int cVex[20];//保存一条路径
 Path *next;//保存下一条路径
}*PathList;;//*PathList是指向结构体的指针
void Init(void);
bool InsertVex(Vex sVex);
bool InsertEdge(Edge sEdge);
Vex GetVex(int nVex);
int FindEdge(int nVex, Edge aEdge[]);
void DFS(int nVex, bool bVisited[], int &nIndex, PathList &pList);
void DFSTraverse(int nVex, PathList &pList);
int FindShortPath(int nVexStart, int nVexEnd, Edge aPath[]);
int FindMinTree(int nStart, Edge aEdge[]);
#endif //GRAPH_H_INCLUDED

Graph.cpp

#define _CRT_SECURE_NO_WARNINGS//消除scanf警告
#include"Graph.h"
#include"Tourism.h"
#include<cstring>
#include<iostream>
#define INF 32767;
using namespace std;
CCgraph m_Graph;
//初始化图信息
void Init(void)
{
 m_Graph.m_nVexNum = 0;
 int i;
 for (i = 0; i < 20; i++)
 {
  m_Graph.m_aVexs[i].num = -1;
  strcpy(m_Graph.m_aVexs[i].name, "");
  strcpy(m_Graph.m_aVexs[i].desc, "");
  for (int j = 0; j < 20; j++)
   m_Graph.m_aAdjMatrix[i][j] = 0;
       
 }
}
//插入点
bool InsertVex(Vex sVex)
{
 if (m_Graph.m_nVexNum == 32767)
  return false;
 m_Graph.m_aVexs[m_Graph.m_nVexNum++] = sVex;
 return true;
}
//插入边
bool InsertEdge(Edge sEdge)
{
 if (sEdge.vex1 < 0 || sEdge.vex1 >= m_Graph.m_nVexNum ||
  sEdge.vex2 < 0 || sEdge.vex2 >= m_Graph.m_nVexNum)
  return false;
 m_Graph.m_aAdjMatrix[sEdge.vex1][sEdge.vex2] = sEdge.weight;
 m_Graph.m_aAdjMatrix[sEdge.vex2][sEdge.vex1] = sEdge.weight;
 return true;
}
Vex GetVex(int nVex){
 return m_Graph.m_aVexs[nVex];
}
/*
寻找周围景区 相连边存放于aEdge数组中
周围景区数目
*/
int FindEdge(int nVex, Edge aEdge[]) {
 int k = 0;
 for (int i = 0; i < m_Graph.m_nVexNum; i++)
 {
  if (m_Graph.m_aAdjMatrix[nVex][i] != 0)
  {
   aEdge[k].vex1 = nVex;
   aEdge[k].vex2 = i;
   aEdge[k].weight = m_Graph.m_aAdjMatrix[nVex][i];
   k++;
  }
 }
 return k; //返回周围景点的数目
}
void DFSTraverse(int nVex, PathList &pList) {
 bool bVisited[32767] = { false };
 int nIndex = 0;
 DFS(nVex, bVisited, nIndex, pList);
}
//顶点编号 记录某个顶点是否被遍历过 遍历的深度 遍历得到的结果
void DFS(int nVex, bool bVisited[], int &nIndex, PathList &pList) {
 bVisited[nVex] = true; //改为已访问
 pList->cVex[nIndex++] = nVex; //访问顶点nVex
 int nVexNum = 0;
 for (int i = 0; i < m_Graph.m_nVexNum; i++) {
  if (bVisited[i]) nVexNum++;
 }
 //判断是否所有顶点都访问过
 if (nVexNum == m_Graph.m_nVexNum) {
  pList->next = (PathList)malloc(sizeof(Path));
  for (int i = 0; i < m_Graph.m_nVexNum; i++){
   pList->next->cVex[i] = pList->cVex[i];
  }
  pList = pList->next;
  pList->next = NULL;//链表移动
 }
 else{
  for (int i = 0; i < m_Graph.m_nVexNum; i++)
  {
   if (!bVisited[i]&&(m_Graph.m_aAdjMatrix[nVex][i]>0)&& (m_Graph.m_aAdjMatrix[nVex][i]!=32767)){
    //递归调用得到一条路径
    DFS(i, bVisited, nIndex, pList);
    bVisited[i] = false; //得到一条路径后将访问的i点置为false
    nIndex--;//回溯
   }
  }
 }
}
//功能4.搜索最短路径 Dijkstra贪心算法 贪心策略、最优子结构
int FindShortPath(int nVexStart, int nVexEnd, Edge aPath[]) {
 //初始化最短路径
 int flag[20],pre[20]; //标记数组,前置顶点
 int dist[20],k;
 for (int i = 0; i < m_Graph.m_nVexNum; i++){ 
  flag[i] = 0; //默认都没置入集合
  pre[i] = -1; 
  if (m_Graph.m_aAdjMatrix[nVexStart][i] > 0||i == nVexStart) {
   dist[i] = m_Graph.m_aAdjMatrix[nVexStart][i];//两点距离
   pre[i] = nVexStart;   //当两个边直接相连时,pre初始化为起点
  }
  else{
   dist[i] = INF;//两点距离
  }
 }
 flag[nVexStart] = 1; //第一个并入的应该是nStartVex点
 int min;
 //遍历 m_Graph.m_nVexNum-1次:每次找出一个顶点的最短路径
 for (int i = 1; i < m_Graph.m_nVexNum; i++) {
  //寻找当前最小的路径
  min = INF;
  for (int j = 0; j < m_Graph.m_nVexNum; j++){
   if (flag[j]==0 && dist[j]<min){
    min = dist[j];
    k = j; //k是已经获得最短路径的那个点
   }
  }
  flag[k] = 1;
  if (k == nVexEnd) { //k为终点,返回边的数目
   break;
  }
  //将k作为中间点计算nVexSart到所有顶点的最短路径,进行扩充集合
  for (int j = 0; j < m_Graph.m_nVexNum; j++) {
   int tmp;
   if (m_Graph.m_aAdjMatrix[k][j] == 0){
    tmp = INF;
   }
   else{
    tmp= min + m_Graph.m_aAdjMatrix[k][j];
   }
   if (flag[j]==0 && (tmp<dist[j])){
    dist[j] = tmp;
    pre[j] = k;
   }
  }
 }
 //cout << dist[nVexEnd] << endl;
 int Num = 0; //总共Num条路径
 int i = nVexEnd;//从终点开始回溯
 while (i != nVexStart){
  aPath[Num].vex2 = i;
  aPath[Num].vex1 = pre[i];
  aPath[Num].weight = m_Graph.m_aAdjMatrix[pre[i]][i];
  i = pre[i];
  Num++;
 }
 //cout << Num << endl;
 return Num;
}
//功能5.铺设电路规划 Prim贪心算法 贪心策略 最优子结构
int FindMinTree(int nStart,Edge aEdge[]) {
 int flag[20],closest[20];//标记数组 前置顶点
 int lowcost[20];//最近顶点
 for (int i = 0; i < m_Graph.m_nVexNum; i++) { //flag、closest、lowcost集合初始化
  closest[i] = -1;
  flag[i] =  0 ;
  if (m_Graph.m_aAdjMatrix[nStart][i] > 0 || i == nStart) {
    lowcost[i] = m_Graph.m_aAdjMatrix[nStart][i];
    closest[i] = nStart;
  }
  else{
   lowcost[i] = INF;
  }
 }
 flag[nStart] = 1;
 int Num = 0;
 //找出m_Graph.m_nVexNum-1条边
 int min,k;
 for (int i = 1; i < m_Graph.m_nVexNum; i++) {
  min = INF;
  for (int j = 0; j < m_Graph.m_nVexNum; j++){
   if (flag[j]==0&&lowcost[j]<min){
    min = lowcost[j];
    k = j;
   }
  }
  flag[k] = 1;
  for (int j = 0; j <m_Graph.m_nVexNum ; j++){
   if (flag[j] == 0 && m_Graph.m_aAdjMatrix[k][j] < lowcost[j]&&m_Graph.m_aAdjMatrix[k][j]!=0) {
    lowcost[j] = m_Graph.m_aAdjMatrix[k][j];
    closest[j] = k;
   }
  }
  //存储各边信息至aEdge数组中
  flag[closest[k]] = 1;
  aEdge[Num].vex1 = closest[k];
  aEdge[Num].vex2 = k;
  aEdge[Num].weight = m_Graph.m_aAdjMatrix[closest[k]][k];
  Num++;
 }
 return Num;//返回边的数目
}

Tourism.h

#ifndef TOURISM_H_INCLUDED
#define TOURISM_H_INCLUDED
void CreateGraph(void);
void GetSpotInfo(void);
void TravelPath();
void FindShortPath(void);
void DesignPath(void);
#endif // TOURISM_H_INCLUDED

Toutism.cpp

#define _CRT_SECURE_NO_WARNINGS//消除scanf警告
#include"Tourism.h"
#include"Graph.h"
#include<iostream>
#include<cstring>
using namespace std;
extern CCgraph m_Graph;
//功能1. 创建景区顶点
void CreateGraph(void){
 Init();
 cout << "===== 创建景区管理图 =====" << endl;
 int num;
 FILE *InVex = fopen("D:\\Vex.txt", "r");
 fscanf(InVex, "%d", &num);
 cout << "顶点数目:" << num << endl;
 cout << "----- 顶点 -----" << endl;
 for (int i = 0; i < num; i++)
 {
  Vex vex;
  fscanf(InVex, "%d", &(vex.num));
  fscanf(InVex, "%s", vex.name);
  fscanf(InVex, "%s", vex.desc);
  cout << vex.num << "-" << vex.name << endl;
  InsertVex(vex);
 }
 fclose(InVex);
 cout << "----- 边 -----" << endl;;
 FILE *InEdge = fopen("D:\\Edge.txt","r");
 while(!feof(InEdge))
 {
  Edge edge;
  fscanf(InEdge, "%d %d %d", &edge.vex1, &edge.vex2, &edge.weight);
  cout << "<v" << edge.vex1 << ",v" << edge.vex2 << "> " << edge.weight << endl;
  InsertEdge(edge);
 }
 fclose(InEdge);
 /*
 for (int i = 0; i < 7; i++)
 {
  for (int j = 0; j < 7; j++) {
   cout << m_Graph.m_aAdjMatrix[i][j]<<"  ";
  }
  cout << endl;
 }
 */
}
//功能2. 查询景点信息 直接查询
void GetSpotInfo(void)
{
 if (m_Graph.m_nVexNum == 0) {
  cout << "景区无信息 请首先创建景区信息" << endl;
  return;
 }
 cout << "===== 查询景点信息 =====" << endl;
 int i;
 for (i = 0; i < m_Graph.m_nVexNum; i++)
  cout << m_Graph.m_aVexs[i].num << "-" << m_Graph.m_aVexs[i].name << endl;
 cout << "请输入想要查询的景点编号:";
 int Num;
 cin >> Num;
 if (Num >= m_Graph.m_nVexNum) {
  cout << "编号输入错误 默认退出" << endl;
  return;
 }
 Vex vex = GetVex(Num);
 cout << vex.desc << endl;
 cout << "----- 周围景区 ------" << endl;
 Edge aEdge[100];
 int sum_Edge=FindEdge(Num, aEdge);
 for (i = 0; i < sum_Edge; i++) {
  if (aEdge[i].weight!=32767){
   cout << m_Graph.m_aVexs[aEdge[i].vex1].name << "->" <<
    m_Graph.m_aVexs[aEdge[i].vex2].name << " " << aEdge[i].weight << "m" << endl;
  }
 }
}
//功能3. 旅游景点导航 DFS算法改进
void TravelPath() {
 if (m_Graph.m_nVexNum == 0) {
  cout << "景区无信息 请首先创建景区信息" << endl;
  return;
 }
 for (int i = 0; i < m_Graph.m_nVexNum; i++) 
  cout << m_Graph.m_aVexs[i].num << "-" << m_Graph.m_aVexs[i].name << endl;
 cout << "请输入起始点编号: ";
 int Num;
 cin >> Num;
 if (Num < 0 || Num >= m_Graph.m_nVexNum) {
  cout << "编号输入错误 默认退出" << endl;
  return;
 }
 cout << "导航路线为:" << endl;
 PathList pList=(PathList)malloc(sizeof(Path));
 PathList Head = pList;
 //调用DFSTraverse函数
 DFSTraverse(Num, pList);
 pList = Head ;
 pList = pList->next;
 int i = 1;
 while (pList!=NULL){
  cout << "路线" << i << ":";
  for (int i = 0; i < m_Graph.m_nVexNum; i++){
   cout << m_Graph.m_aVexs[pList->cVex[i]].name << "  ";
  }
  cout << endl;
  pList = pList->next;
  i++;
 }
 free(pList);
 pList = NULL;
 Head = NULL;
}
//功能4.搜索最短路径 Dijkstra贪心算法 贪心策略、最优子结构
//参考:https://blog.csdn.net/chen134225/article/details/79886928
void FindShortPath(void) {
 if (m_Graph.m_nVexNum == 0) {
  cout << "景区无信息 请首先创建景区信息" << endl;
  return;
 }
 int nStart, nEnd;
 cout << "请输入起点的编号:" << endl;
 cin >> nStart;
 cout << "请输入终点的编号:" << endl;
 cin >> nEnd;
 if (nStart > nEnd || nEnd >= m_Graph.m_nVexNum) {
  cout << "编号输入错误 默认退出" << endl;
  return;
 }
 if (nStart == nEnd) {
  cout << "最短距离为:0" << endl;
  return;
 }
 Edge aPath[32767];
 int Num=FindShortPath(nStart, nEnd, aPath);
 cout << "最短路径为:"<<endl;
 int Path = 0;
 for (int i = Num-1; i>=0; i--){
  cout << m_Graph.m_aVexs[aPath[i].vex1].name <<"->";
  cout << m_Graph.m_aVexs[aPath[i].vex2].name << endl;
  Path += aPath[i].weight;
 }
 cout << "最短路径为:" << Path << endl;
}
//功能5.铺设电路规划 Prim贪心算法
void DesignPath(void){
 if (m_Graph.m_nVexNum == 0) {
  cout << "景区无信息 请首先创建景区信息" << endl;
  return;
 }
 int n = m_Graph.m_nVexNum - 1;
 cout<< "请输入您要铺设电路的起始顶点:输入(" <<0<<"/"<<n<<")"<< endl;
 int nStart;
 cin >> nStart;
 if (nStart!=0&&nStart!=n) {
  cout << "编号输入错误 默认退出" << endl;
  return;
 }
 Edge aEdge[20];
 int Num = FindMinTree(nStart, aEdge),Path=0;
 //输出
 cout << "在以下两个景点之间铺设电路:" << endl;
    for (int i = 0; i < Num; i++){
  cout << m_Graph.m_aVexs[aEdge[i].vex1].name << " - " << m_Graph.m_aVexs[aEdge[i].vex2].name << " "
   << aEdge[i].weight << "m" << endl;
  Path += aEdge[i].weight;
 }
 cout << "铺设电路的总长度为:" << Path <<"m"<< endl;
}

前几天抽时间肝完的,整个实验难度不大,书上都给出了各个文件函数调用顺序,写的时候主要是一些小bug。
自己算法能力还差很多,以后尤其要注意这些前人已发明的算法使用,牢记于心,在一些算法题中通过这些算法帮助快捷地解决问题。
加油…还有连连看。。

  • 15
    点赞
  • 92
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值