遍历算法主要用在在处理迷宫问题,图,最短路径,以及枚举所有可能等问题上。下面我们通过一个简单的例子,来入门深度优先和广度优先算法:
1 package com.rampage.algorithm.base; 2 3 import java.util.ArrayList; 4 import java.util.LinkedHashSet; 5 import java.util.List; 6 import java.util.Set; 7 8 /** 9 * 相关的搜索算法实例 假设有1-9,9个数字,现在任意取三个,要求得到一共能得到多少个不同值的数字。如果可能的化输出所有可能的值。 10 * 11 * @author zyq 12 * 13 */ 14 public class SearchAlgorithm { 15 private static int totalCount = 0; // 存储总计数 16 private static Set<String> results = new LinkedHashSet<String>(); // 存储所有的结果 17 18 public static void main(String[] args) { 19 deepFirstSearch(); 20 breadthFirstSearch(); 21 } 22 23 /** 24 * 广度优先搜索:广度优先搜索算法的核心是列表。首先就得到第一步可以放的所有数,然后依次将其放入列表。接下来逐个处理列表中的每个数,给出接下来可能出现的第二个数, 25 * 处理完列表中的一个数就将该数从列表中移除。依次类推,直到待处理的列表中的元素为空。 26 */ 27 private static void breadthFirstSearch() { 28 totalCount = 0; 29 results.clear(); 30 List<String> possibleList = new ArrayList<String>(); 31 32 // 初始化列表,开始时第一号盒子可以放入1-9 33 for (int i = 1; i < 10; i++) { 34 possibleList.add(i + ""); 35 } 36 37 // 列表不为空的时候循环处理,因为又要增加又要删除,此时逆序遍历(此时即使用iterator,但是iterator没法删除元素,所以仍然会报错。) 38 while (!possibleList.isEmpty()) { 39 for (int i=possibleList.size() - 1; i>=0; i--) { 40 String element = possibleList.get(i); 41 // 长度为3说明3个数都放过了 42 if (element.length() == 3) { 43 totalCount++; 44 results.add(element); 45 possibleList.remove(i); 46 continue; 47 } 48 49 for (int j = 1; j < 10; j++) { 50 // 如果已经包含,则该数字不能再使用 51 if (element.contains(j + "")) { 52 continue; 53 } else { 54 // 如果没有包含对应的数字,则此时将数字加到元素后面,作为新的可能结果列表放入列表中 55 possibleList.add(element + j); 56 } 57 } 58 59 // 移除已经处理过的元素 60 possibleList.remove(i); 61 } 62 63 } 64 65 System.out.println("Total count:" + totalCount); 66 System.out.println(results); 67 } 68 69 /** 70 * 采用深度优先算法实现:深度优先算法的核心思想是迭代。既然要迭代就应该先抽象出每一步需要重复处理的数据。 可以这样思考深度优先算法: 71 * 假设有三个盒子,先往1号盒子放入1, 然后往2号盒子放入2,最后往3号盒子放入3.这样其实就组成了一个组合:123 72 * 要想得到其他的组合,则必须先收回3号盒子中的3,然后放入剩下的任意一个。依次类推,当3号盒子可能的情况都放完了之后,就需要同时取回3号和2号盒子中的东西, 73 * 然后在开始试。依次类推: 74 * 75 */ 76 private static void deepFirstSearch() { 77 totalCount = 0; 78 results.clear(); 79 int[] book = new int[10]; // 定义已经使用过的数字,如果使用过某数字i,那么book[i] = 1 80 int[] result = new int[3]; // 存储当前的三个数字组成的数组 81 go(book, result, 0); 82 System.out.println("Total count:" + totalCount); 83 System.out.println(results); 84 } 85 86 /** 87 * @param book 88 * 存储已经放过的数字 89 * @param step 90 * 第几步,就相当于前面所说的放第几个盒子(第一个盒子对应第0步) 91 */ 92 private static void go(int[] book, int[] result, int step) { 93 if (step == 3) { 94 totalCount++; 95 results.add(new String(result[0] + "" + result[1] + "" + result[2])); 96 return; 97 } 98 for (int i = 1; i < 10; i++) { 99 if (book[i] == 1) { 100 continue; 101 } 102 book[i] = 1; // 标记i已经被使用 103 result[step] = i; 104 // 因为是深度优先,所以需要继续往更深处遍历 105 go(book, result, step + 1); 106 107 // 因为还要尝试其他组合所以这里沿路返回 108 book[i] = 0; 109 result[step] = 0; 110 } 111 } 112 }