您的位置:首页 > 编程语言 > Java开发

Java深度优先搜索两点间路径,支持命令行参数,约束条件设置

2013-07-18 10:24 393 查看

程序内容:

通过递归的方法搜索两点之间的路径,支持命令行参数设置起始节点,目标节点以及限制所得路径没有相同节点或没有相同边,路径最终输出到文件中

命令行输入内容:" /ftextshort2.txt /s105 /d110 /c1 /oresult.txt"
命令行具体参数:/f后面参数为数据源, /s后面参数为起始节点 ,/d后面参数为目的节点,/c后面参数为约束条件,/o后面为输出文件地址

涉及到的知识点:

Java 通过命令行参数,参考http://blog.csdn.net/zbwork000/article/details/6843596
Java的 I/O
数据存储(HashMap ArrayList)
通过堆栈递归

存在不足的地方:

无法直接搜索到最短路径
当节点数目上升到一定数目的时候,采用这种深度优先算法效率下降明显
HashMap对数据存储的利用,没有合理的处理使得占用空间较大

算法优化:

可以考虑用dijkstra算法对路径的搜索实现优化。
具体如何优化,大概思路就是将权值设置为1,然后默认所有节点距离设置为一个较大值(很大很大),默认搜索状态为0(未搜索)
搜索起始节点时设置距离为0,与起始节点直接相连的子节点设置为1,如此类推在检查某个距离为K的节点的时候,设置其直接相连的子节点为K+1;
每搜索一个节点,先检查这个节点是否已经被搜索,如果已经被搜索过,则比较它父节点距离值+1与它当前的距离值的大小,取较小的距离值作为这个节点的距离值,并根据距离值的大小判断是否需要更新其路径中前趋节点;如果没有被搜索过,则直接设置距离值为父节点距离值+1并设置路径前趋节点
当一个节点被检查完后,要将检查状态设置为1
当检查到节点的值为一开始设置的目的节点,则停止,并沿着目标节点的K值逆序,以及通过每个节点设置的前趋节点,逐步返回寻找到一条正确的路径
 

数据文件格式如下图:




     第一行为开头
     接下来每一行表示两个互相连接的节点
     91,91:表示节点91与节点92相连接
 
主程序:
1: package com.zhengjianbao.zcmatch;
2: /*From South Agricultural University,Electrical Information Majority zhengjianbao*/[/code]
3: import java.io.BufferedReader;
4: import java.io.File;
5: import java.io.FileReader;
6: import java.io.FileWriter;
7: import java.util.ArrayList;
8: import java.util.HashMap;
9:
10: /**
11:  * 程序入口:
12:  * 思路:1.getInput方法先将文件解析,转化成HashMap存储每个节点与其相连的所有子
13:  *     节点,以这个节点的值作为key,值是ArrayList类型,存放与它相连的所有节点
14:  *     2.自定义HashFind类,getPaths方法通过堆栈操作实现路径查询;
15:  *     3.outPath方法将获得的路径输出到文件中;
16:  * */
17: public class Excuteable {
18:   /*
19:    * 解析数据文件
20:    * 思路:将数据文件逐行读取,然后把左右数据放到Hash表中
21:    *           例如23,34:23与34相连,因此把23放到以34为键的表中,把34放到以23为键的表中
22:    * 输入参数:inputPath 输入的路径
23:    * 返回        :经过调节后的HashMap
24:    * */
25:   public static HashMap<Integer, ArrayList<Integer>> getInput(String inputPath) {
26:     try {
27:
28:       BufferedReader data = new BufferedReader(new FileReader(inputPath));
29:       String s = new String();
30:       String s2 = new String();
31:
32:       HashMap<Integer, ArrayList<Integer>> hashMap = new HashMap<Integer, ArrayList<Integer>>();
33:
34:       ArrayList<Integer> nodeDataFront;
35:       ArrayList<Integer> nodeDataBack;
36:       while ((s = data.readLine()) != null) {
37:
38:         if (s.equals("") || s.equals("A_NE_ID,Z_NE_ID")) {
39:           continue; // 遇到空行跳过
40:         }
41:
42:         s2 = s2 + s.trim() + "\r\n";
43:         String[] tmp = new String[] {};
44:         tmp = s.split(",");
45:
46:         Integer nodeLeft = Integer.valueOf(tmp[0].trim());
47:         Integer nodeRight = Integer.valueOf(tmp[1].trim());
48:         // 如果以左边数据为主键的数据链表不存在,也就是当前的数据行,以左边数据为主键,它的子节点在之前不存在
49:         if (hashMap.get(nodeLeft) == null)
50:           // 新创建一个以数据链表,用来存放以左边数据为主键的子节点集合
51:           nodeDataFront = new ArrayList<Integer>();
52:         else
53:           // 否则直接获取以左边数据为主键的集合,作后续插入操作
54:           nodeDataFront = hashMap.get(nodeLeft);
55:
56:         if (hashMap.get(nodeRight) == null)
57:           nodeDataBack = new ArrayList<Integer>();
58:         else
59:           nodeDataBack = hashMap.get(nodeRight);
60:
61:         // 将右边的数据放到以它的左边节点的集合中
62:         nodeDataFront.add(nodeRight);
63:         // 左边数据位主键,对应的集合内存放的是左数据作为节点的子节
64:         hashMap.put(nodeLeft, nodeDataFront);
65:
66:         // 右边数据的子节点的集合
67:         nodeDataBack.add(nodeLeft);
68:         hashMap.put(nodeRight, nodeDataBack);
69:
70:       }
71:       data.close();
72:       return hashMap;
73:
74:     } catch (Exception e) {
75:       // TODO: handle exception
76:       return null;
77:     }
78:
79:   }
80:   /*
81:    * 路径输出到文件:
82:    * 思路:返回的路径存放在一个ArrayList中,每一条路径是一个Object[]类型数据
83:    *     输出路径会先判断存放路径文件夹是否存在,若存在则覆盖
84:    *            获取ArrayList的每一个数据后,输出路径,
85:    * 输入参数:result路径链表 , outpath路径结果存放文件所在位置
86:    */
87:   public static void outPutPath(ArrayList<Object[]> results, String outpath) {
88:
89:     File fileoutFile = new File(outpath);
90:     if (fileoutFile.isFile()) {
91:       System.out.println("文件已经存在,将覆盖原文件");
92:       fileoutFile.delete();
93:     }
94:     for (int i = 0; i < results.size(); i++) {
95:       Object[] existedObjects = results.get(i);
96:       String sPath = "";
97:       for (int j = 0; j < existedObjects.length; j++) {
98:         if (j < (existedObjects.length - 1))
99:           sPath = sPath + "node" + existedObjects[j] + "-->";
100:         else
101:           sPath = sPath + "node" + existedObjects[j] + "\n\r";
102:       }
103:       try {
104:         FileWriter writer = new FileWriter(outpath, true);
105:         writer.write(sPath);
106:         writer.write("\r\n");
107:         writer.close();
108:       } catch (Exception e) {
109:         // TODO: handle exception
110:       }
111:
112:     }
113:
114:   }
115:
116:   public static void main(String[] args) {
117:
118:     try {
119:       /*命令行参数形式:" /ftextshort2.txt /s105 /d110 /c1 /oresult.txt" */
120:       /*第一个参数为数据源, 第二个参数为起始节点 ,第三个参数为目的节点,第四个参数为约束条件,第五个参数为输出文件地址*/
121:       String inputPath = args[0].substring(2);
122:       String beginNode = args[1].substring(2);
123:       String endNode = args[2].substring(2);
124:       String requirements = args[3].substring(2);
125:       String outputPath = args[4].substring(2);
126:
127:       /* 从输入路径解析文件,并且将连接的点转为集合 */
128:       File fileInput = new File(inputPath);
129:       HashMap<Integer, ArrayList<Integer>> hashMap = getInput(inputPath);
130:
131:       double startTime = System.currentTimeMillis();
132:       /*设置节点寻找约束条件:1.表示没有相同节点;2.表示没有相同边*/
133:       HashFind.setrequirement = Integer.valueOf(requirements);
134:       HashFind hashFind = new HashFind(hashMap);
135:       /*获取节点路径的方法:采用深度优先*/
136:       boolean isPathExist = hashFind.getPaths(Integer.valueOf(beginNode),
137:                         null,Integer.valueOf(endNode));
138:       if (isPathExist) {
139:         System.out.println("路径不存在");
140:       }
141:       /*将获得的节点输出到文件中*/
142:       outPutPath(hashFind.sers, outputPath);
143:       long endTime = System.currentTimeMillis();
144:       System.out.println("运行时间是: " + (endTime - startTime)/1000 + "seconds");
145:       System.out.println("文件存储地址是:"+outputPath);
146:       System.out.println(Package.getPackages());
147:     } catch (Exception e) {
148:       // TODO: handle exception
149:       System.out.println("请输入正确参数");
150:     }
151:   }
152: }
153:

深度优先搜索:

