java查找無(wú)向連通圖中兩點(diǎn)間所有路徑的算法
之前就這個(gè)問(wèn)題發(fā)帖求教過(guò),過(guò)了幾天沒(méi)看到回復(fù)就沒(méi)再關(guān)心。后來(lái)自己設(shè)計(jì)了一個(gè)算法,在公司的項(xiàng)目中實(shí)踐了一下,效果還可以,貼出來(lái)供大家參考。
算法要求:
1. 在一個(gè)無(wú)向連通圖中求出兩個(gè)給定點(diǎn)之間的所有路徑;
2. 在所得路徑上不能含有環(huán)路或重復(fù)的點(diǎn);
算法思想描述:
1. 整理節(jié)點(diǎn)間的關(guān)系,為每個(gè)節(jié)點(diǎn)建立一個(gè)集合,該集合中保存所有與該節(jié)點(diǎn)直接相連的節(jié)點(diǎn)(不包括該節(jié)點(diǎn)自身);
2. 定義兩點(diǎn)一個(gè)為起始節(jié)點(diǎn),另一個(gè)為終點(diǎn),求解兩者之間的所有路徑的問(wèn)題可以被分解為如下所述的子問(wèn)題:對(duì)每一個(gè)與起始節(jié)點(diǎn)直接相連的節(jié)點(diǎn),求解它到終點(diǎn)的所有路徑(路徑上不包括起始節(jié)點(diǎn))得到一個(gè)路徑集合,將這些路徑集合相加就可以得到起始節(jié)點(diǎn)到終點(diǎn)的所有路徑;依次類推就可以應(yīng)用遞歸的思想,層層遞歸直到終點(diǎn),若發(fā)現(xiàn)希望得到的一條路徑,則轉(zhuǎn)儲(chǔ)并打印輸出;若發(fā)現(xiàn)環(huán)路,或發(fā)現(xiàn)死路,則停止尋路并返回;
3. 用棧保存當(dāng)前已經(jīng)尋到的路徑(不是完整路徑)上的節(jié)點(diǎn),在每一次尋到完整路徑時(shí)彈出棧頂節(jié)點(diǎn);而在遇到從棧頂節(jié)點(diǎn)無(wú)法繼續(xù)向下尋路時(shí)也彈出該棧頂節(jié)點(diǎn),從而實(shí)現(xiàn)回溯。
算法偽碼(java描述):
public Stack stack = new Stack();/*臨時(shí)保存路徑節(jié)點(diǎn)的棧*/
public ArrayList sers = new ArrayList();/*存儲(chǔ)路徑的集合*/
public class Node/*表示一個(gè)節(jié)點(diǎn)以及和這個(gè)節(jié)點(diǎn)相連的所有節(jié)點(diǎn)*/
{
public String name = null;
public ArrayList relationNodes = new ArrayList();
public String getName()
{
return name;
}
public void setName(String name)
{
this.name = name;
}
public ArrayList getRelationNodes()
{
return relationNodes;
}
public void setRelationNodes(ArrayList relationNodes)
{
this.relationNodes = relationNodes;
}
}
public boolean isNodeInStack(Node node)/*判斷節(jié)點(diǎn)是否在棧中*/
{
Iterator it = stack.iterator();
while(it.hasNext())
{
Node node1 = (Node)it.next();
if(node == node1)
return true;
}
return false;
}
public void showAndSavePath ()/*此時(shí)棧中的節(jié)點(diǎn)組成一條所求路徑,轉(zhuǎn)儲(chǔ)并打印輸出*/
{
Object[] o = stack.toArray();
for(int i = 0;i<o.length;i++)
{
System.out.print(o[i]);
}
sers.add(o); /*轉(zhuǎn)儲(chǔ)*/
System.out.println("\n");
}
/*尋找路徑的方法*/
public boolean getPaths(Node cNode, Node pNode, Node sNode, Node eNode)
/*cNode表示當(dāng)前的起始節(jié)點(diǎn)currentNode,pNode表示當(dāng)前起始節(jié)點(diǎn)的上一節(jié)點(diǎn)previousNode,sNode表示最初的起始節(jié)點(diǎn)startNode,eNode表示終點(diǎn)endNode*/
{
Node nNode = null;
if(cNode != null && pNode != null && cNode == pNode)
return false;/*如果符合條件判斷說(shuō)明出現(xiàn)環(huán)路,不能再順著該路徑繼續(xù)尋路,返回false*/
if(cNode != null)
{
int i = 0;
stack.push(cNode);/*起始節(jié)點(diǎn)入棧*/
if(cNode == eNode)/*如果該起始節(jié)點(diǎn)就是終點(diǎn),說(shuō)明找到一條路徑*/
{
showAndSavePath();/*轉(zhuǎn)儲(chǔ)并打印輸出該路徑,返回true*/
return true;
}
Else/*如果不是,繼續(xù)尋路*/
{
nNode = cNode.getRelationNodes().get(i);/*從與當(dāng)前起始節(jié)點(diǎn)cNode有連接關(guān)系的節(jié)點(diǎn)集中按順序遍歷得到一個(gè)節(jié)點(diǎn)作為下一次遞歸尋路時(shí)的起始節(jié)點(diǎn)*/
while(nNode != null)
{
if(pNode != null && (nNode == sNode
|| nNode == pNode
|| isNodeInStack(nNode)))/*如果nNode是最初的起始節(jié)點(diǎn)或者nNode就是cNode的上一節(jié)點(diǎn)或者nNode已經(jīng)在棧中,說(shuō)明產(chǎn)生環(huán)路,應(yīng)重新在與當(dāng)前起始節(jié)點(diǎn)有連接關(guān)系的節(jié)點(diǎn)集中尋找nNode*/
{
i++;
if(i>=cNode.getRelationNodes().size())
nNode = null;
else
nNode = cNode.getRelationNodes().get(i);
continue;
}
/*以nNode為新的起始節(jié)點(diǎn),當(dāng)前起始節(jié)點(diǎn)cNode為上一節(jié)點(diǎn),遞歸調(diào)用尋路方法*/
if(getPaths(nNode, cNode, sNode, eNode))/*遞歸調(diào)用*/
{
stack.pop();/*如果找到一條路徑,則彈出棧頂節(jié)點(diǎn)*/
}
i++;/*繼續(xù)在與cNode有連接關(guān)系的節(jié)點(diǎn)集中測(cè)試nNode*/
if(i>=cNode.getRelationNodes().size())
nNode = null;
else
nNode = cNode.getRelationNodes().get(i);
}
stack.pop();/*當(dāng)遍歷完所有與cNode有連接關(guān)系的節(jié)點(diǎn)后,說(shuō)明在以cNode為起始節(jié)點(diǎn)到終點(diǎn)的路徑已經(jīng)全部找到*/
return false;
}
}
else
return false;
}
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
SpringBoot詳解自定義Stater的應(yīng)用
Springboot的出現(xiàn)極大的簡(jiǎn)化了開(kāi)發(fā)人員的配置,而這之中的一大利器便是springboot的starter,starter是springboot的核心組成部分,springboot官方同時(shí)也為開(kāi)發(fā)人員封裝了各種各樣方便好用的starter模塊2022-07-07
Spring boot如何集成kaptcha并生成驗(yàn)證碼
這篇文章主要介紹了Spring boot如何集成kaptcha并生成驗(yàn)證碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-07-07
java中Statement 與 PreparedStatement接口之間的關(guān)系和區(qū)別
這篇文章主要介紹了java中Statement 與 PreparedStatement接口之間的關(guān)系和區(qū)別,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-07-07
Spring Security 實(shí)現(xiàn)“記住我”功能及原理解析
這篇文章主要介紹了Spring Security 實(shí)現(xiàn)“記住我”功能及原理解析,需要的朋友可以參考下2020-05-05

