1. 程式人生 > >無向連通圖中兩點間所有路徑的演算法

無向連通圖中兩點間所有路徑的演算法

http://bbs.csdn.net/topics/360001583

之前在csdn就這個問題發帖求教過,過了幾天沒看到回覆就沒再關心。後來自己設計了一個演算法,在公司的專案中實踐了一下,效果還可以,貼出來供大家參考。
演算法要求:
1. 在一個無向連通圖中求出兩個給定點之間的所有路徑;
2. 在所得路徑上不能含有環路或重複的點;

演算法思想描述:
1. 整理節點間的關係,為每個節點建立一個集合,該集合中儲存所有與該節點直接相連的節點(不包括該節點自身);
2. 定義兩點一個為起始節點,另一個為終點,求解兩者之間的所有路徑的問題可以被分解為如下所述的子問題:對每一個與起始節點直接相連的節點,求解它到終點的所有路徑(路徑上不包括起始節點)得到一個路徑集合,將這些路徑集合相加就可以得到起始節點到終點的所有路徑;依次類推就可以應用遞迴的思想,層層遞迴直到終點,若發現希望得到的一條路徑,則轉儲並列印輸出;若發現環路,或發現死路,則停止尋路並返回; 


3. 用棧儲存當前已經尋到的路徑(不是完整路徑)上的節點,在每一次尋到完整路徑時彈出棧頂節點;而在遇到從棧頂節點無法繼續向下尋路時也彈出該棧頂節點,從而實現回溯。

演算法偽碼(java描述):
public Stack  stack = new Stack();/*臨時儲存路徑節點的棧*/
public ArrayList  sers = new ArrayList();/*儲存路徑的集合*/

public class Node/*表示一個節點以及和這個節點相連的所有節點*/
    {
        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)/*判斷節點是否在棧中*/
    {
        Iterator it = stack.iterator();
        while(it.hasNext())
        {
            Node node1 = (Node)it.next();
            if(node == node1)
                return true;
        }
        return false;
    }

public void showAndSavePath ()/*此時棧中的節點組成一條所求路徑,轉儲並列印輸出*/
    {
        Object[] o = stack.toArray();
        for(int i = 0;i<o.length;i++)
        {
            System.out.print(o[i]);
        }
        sers.add(o); /*轉儲*/
        System.out.println("\n");
    }

/*尋找路徑的方法*/
public boolean getPaths(Node cNode, Node pNode, Node sNode, Node eNode)
/*cNode表示當前的起始節點currentNode,pNode表示當前起始節點的上一節點previousNode,sNode表示最初的起始節點startNode,eNode表示終點endNode*/
    {
        Node nNode = null;
        if(cNode != null && pNode != null && cNode == pNode)
            return false;/*如果符合條件判斷說明出現環路,不能再順著該路徑繼續尋路,返回false*/
        if(cNode != null)
        {
            int i = 0;
            stack.push(cNode);/*起始節點入棧*/
            if(cNode == eNode)/*如果該起始節點就是終點,說明找到一條路徑*/
            {
                showAndSavePath();/*轉儲並列印輸出該路徑,返回true*/
                return true;
            }
            Else/*如果不是,繼續尋路*/
            {
                nNode = cNode.getRelationNodes().get(i);/*從與當前起始節點cNode有連線關係的節點集中按順序遍歷得到一個節點作為下一次遞迴尋路時的起始節點*/
                while(nNode != null)
                {
                    if(pNode != null && (nNode == sNode 
                            || nNode == pNode 
                            || isNodeInStack(nNode)))/*如果nNode是最初的起始節點或者nNode就是cNode的上一節點或者nNode已經在棧中,說明產生環路,應重新在與當前起始節點有連線關係的節點集中尋找nNode*/
                    {
                        i++;
                        if(i>=cNode.getRelationNodes().size())
                            nNode = null;
                        else
                            nNode = cNode.getRelationNodes().get(i);
                        continue;
                    }
/*以nNode為新的起始節點,當前起始節點cNode為上一節點,遞迴呼叫尋路方法*/
                    if(getPaths(nNode, cNode, sNode, eNode))/*遞迴呼叫*/
                    {
                        stack.pop();/*如果找到一條路徑,則彈出棧頂節點*/
                    }
                    i++;/*繼續在與cNode有連線關係的節點集中測試nNode*/
                    if(i>=cNode.getRelationNodes().size())
                        nNode = null;
                    else
                        nNode = cNode.getRelationNodes().get(i);
                }
                stack.pop();/*當遍歷完所有與cNode有連線關係的節點後,說明在以cNode為起始節點到終點的路徑已經全部找到*/
                return false;
            }
        }
        else
            return false;
}