1: package com.zhengjianbao.zcmatch;
2: /*From South Agricultural University,Electrical Information Majority zhengjianbao*/
3: import java.util.ArrayList;
4: import java.util.HashMap;
5: import java.util.Iterator;
6: import java.util.Stack;
7:
8: public class HashFind {
9:   public HashMap<Integer, ArrayList<Integer>> inputHash = new HashMap<Integer, ArrayList<Integer>>();
10:   public static Stack<Integer> stack = new Stack<Integer>();
11:   public static ArrayList<Object[]> sers = new ArrayList<Object[]>();
12:   public static int setrequirement;
13:   public static String sPath = null;
14:
15:   public HashFind(HashMap<Integer, ArrayList<Integer>> hash) {
16:     this.inputHash = hash;
17:   }
18:   /*
19:    * cNode:开始节点
20:    * pNode:开始节点的上一级节点(方便递归时调用)
21:    * targetNode:目标节点
22:    * */
23:   public boolean getPaths(Integer cNode, Integer pNode, Integer targetNode) {
24:     // 作为递归使用的节点,暂存当前节点的子节点
25:     Integer tmpNode = null;
26:     ArrayList<Integer> tmpNodeList = null;
27:
28:     if (cNode != null && pNode != null && cNode.equals(pNode)) {
29:       return false;
30:     }
31:
32:     if (cNode != null) {
33:       int i = 0;
34:       stack.push(cNode);
35:       if (cNode.equals(targetNode)) {
36:         // 当前节点==终止节点时,返回上一次递归(即目标节点父节点处)
37:         showAndSavePath();
38:         return true;
39:       } else {
40:         // 继续寻找当前节点连接的子节点
41:         tmpNodeList = inputHash.get(cNode);
42:         tmpNode = tmpNodeList.get(i);
43:         /*递归核心部分*/
44:         while (tmpNode != null) {
45:           // 判断这个子节点是否已经在堆栈中或当前节点的当前子节点是否仅与当前节点相连(即判断当前节点子节点是否只有一个父节点)
46:           if (pNode != null
47:               && (tmpNode.equals(pNode) || isNodeInStack(tmpNode))) {
48:             // 如果是的话移到当前节点的下一个子节点,并判断它是否为当前节点最后一个子节点
49:             i++;
50:             if (i >= tmpNodeList.size())
51:               tmpNode = null;
52:             else
53:               tmpNode = tmpNodeList.get(i);
54:             continue;
55:           }
56:           /*获取路径后逐次将路径上的节点弹出,直到找到一个点,它的兄弟节点没有被遍历,继续遍历它的兄弟节点*/
57:           if (getPaths(tmpNode, cNode, targetNode)) {
58:             stack.pop();
59:           }
60:           i++;
61:           if (i >= tmpNodeList.size())
62:             tmpNode = null;
63:           else
64:             tmpNode = tmpNodeList.get(i);
65:
66:         }
67:         // 不符合的路径,对最后压入堆栈中最后的元素清除
68:         // (tmpNode==null的时候表示没有子节点,tmpNode是cNode的子节点,因此就是把cNode弹出堆栈)
69:         // 一弹出堆栈以后,又返回上一级getPaths(tmpNode, cNode, targetNode)中
70:         // 然后直接+i,继续判断之前被弹出堆栈的cNode的父节点的下一个子节点
71:         stack.pop();
72:         return false;
73:       }
74:     } else {
75:       /*起始节点为空,说明到了叶子节点或者输入的起始节点有误*/
76:       return false;
77:     }
78:   }
79:
80:   /* 判断节点是否在栈中 */
81:   public static boolean isNodeInStack(Integer node) {
82:     Iterator<Integer> it = stack.iterator();
83:     while (it.hasNext()) {
84:       Integer node1 = (Integer) it.next();
85:       if (node.equals(node1))
86:         return true;
87:     }
88:     return false;
89:   }
90:
91:   /* 约束条件1:判断路径与之前路径是否有重复的点
92:    * 参数:待检测路径
93:    *  */
94:   public static boolean existSameNode(Object[] whichCheck) {
95:
96:     for (int i = 0; i < sers.size(); i++) {
97:       Object[] existedObjects = sers.get(i);
98:
99:       for (int j = 1; j < whichCheck.length - 1; j++) {
100:         for (int t = 1; t < existedObjects.length - 1; t++) {
101:           if (whichCheck[j].equals(existedObjects[t])) {
102:             return true;
103:           }
104:         }
105:       }
106:
107:     }
108:     return false;
109:   }
110:
111:   /* 约束条件2:判断路径与之前路径是否有重复的边
112:    * 参数:待检测路径
113:    * */
114:   public static boolean existSameLink(Object[] whichCheck) {
115:
116:     for (int i = 0; i < sers.size(); i++) {
117:       Object[] existedObjects = sers.get(i);
118:       for (int j = 0, j2 = j + 1; j2 < whichCheck.length - 1; j++, j2++) {
119:         for (int t = 0, t2 = t + 1; t2 < existedObjects.length - 1; t++, t2++) {
120:           if (whichCheck[j].equals(existedObjects[t])
121:               && whichCheck[j2].equals(existedObjects[t2])) {
122:             return true;
123:           }
124:         }
125:       }
126:     }
127:     return false;
128:   }
129:
130:   /* 将栈中所求得的路径存储到ArrayList中,存储的时候进行约束条件的判断 */
131:   public static void showAndSavePath() {
132:     Object[] o = stack.toArray();
133:
134:     switch (setrequirement) {
135:     case 1:
136:       if (existSameNode(o))
137:         return ;
138:       break;
139:     case 2:
140:       if (existSameLink(o))
141:         return ;
142:       break;
143:     default:
144:       break;
145:     }
146:     /* 转储 */
147:     sers.add(o);
148:   }
149: }


仅供参考,转载请注明出处,谢谢

有什么问题欢迎留言或者进新建群: 328797896,大家一起交流交流。(额…简单问题可先百度之)

附上可运行jar,bat文件以及测试用数据:

http://pan.baidu.com/share/link?shareid=2804835017&uk=1797141571
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: