数据结构实验2--景区信息系统管理

一、第一阶段:景区景点信息创建和景点信息查询

在这一阶段主要是建立数据结构,读取文本文件中的景点信息,并利用景点图的邻接矩阵完成景点信息搜索

搜索代码如下:

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<Edge> 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,通过调试都得到了解决。实验用到了数据结构中图的知识,上个学期薛数据结构的时候觉得图很难,不愿意进行图的编程,也觉得哈夫曼编码很难,然后就学的不好,但是这个学期亲自动手去写以后,对哈夫曼树、图的构造、图的深度优先遍历、广度优先遍历以及最小生成树的构建等等都有了很清晰的理解,果然工科不动手是学不好的啊。。。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值