您的位置:首页 > 其它

利用链式前向星在无权图中实现寻找两点最短路径

2014-01-24 01:16 931 查看
最近参加了中兴捧月的比赛,特地挑了道图算法的题来做。经过几天的学习和思考,利用广度搜索来解决“无权图两点最短路径”,存储结构上,用链式前向星处理“稀疏图”能达到一个较低的时间复杂度。
那么什么是链式前向星呢? 其实它是一种邻接表的数组实现方式,使用它,既能减少代码的复杂度,也能在一定的条件下节省存储空间,下面我们先学习一下这种数据存储结构(下面的课件摘自:http://malash.me/200910/linked-forward-star/

































由上可见,链式前向星其实模拟了指针的过程,这样实现起来比邻接链表要更为简单,编写效率可以说是相当高。
利用链式前向星,可以快速有效地解决诸如:SPFA,图的遍历等等问题。

接下来下面我们可以先来看看题目:
在一个网络拓扑中(可以支持数千个点的规模),边是双向的,两点之间最多有一条边,所有边的距离相等(也就是权重为1),给出源和目的两个点,需要找出满足条件的路径。1。找出源和目的之间的一条主用路径。2。找出源和目的之间的一条备用路径。备用路径和主用路径至少有一个点或边不相同。关于备用路径可能满足下列约束: 1)和主用路径没有相同的中间节点。 2)和主用路径没有相同的边。例如:示例数据A_NE_ID,Z_NE_ID2,284,489,4510,110,1111,1211,212,1313,1415,2316,2417,2518,1918,120,2120,2920,321,2222,2323,2424,3226,2726,3427,2827,3528,3629,3730,3132,4032,3332,3133,2533,4136,4437,3837,4539,3039,440,540,4943,4243,5043,644,4345,745,846,3746,4747,4848,40拓扑图描述文件



拓扑图文件说明,出于简化的目的,网络拓扑节点用数字表示。




程序支持命令行参数,/f后表示拓扑图文件/s 表示源节点/d表示目的节点/c 表示条件(取值1-2,满足上面两个约束条件之一)/o 表示输出结果文件如cpath.exe /ftopolink_example01.txt /s20 /d32 /c2 /otopolink_result01.txt表示根据拓扑图文件topolink_example01.txt,计算节点20和节点32之间的主用和备用路径,备用路径要求满足约束条件2。输出结果文件topolink_result01.txt内容可能的为main: 20, 21 ,22, 23,24, 32backup: 20,29,37, 46,47,48, 40,32
解决思路如下:



首先我们来解决如何定义一个图:

typedef struct EDGE
{
int to;     //边上的节点
int next;   //下一个节点
int weight; //权重
}EDGE;
typedef struct GRAPH
{
int *vertex;    //顶点集
EDGE *edge;     //边集
int index;      //下标值
int vertexSize; //顶点个数
int edgeSize;   //边个数
int *pre;       //前一个访问对象
int *visited;   //遍历过的点
}GRAPH;
然后我们如何构建一个无权图呢?只需要将边插入两个顶点中就好了(与邻接链表是一样)

void graphInsertE(GRAPH *g, int u, int v, int w)
{
int index = g->index;
g->edge[index].to = v;
g->edge[index].next = g->vertex[u];
g->edge[index].weight = w;
g->vertex[u] = index++;
g->index = index;
}
如何去搜寻图中最短的路径呢?其实就是去做一个广度搜索,如果遇到了我们要找的节点,就停止搜索就好了
/*******************************************************
* Function Name: BFSSearch
* Purpose: 使用广度优先找寻最短路径
* Params :
*   @GRAPH *g 图指针
*   @int s 源节点
*   @int d 目标节点
*******************************************************/
void BFSSearch(GRAPH *g, int s, int d)
{
//初始化一个队列
QUEUE *q = initQueue(g->vertexSize);
int qfront, temp;
int flag = TRUE, i;
//从源节点开始找寻
g->visited[s] = 1;
in(q, s);
//直到找到目标节点或者队列为空才停止
while(flag && !isQueueEmpty(*q))
{
out(q, &qfront);
for(i = g->vertex[qfront];flag && i;i = g->edge[i].next)
{
if(g->edge[i].weight == 1)
{
temp = g->edge[i].to;
if(!g->visited[temp])
{
in(q, temp);
g->pre[temp] = qfront;
g->visited[temp] = 1;
}
if(temp == d)
{
flag = FALSE;
}
}
}
}
//释放队列
destroyQueue(&q);
}


好了,大概的讲解就到这里,如果说大家想要了解更多的话,源代码就在附件中,可以自己下载调试
本文出自 “geek的自我修养” 博客,请务必保留此出处http://guanyifeng.blog.51cto.com/5790852/1354264
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: