图论--寻找节点间所有路径
最近在论文中,要获得节点间的路由,由此又开始继续去年的算法学习。下面的就关于寻找两个节点之间所有的路径。因为是在获得路径后,再加上权重,所以不能将那些求最短路径的算法给之间粘贴上。
下面是我的一个路径的设想。在图中存在着7个节点,连通情况如下:
首先,想到的就是树中的深度遍历。因为我们需要循着上轮访问的节点,才能确定整个路径。如果仅仅完成没有问题,最关键的在于如何记录下所有的路径。一开始,我想利用两个栈,一个放最后所有路径的结果,一个放临时刚出栈的元素。但是后面发现,本程序的起始节点是A,终止节点是E比如在从a->b->c>e,当e节点已经为最后的节点,对于临时数组中的c,它的存在没有任何的意义。
所以本程序的关键是在于如何存放之前的路径。要避免走回路。
程序代码如下
本代码的主要思想为:
创建一个结构体Node保存key值,flag为这个元素开始遍历所在的索引位置。比如,从A->B,那么flag为1,当遍历完B,开始继续遍历到D,A的flag为3.
其中深度遍历的元素的key值可以以flag作为标准,flag+1即为下个元素的key值。在这里我们要清楚的是,比如要A->B->C,其中C为新元素,则B的flag为2,赋值给C的键值为3。
如果D连接的所有元素都被访问了,那么将D的flag重新设置为0,并设置它未被访问。因为D的访问可能来自B,也可能来自A.而A先访问,如果不设置未被访问,由A到D遍历E的路径将无法被读取
#include <iostream>
using namespace std;
#define NUM 6+2
#define MAX_PATH 100
struct Node
{
int key;
int flag;//获得当前节点的范围索引
Node()
{
flag=0;
}
};
class Graph
{
public:
//stack<int> searchStack;
int resultPath[MAX_PATH][NUM];
int result[NUM+1];//将result设为NUM+1,主要是为了避免发生B->D->B的事情
Node headNode;//起始节点
Node endNode;//终止节点
int pathNum;
int nPos;
bool Mark[NUM];
public:
Graph()
{
//将矩阵中的元素置为空
for (int i=0;i<NUM;i++)
{
for (int j=0;j<MAX_PATH;j++)
{
resultPath[j][i]=0;
}
result[i]=0;
Mark[i]=false;
}
result[NUM]=0;
pathNum=0;
nPos=0;
}
void test()
{
//对应无向图的矩阵
int Matrix[NUM][NUM]={
{0,1,0,1,0,0,0,0}, //A
{1,0,1,1,0,0,0,0},//B
{0,1,0,0,1,0,0,0},//C
{1,1,0,0,1,1,0,0}, //D
{0,0,1,1,0,0,1,0}, //E
{0,0,0,1,0,0,1,1}, //F
{0,0,0,0,1,1,0,0}, //G
{0,0,0,0,0,1,0,0} //H
};
//开始节点
headNode.key=1;
headNode.flag=1;
//结束节点
endNode.key=5;
FindAllPath(Matrix,headNode,endNode);
cout<<"路径数目为:"<<pathNum<<endl;
for (int i=0;i<pathNum;i++)
{
cout<<"第"<<i<<"条: ";
for(int j=0;j<NUM;j++)
{
if (resultPath[i][j]==0)
{
break;
}
cout<<resultPath[i][j]<<" ";
}
cout<<endl;
}
int i=0;
}
/************************************************************************/
/* 函数功能:找到图中两个节点之间的所有路径
参数说明:1、Matrix 初始矩阵,将路径矩阵的形式存储,本程序对应的是一个无向图。
2、headNode 初始节点
3、endNode 结束节点
主要的思想 利用深度优先遍历的算法
1、利用result来存放每次从栈中出栈的数据,里面很可能就是要找的路径,为什么要单独提取出来,因为包含了多条路径
2、通过设置 访问是否的变量来避免回路/
/************************************************************************/
void FindAllPath(int Matrix[NUM][NUM],Node startNodeKey,Node endNodeKey)
{
result[nPos]=startNodeKey.key; //将当前元素放入结果集中
Mark[startNodeKey.key-1]=true; //将访问标记为已访问
nPos++; //结果集索引加1
while(nPos!=0)
{
int tempVal=result[nPos-1];//获取到最前面的元素
if (tempVal==endNodeKey.key) //若当前元素为目标节点
{
for (int j=0;j<nPos;j++)
{
resultPath[pathNum][j]=result[j]; //将结果集复制于最后的路径矩阵中
}
nPos--; //回溯至上一个节点
result[nPos]=0; //结果集对应索引置为空
pathNum++; //路径数目加1
Mark[endNodeKey.key-1]=false;
break;
}
while(startNodeKey.flag<NUM)//利用flag来指示每次的元素的索引
{
if (Matrix[tempVal-1][startNodeKey.flag]==1)
{
if (Mark[startNodeKey.flag]==false)//利用Mark来判断是否已经访问过该节点
{
Node tempNode;
tempNode.key=startNodeKey.flag+1;
FindAllPath(Matrix,tempNode,endNodeKey);//深度优先遍历算法,
}
}
startNodeKey.flag++;//索引值相应的加一
}
if (startNodeKey.flag==NUM)//如果已经是到最后的邻居,说明访问结束,
{ //将对应的值置为空
nPos--; //再次向上回溯
startNodeKey.flag=0; //将节点的索引置为空
result[nPos]=0; //将结果集中对应的索引置为空
Mark[startNodeKey.key-1]=false; //访问之后标记为未访问。因为下面的元素已经访问结束,便于下次的访问
break;
}
}
}
};
运行结果:
2、matlab对应的代码
function [resultMatrix,nPos,result,numPath]=getPath(Graph,startData,endData,nPos,result,resultMatrix,numPath)
result(1,nPos)=startData.key;
nPos=nPos+1;
while nPos~=1
tempVal=startData.key;
if tempVal==endData.key
for lengthPath=1:(nPos-1)
resultMatrix(numPath,lengthPath)=result(lengthPath);
end
nPos=nPos-1;
result(nPos)=0;
startData.flag=1;
numPath=numPath+1;
break;
end
while startData.flag<=(length(Graph))
t= Graph(tempVal,startData.flag);
if t==1
if length(find(result==startData.flag))==0
newData=struct('key',startData.flag,'flag',1);
[resultMatrix,nPos,result,numPath]=getPath(Graph,newData,endData,nPos,result,resultMatrix,numPath);
end
end
startData.flag=startData.flag+1;
end
if startData.flag==(length(Graph)+1)
nPos=nPos-1;
startData.flag=1;
result(nPos)=0;
break;
end
end
小结:
1)节点数目增加的话,时间会很长,还需要改进
2)访问后的节点应该将路径记录下来,这里还是有问题
3)大家多多指教