华为2014上机考试样题_高级题_地铁换乘最短路径_无向无权图+邻接表存储+BFS广度优先算法

http://blog.csdn.net/sduweichao/article/details/11678033

/*
Copyright (c) 2013, binzhouweichao@163.com

华为2014上机考试样题 高级题 地铁换乘 最短路径
http://company.dajie.com/huawei/job/nj/topic/206708/detail

无向无权图 邻接表存储 BFS广度优先算法搜索
涉及:图 链表 队列 指针 数组 字符串 类型转换

供参考

*/

/*

						A10-----A11-----A12-----A13
						|						 |
	B1--B2--B3--B4--B5--T1--B6--B7--B8--B9--B10--T2--B11--B12--B13--B14--B15
						|						 |
						A9						 A14
						|						 |
						A8						 A15
						|						 |
						A7						 A16
						|						 |
						A6						 A17
						|						 |
						A5---A4---A3---A2---A1---A18
						

*/

#include <iostream>
#include <string> //用到字符串操作
#include <sstream> //int转string,用到流操作

using namespace std; //标准库命名空间

#define DEBUG //是否为调试模式

#define VerNum 35 //定义顶点数为35 = 18(A) + 15(B) + 2(T)
#define NULL 0 //定义空指针

typedef int Boolean; //定义布尔类型,为int类型别名,适用于访问标志visited
#define TRUE 1 //定义TRUE为1
#define FALSE 0 //定义FALSE为0


/*********************字符串数组与编号映射*************************************

A
data:	A1	A2	A3	A4	A5	A6	A7	A8	A9	A10	A11	A12	A13	A14	A15	A16	A17	A18
index:	0	1	2	3	4	5	6	7	8	9	10	11	12	13	14	15	16	17

B
data:	B1	B2	B3	B4	B5	B6	B7	B8	B9	B10	B11	B12	B13	B14	B15
index:	18	19	20	21	22	23	24	25	26	27	28	29	30	31	32

T
data:	T1	T2
index:	33	34

*/
string Data[VerNum];	//字符串数组,用于存储输入的字符串,数据和下标构成上述映射关系
						//全局变量。。
string intToString(int index)	//int转string,用于下述initD()的字符串序号
{
	stringstream str1;
	string str2;
	str1 << index;
	str1 >> str2;
	return str2;
}
void InitData()	//初始化字符串数组,完成映射
{
	int index;
	//A1-A18, index 0-17
	for(index=0; index<18; index++)
	{
		Data[index] = "A" + intToString(index+1);
	}
	//B1-B15, index 18-32
	for(index=18; index<33; index++)
	{
		Data[index] = "B" + intToString(index-18+1);
	}
	//T1-T2, index 33-34
	Data[33] = "T1";
	Data[34] = "T2";
}
/*********************************************************************************************/

int dataToIndex(string str)	//查找输入字符串的相应index
{
	int index;
	for(index=0; index<VerNum; index++)
	{
		if(strcmp(str.c_str(), Data[index].c_str()) == 0)	//比较输入字符串str与数据数组Data[]的各元素,相等则返回该元素下标index
			break;
	}
	return index;
}

/**************************************************************邻接表存储图信息******************************

Data	index		顶点表GraphList				第一边表e1[35]			第二边表e2[33]			第三边表e3[2]			第四边表e4[2]
					verIndex	firstedge	eVerIndex	nextEdge	eVerIndex	nextEdge	eVerIndex	nextEdge	eVerIndex	nextEdge
-----------------------------------------------------------------------------------------------------------------------------------------------
A1		0		|		0		-->		|e1[0]	1		-->		|e2[0] 17		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A2		1		|		1		-->		|		2		-->		|		0		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A3		2		|		2		-->		|		3		-->		|		1		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A4		3		|		3		-->		|		4		-->		|		2		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A5		4		|		4		-->		|		5		-->		|		3		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A6		5		|		5		-->		|		6		-->		|		4		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A7		6		|		6		-->		|		7		-->		|		5		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A8		7		|		7		-->		|		8		-->		|		6		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A9		8		|		8		-->		|		32(T1)	-->		|		7		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A10		9		|		9		-->		|		10		-->		|		33(T1)	-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A11		10		|		10		-->		|		11		-->		|		9		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A12		11		|		11		-->		|		12		-->		|		10		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A13		12		|		12		-->		|		34(T2)	-->		|		11		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A14		13		|		13		-->		|		14		-->		|		34(T2)	-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A15		14		|		14		-->		|		15		-->		|		13		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A16		15		|		15		-->		|		16		-->		|		14		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A17		16		|		16		-->		|		17		-->		|		15		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
A18		17		|		17		-->		|		0		-->		|e2[17]	16		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B1		18		|		18		-->		|		19		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B2		19		|		19		-->		|		20		-->		|e2[18]	18		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B3		20		|		20		-->		|		21		-->		|		19		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B4		21		|		21		-->		|		22		-->		|		20		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B5		22		|		22		-->		|		33(T1)	-->		|		21		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B6		23		|		23		-->		|		24		-->		|		33(T1)	-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B7		24		|		24		-->		|		25		-->		|		23		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B8		25		|		25		-->		|		26		-->		|		24		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B9		26		|		26		-->		|		27		-->		|		25		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B10		27		|		27		-->		|		34(T2)	-->		|		26		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B11		28		|		28		-->		|		29		-->		|		34(T2)	-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B12		29		|		29		-->		|		30		-->		|		28		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B13		30		|		30		-->		|		31		-->		|		29		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B14		31		|		31		-->		|		32		-->		|e2[30]	30		-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
B15		32		|		32		-->		|		31(B14)	-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
T1		33		|		33		-->		|e1[33]	9(A10)	-->		|e2[31]	8(A9)	-->		|e3[0]	23(B6)	-->		|e4[0]	22(B5)	-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------
T2		34		|		34		-->		|e1[34]	13(A14)	-->		|e2[32]	12(A14)	-->		|e3[1]	28(B11)	-->		|e4[1]	27(B10)	-->NULL	|
-----------------------------------------------------------------------------------------------------------------------------------------------

参考:
http://blog.chinaunix.net/uid-26548237-id-3483650.html

*/

//邻接表相关
//边表结构
typedef struct edgeNode
{
	int eVerIndex;	//边表的顶点号
	struct edgeNode *nextEdge;	//指向下一边表的指针
}edgeNode;	//struct edgeNode的别名为edgeNode,方便调用

//顶点表结构
typedef struct vertexNode
{
	int verIndex;	//顶点表的顶点号
	edgeNode *firstEdge;	//指向第一边表的指针
}vertexNode;

//顶点表构成的图的邻接表
typedef struct
{
	vertexNode adjList[VerNum];	//顶点表结构数组,总数为顶点的数目
}graphList;	//将此结构体别名定义为GraphList

//建图,确立顶点表和边表的关系,完善各表的数据域和指针域
void CreateGraph(graphList *g)	//指针形参,对g指向的内容的操作在函数结束后仍然有效
{
	/**************边表************************/
	//边表和顶点表的填充过程参考上面的邻接表图

	edgeNode *e1[35];	//第一边表
	edgeNode *e2[33];	//第二边表
	edgeNode *e3[2];	//第三边表
	edgeNode *e4[2];	//第四边表

	int i;
	for(i=0; i<35; i++)	//第一边表初始化,分配内存
	{
		e1[i] = new edgeNode;
	}
	for(i=0; i<33; i++)	//第二边表初始化,分配内存
	{
		e2[i] = new edgeNode;
	}
	for(i=0; i<2; i++)	//第三、四边表初始化,分配内存
	{
		e3[i] = new edgeNode;
		e4[i] = new edgeNode;
	}

	//第一边表数据域,即第一边表顶点号
		//A
	for(i=0; i<18; i++)
	{
		e1[i]->eVerIndex = i+1;
	}
		//修正A
	e1[8]->eVerIndex = 33;	//A9-->T1
	e1[12]->eVerIndex = 34;	//A13-->T2
	e1[17]->eVerIndex = 0;	//A18-->A1
	
		//B
	for(i=18; i<18+15; i++)
	{
		e1[i]->eVerIndex = i+1;
	}
		//修正B
	e1[22]->eVerIndex = 33;	//B5-->T1
	e1[27]->eVerIndex = 34;	//B10-->T2
	e1[32]->eVerIndex = 31;	//B15-->B14

		//T1 T2
	e1[33]->eVerIndex = 9;	//T1-->A9
	e1[34]->eVerIndex = 13;	//T2-->A14

	//第二边表数据域,即第二边表顶点号
		//A
	for(i=0; i<18; i++)
	{
		e2[i]->eVerIndex = i-1;
	}
		//修正A
	e2[0]->eVerIndex = 17;	//A1-->A18
	e2[9]->eVerIndex = 33;	//A10-->T1
	e2[13]->eVerIndex = 34;	//A14-->T2

		//B
	for(i=18; i<31; i++)
	{
		e2[i]->eVerIndex = i;
	}
		//修正B
	e2[22]->eVerIndex = 33;	//B6-->T1
	e2[27]->eVerIndex = 34;	//B11-->T2

		//T1 T2
	e2[31]->eVerIndex = 8;	//T1-->A9
	e2[32]->eVerIndex = 12;	//T2-->A13

	//第三边表数据域,即第三边表顶点号
		//T1 T2
	e3[0]->eVerIndex = 23;	//T1-->B6
	e3[1]->eVerIndex = 28;	//T2-->B11

	//第四边表数据域,即第四边表顶点号
	e4[0]->eVerIndex = 22;	//T1-->B5
	e4[1]->eVerIndex = 27;	//T2-->B10

	//第一边表指针域
	for(i=0; i<18; i++)
	{
		e1[i]->nextEdge = e2[i];
	}
	e1[18]->nextEdge = NULL;
	for(i=19; i<32; i++)
	{
		e1[i]->nextEdge = e2[i-1];
	}
	e1[32]->nextEdge = NULL;

	e1[33]->nextEdge = e2[31];
	e1[34]->nextEdge = e2[32];

	//第二边表指针域
	for(i=0; i<33; i++)
	{
		e2[i]->nextEdge = NULL;
	}
	e2[31]->nextEdge = e3[0];
	e2[32]->nextEdge = e3[1];

	//第三边表指针域
	e3[0]->nextEdge = e4[0];
	e3[1]->nextEdge = e4[1];

	//第四边表指针域
	e4[0]->nextEdge = NULL;
	e4[1]->nextEdge = NULL;

/*************************************************************/

	/***完善顶点表数据域和指针域,关联顶点表与第一边表****/

	for(i=0; i<VerNum; i++)
	{
		g->adjList[i].verIndex = i;	//顶点表数据域
		g->adjList[i].firstEdge = e1[i];	//顶点表指针域
	}

/***********************************************************/

}

/***打印邻接表信息*******/
#ifdef DEBUG	//只在DEBUG模式下打印
void printGraph(graphList *g)
{
	int i;
	edgeNode *p;

	for(i=0; i<VerNum; i++)
	{
		cout << "顶点号:" << i << " 边号:";
		p = g->adjList[i].firstEdge;

		while(p)
		{
			cout << p->eVerIndex << " ";
			p = p->nextEdge;
		}
		cout << endl;
	}
}
#endif

/***************************************************/

/****BFS广度优先搜索邻接表,找出最短路径***********
参考:
http://blog.163.com/zhoumhan_0351/blog/static/3995422720098711040303/
******************************************************/

//队列链表结点结构,单向链表
typedef struct qNode
{
	int qVerIndex;	//队列数据域,结点存储的顶点号
	struct qNode *nextQNode;	//队列指针域,结点指向的下一个队列结点
}qNode;	//队列链表结点结构别名为qNode

//队列链表
typedef struct
{
	qNode *front;	//队列头,删除
	qNode *rear;	//队列尾,添加
}queue;	//队列链表别名queue

//初始化队列,新建队列
void InitQueue(queue *q)
{
	
	q->rear = new qNode;	//新建队列结点,赋予队尾
	q->front = q->rear;		//空队列的队头与队尾为同一单元
	/*
	if(q->front == NULL)	//分配单元失败
	{
		cout << "InitQueue Error!" << endl;
		exit(1);
	}
	*/
	q->front->nextQNode = NULL;	//队头的指向下一结点的指针为空
	//因为队首队尾为同一单元,则队尾结点的下一结点指针也为空,即q->rear->nextQNode == NULL
}

//入队,队尾添加
void EnQueue(queue *q, int e)	//形参为队列q地址,要添加的新的队列结点的数据域
{
	qNode *p = new qNode;	//新建结点,并分配内存
	
	/*if(p == NULL )	//若分配内存失败则退出
	{
		cout << "EnQueue Error!" << endl;
		exit(1);
	}
	*/
	p->qVerIndex = e;	//新结点的数据域为传入的参数
	p->nextQNode = NULL;		//新结点指针域为空
	
	q->rear->nextQNode = p;	//原队尾指向下一结点的指针指向p
	//因为空队的队首与队尾单元相同,则若为空队时,q->front->nexQNode = p
	//即空队的 队头的指向下一结点的指针 指向新结点
	//若非空队,则对队首不影响
	q->rear = p;	//p成为新的队尾
	//这时,队首q->front仍为第一次初始化时的单元,而队尾则成了新加的结点单元
	//队尾的指向下一结点的指针永远指向NULL
}

int QueueEmpty(queue *q)	//判断队列是否为空,空则返回1,非空为0
{
	return(q->front == q->rear ? 1:0);	//判断条件为,队头与队尾为同一单元
}

//出队,队首删除
void DeQueue(queue *q, int *m)	//队列q指针传参,m为指针形参,用于保存删除的结点的数据域
{
	qNode *p = new qNode;	//新建队列结点,用于缓存
	if(QueueEmpty(q))	//若为空队列,则报错退出
	{
		cout << "DeQueue Error!" << endl;
		exit(1);
	}
	p = q->front->nextQNode;	//要删除的结点缓存为p
	*m = p->qVerIndex;	//要删除的结点的数据域放入m所指单元
	q->front->nextQNode = p->nextQNode;	//队头指向下一结点的指针指向要删除的结点的下一个结点
	if(q->front->nextQNode == NULL)	//判断是否已经清空队列
	{
		q->rear = q->front;	//若队首指向下一个结点的指针为空,则表明队列已经清空,队首队尾为同一单元
		//注:不能写反了
	}
	free(p);	//释放缓存
}

