当前位置:   article > 正文

JAVA-DFS深度优先搜索-解决链表有向图节点路径问题_java dfs

java dfs

定义一个自定义链表,存储两个id,left为左对象的id,right为右对象的id,

同一个链表中的左右对象id不能重复,

不同链表中的

前一个节点的右对象只能够与后一个节点的左对象相连接,要求输出对象路径顺序,以left与right的顺序输出,

例图1-1:

输入一个链表数组(可自定义),传入5个链表对象.指定一个起点对象,这里指定node:11为起点

 

                                                            图1-1

输出:

1(11)->2(11)->2(12)->4(12)->4(13)->6(13)

1(11)->2(11)->2(14)->7(14)->7(15)->8(15)

首先考虑深度优先算法(DFS)+回溯算法.

深度优先算法(Depth First Search,简称DFS):它是一种用于遍历或搜索树或图的暴力算法,沿着树的深度遍历树的节点,尽可能深的遍历树的分支。

回溯算法:结合深度优先算法,当路径搜索完毕后,返回上一节点,再次递归,看是否还有其他路径可以搜索,这样可以搜索有向图的所有路径.

 话不多说,上JAVA代码:

定义一个链表对象

  1. @Data
  2. @AllArgsConstructor
  3. @NoArgsConstructor
  4. public class NodeLine {
  5. private String node;
  6. private String left;
  7. private String right;
  8. }

DFS测试类

  1. public class DfsTest {
  2. public static void main(String[] args) {
  3. List<NodeLine> nodeLines = new ArrayList<>();
  4. nodeLines.add(new NodeLine("11", "1", "2"));
  5. nodeLines.add(new NodeLine("12", "2", "4"));
  6. nodeLines.add(new NodeLine("13", "4", "6"));
  7. nodeLines.add(new NodeLine("14", "2", "7"));
  8. nodeLines.add(new NodeLine("15", "7", "8"));
  9. //用来记录顶点的map
  10. Map<String, Integer> beginIsVisited = new HashMap<>();
  11. beginIsVisited.put("1", 0);
  12. //用来记录节点是否被访问过,首先先将所有节点放到map中,key为node+left或node+right
  13. Map<String, Integer> visitedMap = new HashMap<>();
  14. for (NodeLine nodeLine : nodeLines) {
  15. String node = nodeLine.getNode();
  16. String left = nodeLine.getLeft();
  17. String right = nodeLine.getRight();
  18. if (visitedMap.containsKey(node + "-" + left)) {
  19. String msg = "node-left重复:" + node + "-" + left;
  20. System.out.println("msg = " + msg);
  21. } else {
  22. visitedMap.put(node + "-" + left, 0);
  23. }
  24. if (visitedMap.containsKey(node + "-" + right)) {
  25. String msg = "node-right重复:" + node + "-" + right;
  26. System.out.println("msg = " + msg);
  27. } else {
  28. visitedMap.put(node + "-" + right, 0);
  29. }
  30. }
  31. //定义连线路径list(可能有多条路径)
  32. List<String> visitedLine = new ArrayList<>();
  33. StringBuffer stringBuffer = new StringBuffer();
  34. dfs(nodeLines, visitedMap, "1", stringBuffer, beginIsVisited, visitedLine);
  35. //打印路径
  36. for (String line : visitedLine) {
  37. //去除尾端箭头
  38. line = line.substring(0, line.lastIndexOf("->"));
  39. System.out.println("line = " + line);
  40. }
  41. }
  42. public static void dfs(List<NodeLine> nodeLines, Map<String, Integer> visitedMap,
  43. String beginId, StringBuffer stringBuffer, Map<String, Integer> beginIsVisited,
  44. List<String> visitedLine) {
  45. //递归终止条件,若节点全被访问过,则递归终止,或者循环结束
  46. if (!visitedMap.containsValue(0)) {
  47. //若节点不含有0,则全部被访问过
  48. return;
  49. }
  50. for (NodeLine nodeLine : nodeLines) {
  51. String node = nodeLine.getNode();
  52. String left = nodeLine.getLeft();
  53. String right = nodeLine.getRight();
  54. String leftMapKey = node + "-" + left;
  55. String rightMapKey = node + "-" + right;
  56. //若点被访问过,则跳过
  57. if (visitedMap.containsKey(leftMapKey) && visitedMap.containsKey(rightMapKey)) {
  58. if ((visitedMap.get(leftMapKey) != 0) && (visitedMap.get(rightMapKey) != 0)) {
  59. //System.out.println(leftMapKey + "节点被访问过" + rightMapKey + "节点被访问过");
  60. continue;
  61. }
  62. }
  63. //先找出起点
  64. if (left.equals(beginId)) {
  65. //点对点,记录该点被访问
  66. visitedMap.put(leftMapKey, 1);
  67. visitedMap.put(rightMapKey, 1);
  68. //记录顶点被访问
  69. if (beginIsVisited.containsKey(beginId)) {
  70. beginIsVisited.put(beginId, 1);
  71. }
  72. stringBuffer.
  73. append(left).
  74. append("(").append(node).append(")").
  75. append("->").
  76. append(right).
  77. append("(").append(node).append(")").
  78. append("->");
  79. //开始递归遍历
  80. dfs(nodeLines, visitedMap, right, stringBuffer, beginIsVisited, visitedLine);
  81. //选择回溯的点位来记录终点情况
  82. //添加的路径长度
  83. int addLength = left.length() + 1 + node.length() + 1 + 2 + right.length() + 1 + node.length() + 1 + 2;
  84. //这里要深拷贝一个对象:重新定义一个string对象.stringBuffer赋值为浅拷贝,
  85. //会改变原有stringBuffer的值,而实例化一个string对象则可以直接赋值.
  86. String s = stringBuffer.toString();
  87. // 若路径中不含有该路径,则添加进路径集合中
  88. if (!lineContains(visitedLine, s)) {
  89. visitedLine.add(s);
  90. }
  91. stringBuffer.delete(stringBuffer.length() - addLength, stringBuffer.length());
  92. //回溯(点可以重复被访问)
  93. visitedMap.put(leftMapKey, 0);
  94. visitedMap.put(rightMapKey, 0);
  95. }
  96. }
  97. }
  98. //用来标注路径是否重复,若不重复,则记录
  99. public static boolean lineContains(List<String> visitedLine, String s) {
  100. for (String s1 : visitedLine) {
  101. if (s1.startsWith(s)) {
  102. return true;
  103. }
  104. }
  105. return false;
  106. }
  107. }

程序运行结果:

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/笔触狂放9/article/detail/476108
推荐阅读
相关标签
  

闽ICP备14008679号