打印0-n的所有路径【原创】

  几天在论坛,看到这么个题目:
    
  打印0—N(0<=N<=9)的所有路径。
  想起以前那个工序最优解的解法,好像差不多,改一改,就ok了。
import java.util.Stack;

/**
 * 
@author zxub Created on 2005-5-22 10:19:51
 
*/

public class ProcessOpera
{

    
final int MAX = 20;
    
// 保存路径信息的数组
    ProcessInfo process[] = new ProcessInfo[MAX];
    
// 保存路径数目
    int numProcess = 0;
    
// 分支路径栈
    Stack branchProcessStack = new Stack();
    
// 用于搜索回退的栈
    Stack backTrackStack = new Stack();
    
// 保存最后结果的栈
    Stack resultStack = new Stack();
    
// 最长持续时间
    int maxLastingTime = 0;
    
    
private int sNode;

    
/**
     * 初始化所有路径信息,放进数组中
     
*/

    
public void setup()
    
{
        addProcessInfo(
01);

        addProcessInfo(
02);
        addProcessInfo(
12);
        addProcessInfo(
13);

        addProcessInfo(
23);

        addProcessInfo(
24);
        addProcessInfo(
34);
        addProcessInfo(
35);

        addProcessInfo(
45);

        addProcessInfo(
46);
        addProcessInfo(
56);
        addProcessInfo(
57);

        addProcessInfo(
67);

        addProcessInfo(
68);
        addProcessInfo(
78);
        addProcessInfo(
79);

        addProcessInfo(
89);
    }


    
/**
     * 增加路径信息到数组中
     * 
     * 
@param sNode
     *            开始节点
     * 
@param eNode
     *            终止节点
     * 
@param lTime
     *            持续时间
     
*/

    
public void addProcessInfo(int sNode, int eNode)
    
{
        
if (numProcess < MAX) // 如果数组没满的话
        {
            process[numProcess] 
= new ProcessInfo(sNode, eNode);
            numProcess
++;
        }

        
else
        
{
            System.out
                .println(
"ProcessInfo database full!\nAdd error,program exit!");
            System.exit(
0);
        }

    }


    
/**
     * 给所有路径信息中的附加属性赋值,要完成的话,需要遍历路径数组中的所有元素。 对于每个元素,要查看数组中的其它元素,确立关系
     
*/

    
public void setNodeTag()
    
{
        
for (int i = 0; i < numProcess; i++// 遍历路径数组中的所有元素,process[i]是选取的路径
        {
            
for (int j = 0; j < numProcess; j++// 查看其它元素
            {
                
if (i == j) continue// 自己比自己,没得比,继续下次循环
                
// 发现有路径可以和选取路径连接
                if (process[j].endNode == process[i].startNode)
                
{
                    process[i].hasFrontNode 
= true;
                }

                
// 两条不同路径的终结点一样
                if (process[j].endNode == process[i].endNode)
                
{
                    process[i].eNodeIsBranchEndNode 
= true;
                }

                
// 两条不同路径的起始点一样
                if (process[j].startNode == process[i].startNode)
                
{
                    process[i].sNodeIsBranchBeginNode 
= true;
                }

            }

        }

    }


    
/**
     * 找出以选取点为终结点的没走过的一条路径
     * 
     * 
@param eNode
     *            所选取的点
     * 
@return 没被走过的以选取点为终结点的一条路径
     
*/

    
public ProcessInfo findProcessInfo(int eNode)
    
{
        
for (int i = 0; i < numProcess; i++// 遍历路径信息
        {
            
// process[i].skip=false 路径才没被走过
            if ((process[i].endNode == eNode) && (!process[i].skip))
            
{
                
// 由于深度复制和浅度复制的问题,所以复制的时候要新建一个ProcessInfo,而不是引用原来
                
// 这是实现问题,算法与此可以无关
                ProcessInfo pInfo = new ProcessInfo(process[i].startNode,
                    process[i].endNode);
                process[i].skip 
= true;
                pInfo.hasFrontNode 
= process[i].hasFrontNode;
                pInfo.eNodeIsBranchEndNode 
= process[i].eNodeIsBranchEndNode;
                
return pInfo;
            }

        }

        
return null// 没有合适的路径就返回null了
    }


    
/**
     * 核心部分所在,查找任意2点间最长路径 基于AI设计,简单的AI 理论上来说,顺着找和倒着找是一样的,由于项目原因,这里我是倒着找的
     * 查找到的路径放在结果栈resultStack中
     * 
     * 
@param sNode
     *            开始节点
     * 
@param eNode
     *            终止节点
     * 
@param depth
     *            显示debug信息的时候用到,用于显示层次关系
     
*/

    
public void searchProcess(int sNode, int eNode, int depth)
    
{
        
this.sNode=sNode;
        
        ProcessInfo pInfo; 
// 保存路径信息的对象
        int numStartNode = 0// 查找起点的个数
        Stack resultTemp; // 保存查找到路径的临时栈
        while ((pInfo = findProcessInfo(eNode)) != null)
        
{
            
// 分支节点数目+1
            numStartNode++;
            
// 将查找到的路径信息放到分支节点栈,然后再查
            branchProcessStack.push(pInfo);
            showDebugInfo(
"分支路径栈加入:" + pInfo.startNode + "-->" + pInfo.endNode,
                depth);
        }

        
if (numStartNode > 0// 有分支的话,如果这里不成立,整个就结束了
        {
            
for (int i = 0; i < numStartNode; i++// 遍历分支节点栈
            {
                pInfo 
= (ProcessInfo) branchProcessStack.pop(); // 获得一条分支路径
                showDebugInfo("分支路径栈弹出:" + pInfo.startNode + "-->"
                        
+ pInfo.endNode, depth);
                
// 为了防止头尾一样的路径,有了下面的判断,理论上是没有,但实际会出现
                if (pInfo.startNode == pInfo.endNode)
                
{
                    showDebugInfo(
"头尾节点一样,丢弃!", depth + 1);
                    
continue;
                }


                
// 如果存在可到达的路径的话,注意,这是个递归过程
                if (pInfo.startNode == sNode)
                
{
                    
// 当前路径加入回退栈,此时,回退栈里可以找出一条完整的路径了
                    backTrackStack.push(pInfo);
                    showDebugInfo(
"--------到达起点:" + pInfo.startNode + "-->"
                            
+ pInfo.endNode + "--------", depth);
                    
int numbackTrackStack = backTrackStack.size();
                    resultTemp 
= new Stack();
                    
for (int j = 0; j < numbackTrackStack; j++)
                    
{
                        pInfo 
= (ProcessInfo) backTrackStack.get(j);
                        showDebugInfo(
"回溯栈内容进入临时结果栈:" + pInfo.startNode + "-->"
                                
+ pInfo.endNode, depth);
                        resultTemp.push(pInfo);
                    }

                    resultStack 
= resultTemp;
                    showPath();
                    
// 找出一条后,需要回退,然后继续找下一条
                    
// 获得剩余分支路径的数目
                    int numBranch = branchProcessStack.size();

                    
if (numBranch == 0)
                    
{
                        
// 没分支路径了,查找结束,清空回退栈
                        backTrackStack.removeAllElements();
                    }

                    
else if (numBranch > 0)
                    
{
                        
int index = numBranch - 1;
                        
int backTrackValue = ((ProcessInfo) branchProcessStack
                            .get(index)).endNode;
                        showDebugInfo(
"--------回退到节点:" + backTrackValue
                                
+ "--------", depth);
                        
// 要回退到的节点必是分支路径栈中最上路径的尾节点
                        
// 下面的循环就是一直回退,由于还有分支路径,所以可以找到要退到的点
                        do
                        
{
                            pInfo 
= (ProcessInfo) backTrackStack.pop();
                            showDebugInfo(
"找到目标,回溯栈回退到:" + pInfo.startNode
                                    
+ "-->" + pInfo.endNode, depth);
                        }

                        
while (pInfo.endNode != backTrackValue);
                    }

                    
// 回退后,继续查找的话,所有路径的经过标记都要重置,否则经过了的路径是不会再去查的
                    
// 由于开始路径不同,所以不会找到同样的结果
                    resetAllSkip();
                    
continue;// 开始从下个分支路径查找
                }

                
else
                
// 没有直接从sNode到eNode的工序
                {
                    
// 还没到目标
                    
// 如果当前路径的起点还有前驱节点的话,需要递归查找,这是重点
                    if (pInfo.hasFrontNode)
                    
{
                        ProcessInfo btPInfo 
= new ProcessInfo(sNode, eNode);
                        btPInfo.eNodeIsBranchEndNode 
= pInfo.eNodeIsBranchEndNode;
                        
// 说明找过sNode-->eNode
                        backTrackStack.push(btPInfo);
                        showDebugInfo(
"回溯栈加入:" + sNode + "-->" + eNode
                                
+ ",说明找过" + sNode + "-->" + eNode, depth + 1);
                        showDebugInfo(
"查找:" + sNode + "-->" + pInfo.startNode,
                            depth 
+ 1);
                        searchProcess(sNode, pInfo.startNode, depth 
+ 2);
                    }

                    
else
                    
// 当前路径的起点无前驱,则路径错误,需要回溯
                    {
                        
// 如果当前路径的终结点还有其它前驱的话,则退出本次循环,从下个分支路径查找
                        if (pInfo.eNodeIsBranchEndNode)
                        
{
                            
continue;
                        }

                        
// 如果当前路径的终结点没有其它前驱,就要回退了
                        else if (backTrackStack.size() > 0)
                        
{
                            
// 开始回退,一直到找到个路径的终止节点有多个前驱为止,或者是回退栈已经空了。
                            do
                            
{
                                pInfo 
= (ProcessInfo) backTrackStack.pop();
                                showDebugInfo(
"路径错误,开始回溯,回溯栈弹出:"
                                        
+ pInfo.startNode + "-->"
                                        
+ pInfo.endNode, depth + 1);
                            }

                            
while ((!pInfo.eNodeIsBranchEndNode)
                                    
&& (backTrackStack.size() > 0));
                        }

                    }

                }

            }

            showDebugInfo(
"分支已被找遍", depth);
        }

        
else
        
{
            showDebugInfo(
"前面已走过这条路径且被证明走不通,或尾节点没有前驱节点", depth);
            
if (backTrackStack.size() > 0)
            
{
                pInfo 
= (ProcessInfo) backTrackStack.pop();
                showDebugInfo(
"路径不通,回溯栈弹出:" + pInfo.startNode + "-->"
                        
+ pInfo.endNode, depth - 1);
                
if (branchProcessStack.size() > 0)
                
{
                    
int fixNode = ((ProcessInfo) branchProcessStack
                        .lastElement()).endNode;
                    
if (fixNode != pInfo.endNode)
                    
{
                        showDebugInfo(
"========需要调整回溯栈========", depth);
                        showDebugInfo(
"========开始调整回溯栈========", depth);
                        
do
                        
{
                            pInfo 
= (ProcessInfo) backTrackStack.pop();
                            showDebugInfo(
"回溯栈弹出:" + pInfo.startNode + "-->"
                                    
+ pInfo.endNode, depth + 1);
                        }

                        
while (fixNode != pInfo.endNode);
                        showDebugInfo(
"========回溯栈调整结束========", depth);
                    }

                }

            }

        }

    }


    
private void showDebugInfo(String info, int blankCount)
    
{
        
// String blank = "";
        
// for (int i = 0; i < blankCount; i++)
        
// {
        
// blank += " ";
        
// }
        
// System.out.println(blank + info);
    }


    
public void showPath()
    
{
        ProcessInfo pInfo;
        
int num = resultStack.size();
        
if (num == 0)
        
{
            
// showDebugInfo("========没有符合要求的路径========", 0);
        }

        
else
        
{
            System.out.print(
this.sNode);
            
for (int i = 0; i < num; i++)
            
{
                pInfo 
= (ProcessInfo) resultStack.pop();
                System.out.print(
"-->" + pInfo.endNode);
            }

            System.out.println();
        }

    }


    
public void resetAllSkip()
    
{
        
for (int i = 0; i < numProcess; i++)
        
{
            process[i].skip 
= false;
        }

    }


    
public static void main(String[] args)
    
{
        ProcessOpera processOpera 
= new ProcessOpera();
        processOpera.setup();
        processOpera.setNodeTag();
        
for (int i = 0; i <= 9; i++)
        
{
            processOpera.resetAllSkip();
            processOpera.searchProcess(
0, i, 0);
        }

        
//processOpera.searchProcess(0, 4, 0);
    }


    
public class ProcessInfo
    
{

        
// 基本信息:startNode,endNode
        protected int startNode; // 开始节点
        protected int endNode; // 终止节点
        protected int lastingTime; // 路径持续时间
        
// 下面是附加信息,遍历的时候用到
        protected boolean skip; // 判断该路径是否已经走过
        protected boolean hasFrontNode; // 路径是否有前驱节点
        protected boolean eNodeIsBranchEndNode; // 路径终止节点是否有多个前驱
        protected boolean sNodeIsBranchBeginNode; // 路径开始节点是否有多个后继

        
/**
         * 保存任意两点间路径信息
         * 
         * 
@param sNode
         *            开始节点
         * 
@param eNode
         *            终止节点
         * 
@param lTime
         *            持续时间
         
*/

        
public ProcessInfo(int sNode, int eNode)
        
{
            
this.startNode = sNode;
            
this.endNode = eNode;
            
// 由于是刚开始保存,下面的几个信息不能确立,所以都是false
            this.skip = false;
            
this.hasFrontNode = false;
            
this.eNodeIsBranchEndNode = false;
            
this.sNodeIsBranchBeginNode = false;
        }

    }

}
  答案如下:
0-->1
0-->1-->2
0-->2
0-->1-->2-->3
0-->2-->3
0-->1-->3
0-->1-->2-->3-->4
0-->2-->3-->4
0-->1-->3-->4
0-->1-->2-->4
0-->2-->4
0-->1-->2-->3-->4-->5
0-->2-->3-->4-->5
0-->1-->3-->4-->5
0-->1-->2-->4-->5
0-->2-->4-->5
0-->1-->2-->3-->5
0-->2-->3-->5
0-->1-->3-->5
0-->1-->2-->3-->4-->5-->6
0-->2-->3-->4-->5-->6
0-->1-->3-->4-->5-->6
0-->1-->2-->4-->5-->6
0-->2-->4-->5-->6
0-->1-->2-->3-->5-->6
0-->2-->3-->5-->6
0-->1-->3-->5-->6
0-->1-->2-->3-->4-->6
0-->2-->3-->4-->6
0-->1-->3-->4-->6
0-->1-->2-->4-->6
0-->2-->4-->6
0-->1-->2-->3-->4-->5-->6-->7
0-->2-->3-->4-->5-->6-->7
0-->1-->3-->4-->5-->6-->7
0-->1-->2-->4-->5-->6-->7
0-->2-->4-->5-->6-->7
0-->1-->2-->3-->5-->6-->7
0-->2-->3-->5-->6-->7
0-->1-->3-->5-->6-->7
0-->1-->2-->3-->4-->6-->7
0-->2-->3-->4-->6-->7
0-->1-->3-->4-->6-->7
0-->1-->2-->4-->6-->7
0-->2-->4-->6-->7
0-->1-->2-->3-->4-->5-->7
0-->2-->3-->4-->5-->7
0-->1-->3-->4-->5-->7
0-->1-->2-->4-->5-->7
0-->2-->4-->5-->7
0-->1-->2-->3-->5-->7
0-->2-->3-->5-->7
0-->1-->3-->5-->7
0-->1-->2-->3-->4-->5-->6-->7-->8
0-->2-->3-->4-->5-->6-->7-->8
0-->1-->3-->4-->5-->6-->7-->8
0-->1-->2-->4-->5-->6-->7-->8
0-->2-->4-->5-->6-->7-->8
0-->1-->2-->3-->5-->6-->7-->8
0-->2-->3-->5-->6-->7-->8
0-->1-->3-->5-->6-->7-->8
0-->1-->2-->3-->4-->6-->7-->8
0-->2-->3-->4-->6-->7-->8
0-->1-->3-->4-->6-->7-->8
0-->1-->2-->4-->6-->7-->8
0-->2-->4-->6-->7-->8
0-->1-->2-->3-->4-->5-->7-->8
0-->2-->3-->4-->5-->7-->8
0-->1-->3-->4-->5-->7-->8
0-->1-->2-->4-->5-->7-->8
0-->2-->4-->5-->7-->8
0-->1-->2-->3-->5-->7-->8
0-->2-->3-->5-->7-->8
0-->1-->3-->5-->7-->8
0-->1-->2-->3-->4-->5-->6-->8
0-->2-->3-->4-->5-->6-->8
0-->1-->3-->4-->5-->6-->8
0-->1-->2-->4-->5-->6-->8
0-->2-->4-->5-->6-->8
0-->1-->2-->3-->5-->6-->8
0-->2-->3-->5-->6-->8
0-->1-->3-->5-->6-->8
0-->1-->2-->3-->4-->6-->8
0-->2-->3-->4-->6-->8
0-->1-->3-->4-->6-->8
0-->1-->2-->4-->6-->8
0-->2-->4-->6-->8
0-->1-->2-->3-->4-->5-->6-->7-->8-->9
0-->2-->3-->4-->5-->6-->7-->8-->9
0-->1-->3-->4-->5-->6-->7-->8-->9
0-->1-->2-->4-->5-->6-->7-->8-->9
0-->2-->4-->5-->6-->7-->8-->9
0-->1-->2-->3-->5-->6-->7-->8-->9
0-->2-->3-->5-->6-->7-->8-->9
0-->1-->3-->5-->6-->7-->8-->9
0-->1-->2-->3-->4-->6-->7-->8-->9
0-->2-->3-->4-->6-->7-->8-->9
0-->1-->3-->4-->6-->7-->8-->9
0-->1-->2-->4-->6-->7-->8-->9
0-->2-->4-->6-->7-->8-->9
0-->1-->2-->3-->4-->5-->7-->8-->9
0-->2-->3-->4-->5-->7-->8-->9
0-->1-->3-->4-->5-->7-->8-->9
0-->1-->2-->4-->5-->7-->8-->9
0-->2-->4-->5-->7-->8-->9
0-->1-->2-->3-->5-->7-->8-->9
0-->2-->3-->5-->7-->8-->9
0-->1-->3-->5-->7-->8-->9
0-->1-->2-->3-->4-->5-->6-->8-->9
0-->2-->3-->4-->5-->6-->8-->9
0-->1-->3-->4-->5-->6-->8-->9
0-->1-->2-->4-->5-->6-->8-->9
0-->2-->4-->5-->6-->8-->9
0-->1-->2-->3-->5-->6-->8-->9
0-->2-->3-->5-->6-->8-->9
0-->1-->3-->5-->6-->8-->9
0-->1-->2-->3-->4-->6-->8-->9
0-->2-->3-->4-->6-->8-->9
0-->1-->3-->4-->6-->8-->9
0-->1-->2-->4-->6-->8-->9
0-->2-->4-->6-->8-->9
0-->1-->2-->3-->4-->5-->6-->7-->9
0-->2-->3-->4-->5-->6-->7-->9
0-->1-->3-->4-->5-->6-->7-->9
0-->1-->2-->4-->5-->6-->7-->9
0-->2-->4-->5-->6-->7-->9
0-->1-->2-->3-->5-->6-->7-->9
0-->2-->3-->5-->6-->7-->9
0-->1-->3-->5-->6-->7-->9
0-->1-->2-->3-->4-->6-->7-->9
0-->2-->3-->4-->6-->7-->9
0-->1-->3-->4-->6-->7-->9
0-->1-->2-->4-->6-->7-->9
0-->2-->4-->6-->7-->9
0-->1-->2-->3-->4-->5-->7-->9
0-->2-->3-->4-->5-->7-->9
0-->1-->3-->4-->5-->7-->9
0-->1-->2-->4-->5-->7-->9
0-->2-->4-->5-->7-->9
0-->1-->2-->3-->5-->7-->9
0-->2-->3-->5-->7-->9
0-->1-->3-->5-->7-->9

  为做纪念,所以贴出来算了。
原文地址:https://www.cnblogs.com/zxub/p/461163.html