//BFS广度优先搜索
void BFSTraverse(graphList *g, int dist[VerNum][VerNum])	//数组形参,传址,所做修改在函数结束时仍然有效
{
	queue q;	//定义队列

	edgeNode *p = new edgeNode;	//定义边表结点类型指针,下面访问各个结点的边表时用到

	int index;
	/*
	此处使用循环来得到所有点相对其他点的最短路径,
	若图有未达到的点,需要再设置一个循环来达到遍历所有点的目的,
	因为此题中任何点均可以达到其他所有点,不必再设下一循环
	*/
	for(index=0; index<VerNum; index++)	
	{
		InitQueue(&q);	//初始化队列q,每个新的起点都重置一下队列
		Boolean visited[VerNum] = {FALSE};	//定义各顶点访问标志,并初始化为FALSE
		
		/*
		设置一个层次标志
		BFS算法是把图从一个顶点转化为树,并按照距离的远近设置树的层次,
		处于同一层次的叶结点与根结点的距离相同
		而且根结点与页结点的距离,就是层次数
		*/
		int level[VerNum][VerNum];	//树的最大度为VerNum(第一个),每层中最大叶结点为VerNum(第二个)
		//此数组用于保存每层的各叶子结点
		int r1, r2;	//数组横下标为r1,纵下标r2
		for(r1=0; r1<VerNum; r1++)	//初始化层次数组
		{
			for(r2=0; r2<VerNum; r2++)
			{
				level[r1][r2] = VerNum;	//因为没有VerNum序号的结点,用于判断是否赋值,或作其他用途
			}
		}

		EnQueue(&q, index);	//顶点入队
		visited[index] = TRUE;	//入队表示已访问
		r1 = 0;
		r2 = 0;
		level[0][0] = index;	//树的根节点存放的顶点号
		//r1表示层次数,r2表示本层的第几个叶结点
		dist[index][index] = r1 ;	//表示该顶点到自身的距离为0

		while(!QueueEmpty(&q))	//队列非空,则一直访问,直至访问完所有结点
		{
			int m;
			DeQueue(&q, &m);	//队首出队
			if(m == level[r1][0])	//若出队的顶点号与第r1层的第一个结点的顶点号相同
			//即:出队的顶点号是某层第一个入队的结点,那么说明该层已经访问结束,进入下一层访问
			{
				r1 += 1;	//进入下一层
				r2 = 0;		//下一层起点
			}

			p = g->adjList[m].firstEdge;	//按照邻接表各顶点边表的顺序访问每个顶点
			while(p)
			{
				if(!visited[p->eVerIndex])
				{
					EnQueue(&q, p->eVerIndex);	//未访问的入队
					visited[p->eVerIndex] = TRUE;	//入队表示已访问

					level[r1][r2] = p->eVerIndex;	//r1层r2叶结点的顶点号为当前访问的边表顶点号
					dist[index][p->eVerIndex] = r1;	//根顶点与当前访问的顶点的距离,为当前访问的点所在的层次数
					r2 += 1;	//该层访问结点数递增
				}
				p = p->nextEdge;	//循环控制,指向下一个边表
			}
		}
	}
}

#ifdef DEBUG
void printBFS(int dist[VerNum][VerNum])
{
	cout << endl;
	for(int i=0; i<VerNum; i++)
	{
		cout << i <<":";
		for(int j=0; j<VerNum; j++)
		{
			cout << dist[i][j] << " ";
		}
		cout << endl;
	}
}
#endif

int main()
{
	InitData();	//初始化字符串数组,Data[]数组已经设置成了全局变量。。也可以设置在此处数组传参

	graphList g;	//建图
	CreateGraph(&g);	//完善图的所有结点

#ifdef DEBUG	//调试用,打印图
	printGraph(&g);
#endif

	int dist[VerNum][VerNum];	//定义各顶点间距离数组
	for(int d1=0; d1<VerNum; d1++)	//初始化距离数组
	{
		for(int d2=0; d2<VerNum; d2++)
		{
			dist[d1][d2] = 0;	//表示顶点d1到顶点d2的距离
			//最大距离不会是VerNum,表示无法到达或有其他用途
		}
	}

	BFSTraverse(&g, dist);	//BFS搜索,保存各点最短路径

#ifdef DEBUG
	printBFS(dist);	//打印各点间最短路径
#endif

	string str1, str2;	//用于保存两个输入的字符串
#ifdef DEBUG
	cout << "请输入两个站点:" << endl;
#endif
	cin >> str1 >> str2;	//输入两个字符串,没有设置冗余,对于不符合规范的输入,只取前两个

	int index1, index2;	//用于保存将两个输入的字符串转换后的顶点号
	index1 = dataToIndex(str1);	//将str1转换成相应顶点号
	index2 = dataToIndex(str2);	//将str2转换成相应顶点号

	//两点index1和index2间的距离即为dist[index1][index2],无向,则也等于dist[index2][index1]
#ifdef DEBUG
	cout << "两点间站点数为:" << endl;
#endif
	cout << dist[index1][index2] <<endl;

#ifdef DEBUG
	system("pause");	//暂停,以查看输出
#endif

	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值