一、第一阶段:景区景点信息创建和景点信息查询
在这一阶段主要是建立数据结构,读取文本文件中的景点信息,并利用景点图的邻接矩阵完成景点信息搜索
搜索代码如下:
int CGraph::FindEdge(int nVex)//查询与指定顶点相连的边
{
cout << CGraph::m_aVexs[nVex].name << endl;
cout << CGraph::m_aVexs[nVex].desc << endl;
cout << "**********周边景区**********" << endl;
int k = 0;
for (int i = 0; i < CGraph::m_nVexNum; i++)
{
if (CGraph::m_aAdjMatrix[nVex][i] != 0)
{
cout << CGraph::m_aVexs[nVex].name << "->" << CGraph::m_aVexs[i].name << "\t" << CGraph::m_aAdjMatrix[nVex][i] << endl;
k++;
}
}
return k;
}
二、利用邻接矩阵进行图的深度优先搜索,实现景点导航功能
由用户输入起点位置,输出所有路径(经过景区所有景点一次)。
深度优先遍历代码如下(递归方式):
void CGraph::DFS(int nVex, int visited[],int aPath[], int& nIndex,Path* Pathlist)
{
visited[nVex] = 1;//将结点nVex状态改为已访问
aPath[nIndex++] = nVex;
if (nIndex == CGraph::m_nVexNum)//顶点遍历完毕,保存一条路径
{
Path* p = new Path;
p->vexs = new int[CGraph::m_nVexNum];
for (int i = 0; i < CGraph::m_nVexNum; i++)
p->vexs[i] = aPath[i];
Path* q = Pathlist;
while (q->next != NULL)
q = q->next;
q->next = p;
}
else
{
for (int i = 0; i < CGraph::m_nVexNum; i++)
{
if (CGraph::m_aAdjMatrix[nVex][i] != 0 && visited[i] == 0)
{
CGraph::DFS(i, visited, aPath, nIndex,Pathlist);//递归遍历
visited[i] = 0;
nIndex--;
}
}
}
}
刚开始设置了一个尾指针Tail指向链表的尾部,插入结点选用尾插法,后来发现比较麻烦,然后每次都遍历找到链表最后一个结点,但是这样时间开销比较大,现在我想起来了头插法,我好蠢。。
三、第三阶段:搜索两个顶点之间的最短路径
采用Dijkstra方法查找最短路径,但是我之前没有学Dijkstra方法,在进行实验之前去学习了一下这个方法,学习到的大概如下:
1.将顶点集合划分为两部分:S和U。顶点S中保存已经找到到达起点最短路径的顶点,U中保存未找到最短路径的顶点。disc[i]表示顶点i到起点的最短路径长度,pre[i]表示顶点i到起点的最短路径中,i之前的顶点,flag[i]=0表示顶点i在集合U中。
2.从U中选择disc最小的顶点j,加入集合S中,并更新集合U中的顶点,即更新集合U中顶点的disc,直至选完所有顶点。
详细链接:https://blog.csdn.net/chen134225/article/details/79886928
但是在实验中,我遇到的困难是:当两个顶点之间没有边时,边的权是0,不好处理,而且,当选出的顶点与起点相连时,pre没有保存具体的值,造成错误,最终实验中采用在初始化时,如果顶点和起点相连,pre初始化为起点。
代码如下:
void CGraph::FindShortPath(int nVexStart, int nVexEnd,int &length)//查询两景点之间的最短路径
{
length = 0;
int *disc = new int[CGraph::m_nVexNum];
int k;
//pre[i]是顶点nVexStart到顶点i的最短路径中,i前面一个顶点,flag[i]为0,表示未找到从nVexStart到顶点i的最短路径
//disc[i]表示从起点到顶点i的最短路径长度
int * pre = new int[CGraph::m_nVexNum],*flag=new int[CGraph::m_nVexNum];
for (int i = 0; i < CGraph::m_nVexNum; i++)
{
pre[i] = -1;
if (CGraph::m_aAdjMatrix[nVexStart][i] != 0)
{
disc[i] = CGraph::m_aAdjMatrix[nVexStart][i];
pre[i] = nVexStart;
}
else
disc[i] = INT_MAX;
flag[i] = 0;
}
flag[nVexStart] = 1;
disc[nVexStart] = 0;
for (int i = 0; i < CGraph::m_nVexNum-1; i++)//遍历顶点集合m_nVexNum-1次,每次找出一个顶点的最短路径,找到nVexEnd时跳出循环
{
int min = INT_MAX;
for (int j = 0; j < CGraph::m_nVexNum; j++)//在未找到最短路径的顶点中找出disc最小的顶点
{
if (flag[j] == 0 && disc[j] < min)
{
min = disc[j];
k = j;
}
}
flag[k] = 1;
if (k == nVexEnd)//找到终点
break;
//修正剩下未找到最短路径的顶点
for (int j = 0; j < CGraph::m_nVexNum; j++)
{
int temp;
if (CGraph::m_aAdjMatrix[k][j] == 0)
temp = INT_MAX;
else
temp = min + CGraph::m_aAdjMatrix[k][j];
if (flag[j] == 0 && disc[j] > temp)
{
disc[j] = temp;
pre[j] = k;
}
}
}
struct node//定义路径结点
{
int num;//景点编号
node* next=NULL;//下一景点
};
node* head = new node,*p=NULL;
int i = nVexEnd,j=i;
while (i != nVexStart)
{
p = new node;
p->num = i;
p->next = head->next;
head->next = p;
i = pre[i];
}
p = new node;
p->num = nVexStart;
p->next = head->next;
head->next = p;
length = disc[nVexEnd];
p = head->next;
cout << "最短路线为:";
while (p->next != NULL)
{
cout << CGraph::m_aVexs[p->num].name << "->";
p = p->next;
}
cout << CGraph::m_aVexs[p->num].name << endl;
}
四、第四阶段:铺设电路规划
实际上就是构建图的最小生成树,使用的是prim法。
构造方法:将顶点分为两个集合S和U,S是已经选择的顶点集合,U是未选择的顶点集合。从U中选择到S中顶点距离最短的顶点i,最短边对应S中顶点j,边i->j就是最小生成树中的边,将i加入集合S,直至U中没有顶点。
在本实验中,因为要保存边,但是不知道具体有多少条边,本来想用链表保存,但是太过麻烦,我想到了容器,于是就用容器来存储边的集合。
代码如下:
void CGraph::FindMinTree()//构建最小生成树
{
vector aPath;
aPath.clear();
int *flag = new int[CGraph::m_nVexNum];//flag[i]=0表示顶点i没有被选择
for (int i = 0; i < CGraph::m_nVexNum; i++)
flag[i] = 0;
flag[0] = 1;//从顶点0开始
int m,n;
int *prim = new int[CGraph::m_nVexNum];
prim[0] = 0;
for (int i = 0; i < CGraph::m_nVexNum-1; i++)//选择总顶点数-1次,一次选择一个顶点
{
int min = INT_MAX;
for (int j = 0; j <= i; j++)//考察未选择的顶点数组中到达顶点prim[j]的距离,选出最短距离
{
for (int k = 0; k < CGraph::m_nVexNum; k++)//考察未选择的顶点
{
if (flag[k] == 0 && CGraph::m_aAdjMatrix[prim[j]][k] < min&&CGraph::m_aAdjMatrix[prim[j]][k]!=0)
{
min = CGraph::m_aAdjMatrix[prim[j]][k];
m = k;
n = prim[j];
}
}
}
flag[m] = 1;
prim[i + 1] = m;
Edge p;
p.vex1 = n;
p.vex2 = m;
p.weight = CGraph::m_aAdjMatrix[m][n];
aPath.push_back(p);
}
int size = aPath.size();
int length = 0;
for (int i = 0; i < size; i++)
{
cout << CGraph::m_aVexs[aPath[i].vex1].name << "->" << CGraph::m_aVexs[aPath[i].vex2].name << "\t" << aPath[i].weight << "m" << endl;
length += aPath[i].weight;
}
cout << "铺设电路的总长度为:" << length << "m" << endl;
}
到这景区景点信息管理系统就完成了,整个实验过程没有大的困难,都是一些小的bug,通过调试都得到了解决。实验用到了数据结构中图的知识,上个学期薛数据结构的时候觉得图很难,不愿意进行图的编程,也觉得哈夫曼编码很难,然后就学的不好,但是这个学期亲自动手去写以后,对哈夫曼树、图的构造、图的深度优先遍历、广度优先遍历以及最小生成树的构建等等都有了很清晰的理解,果然工科不动手是学不好的啊。。。