十大算法的java实现

目录

二分查找非递归算法实现

分治算法解决汉诺塔问题

 动态规划算法解决01背包问题

暴力匹配算法解决字符串匹配问题

KMP算法解决字符串匹配问题

贪心算法解决集合覆盖问题

普里姆算法解决最短修路问题(最小生成树)

克鲁斯卡尔算法解决最短修路问题(最小生成树)

迪杰斯特拉算法解决最短路径问题

弗洛伊德算法解决最短路径问题

回溯算法解决骑士周游问题

二分查找非递归算法实现

public class BinarySearch {

	public static void main(String[] args) {
		int[] arr = { 1, 3, 8, 10, 11, 67, 100 };
		int i = BinarySearch(arr, 1);
		System.out.println("找到的下标为:" + i);
	}

	/**
	 * @param arr    待查找数组,arr是升序排列
	 * @param target 需要查找的数
	 * @return 查找的数的下标,-1表示没找到
	 */
	public static int BinarySearch(int[] arr, int target) {
		int left = 0;
		int right = arr.length - 1;
		while (left <= right) {
			int mid = (left + right) / 2;
			if (arr[mid] == target) {
				return mid;
			} else if (arr[mid] > target) {
				right = mid - 1;
			} else {
				left = mid + 1;
			}
		}
		return -1;
	}
}

分治算法解决汉诺塔问题

public class HanoiTower {
	public static void main(String[] args) {
		hanoiTower(5, 'a', 'b', 'c');
	}

	public static void hanoiTower(int num, char a, char b, char c) {
		if (num == 1) {
			System.out.println("第" + num + "个盘从" + a + "->" + c);
		} else {
			// 把上面的num-1个盘移动到b,然后把第num个盘移动到c,然后把num-1个盘移动到c
			hanoiTower(num - 1, a, c, b);
			System.out.println("第" + num + "个盘从" + a + "->" + c);
			hanoiTower(num - 1, b, a, c);
		}
	}
}

 动态规划算法解决01背包问题

public class BagProblem {
	public static void main(String[] args) {
		int[] w = { 1, 4, 3 };// 物品的重量
		int[] val = { 1500, 3000, 2000 };// 物品的价值
		int m = 4;// 背包的容量
		int n = val.length;// 物品的个数

		// 创建二维数组,v[i][j]表示前i个物品能够装入容量为j的背包中的最大价值
		int[][] v = new int[n + 1][m + 1];
		// 创建一个二维数组,path[i][j]表示放入商品的 情况
		int[][] path = new int[n + 1][m + 1];

		// 初始化第一行和第一列,在本程序中可以不写,默认为0,但是写了就表示我们有处理
		for (int i = 0; i < v.length; i++) {
			v[i][0] = 0;// 将第一列设置为0
		}
		for (int i = 0; i < v[0].length; i++) {
			v[0][i] = 0;// 将第一行设置为0
		}

		// 动态规划处理
		for (int i = 1; i < v.length; i++) {// 从第一行开始处理,不处理第0行
			for (int j = 1; j < v[i].length; j++) {// 从第一例开始处理,不处理第0列
				if (w[i - 1] > j) {// 因为i是从1开始的,w[0]表示第一个物品的重量,所以要w[i-1]
					v[i][j] = v[i - 1][j];
				} else {
//					v[i][j] = Math.max(v[i - 1][j], val[i - 1] + v[i - 1][j - w[i - 1]]);// val[i]也要改成val[i-1],w[i]也要改成w[i-1]
					if (v[i - 1][j] > val[i - 1] + v[i - 1][j - w[i - 1]]) {
						v[i][j] = v[i - 1][j];
						path[i][j] = 1;
					} else {
						v[i][j] = val[i - 1] + v[i - 1][j - w[i - 1]];
						path[i][j] = 1;
					}
				}
			}
		}

		// 输出v
		for (int i = 0; i < v.length; i++) {
			for (int j = 0; j < v[i].length; j++) {
				System.out.print(v[i][j] + " ");
			}
			System.out.println();
		}

		// 输出最后我们放入的商品
		// 此时我们需要的是最后放入的情况
		int i = path.length - 1;
		int j = path[0].length - 1;
		while (i > 0 && j > 0) {
			if (path[i][j] == 1) {
				System.out.println("第" + i + "个商品放入背包");
				j -= w[i - 1];
			}
			i--;
		}

	}

}

暴力匹配算法解决字符串匹配问题

public class ViolenceMatch {
	public static void main(String[] args) {
		String s1 = "fdjslkfjasd;lkfjhoifhasdlkfmjsdklfjjujsdfo;as";
		String s2 = "fjj";
		int violenceMatch = violenceMatch(s1, s2);
		System.out.println(violenceMatch);

	}

	// 暴力匹配算法
	public static int violenceMatch(String s1, String s2) {
		char[] c1 = s1.toCharArray();
		char[] c2 = s2.toCharArray();

		int length = c1.length;
		int length2 = c2.length;

		int i = 0;
		int j = 0;
		while (i < length && j < length2) {

			if (c1[i] == c2[j]) {
				i++;
				j++;
			} else {
				i = i - (j - 1);
				j = 0;
			}
		}

		if (j == length2) {
			return i - j;
		} else {
			return -1;
		}
	}

}

KMP算法解决字符串匹配问题

public class KMPAlgorithm {
	public static void main(String[] args) {
		String s1 = "BBC ABCDAB ABCDABCDABDE";
		String s2 = "ABCDABD";

		int[] kmpNext = kmpNext(s2);
		System.out.println(Arrays.toString(kmpNext));

		int index = kmp(s1, s2, kmpNext);
		System.out.println("index=" + index);
	}

	// 先来一个方法,获取到一个字符串(子串)的部分匹配值
	public static int[] kmpNext(String string) {
		// 创建一个数组,大小为string.length
		int[] next = new int[string.length()];

		next[0] = 0;// 如果字符串只有一个字符,那部分匹配值就是0;
		for (int i = 1, j = 0; i < next.length; i++) {
			while (j > 0 && string.charAt(i) != string.charAt(j)) {
				j = next[j - 1];
			}

			if (string.charAt(i) == string.charAt(j)) {
				j++;
			}
			next[i] = j;
		}
		return next;
	}

	// kmp算法
	public static int kmp(String s1, String s2, int[] next) {
		for (int i = 0, j = 0; i < s1.length(); i++) {
			while (j > 0 && s1.charAt(i) != s2.charAt(j)) {
				j = next[j - 1];
			}

			if (s1.charAt(i) == s2.charAt(j)) {
				j++;
			}

			if (j == s2.length()) {
				return i - (j - 1);
			}
		}
		return -1;
	}

}

贪心算法解决集合覆盖问题

public class GreedyAlgorithm {
	public static void main(String[] args) {
		// 创建广播电台,放到Map中
		HashMap<String, HashSet<String>> broadcasts = new HashMap<String, HashSet<String>>();

		HashSet<String> hashSet1 = new HashSet<String>();
		hashSet1.add("北京");
		hashSet1.add("上海");
		hashSet1.add("天津");
		HashSet<String> hashSet2 = new HashSet<String>();
		hashSet2.add("广州");
		hashSet2.add("北京");
		hashSet2.add("深圳");
		HashSet<String> hashSet3 = new HashSet<String>();
		hashSet3.add("成都");
		hashSet3.add("上海");
		hashSet3.add("杭州");
		HashSet<String> hashSet4 = new HashSet<String>();
		hashSet4.add("上海");
		hashSet4.add("天津");
		HashSet<String> hashSet5 = new HashSet<String>();
		hashSet5.add("杭州");
		hashSet5.add("大连");

		broadcasts.put("k1", hashSet1);
		broadcasts.put("k2", hashSet2);
		broadcasts.put("k3", hashSet3);
		broadcasts.put("k4", hashSet4);
		broadcasts.put("k5", hashSet5);

		HashSet<String> allAreas = new HashSet<String>();// 这个存放所有的地区
		allAreas.addAll(hashSet1);
		allAreas.addAll(hashSet2);
		allAreas.addAll(hashSet3);
		allAreas.addAll(hashSet4);
		allAreas.addAll(hashSet5);

		System.out.println(allAreas);

		ArrayList<String> selects = new ArrayList<String>();// 这里创建一个ArrayList用来存放选上的电台

		HashSet<String> tempSet = new HashSet<String>();// 这里 一个HashSet用来临时存储遍历过程中的某个电台所覆盖的地区

		String maxKey = null;// 定义一个maxKey用来保存遍历过程中能够覆盖最多的未被覆盖地区的电台

		while (allAreas.size() != 0) {// allAreas里面的地区是不断减少的

			maxKey = null;// 置空maxKey

			for (String k : broadcasts.keySet()) {

				tempSet.clear();// 置空临时的存储某个电台覆盖地区的这个tempSet

				HashSet<String> areas = broadcasts.get(k);// 遍历过程中的某个电台可以覆盖的地区保存下来
				tempSet.addAll(areas);// 用我们定义好的tempSet变量存储地区
				tempSet.retainAll(allAreas);// 筛选出这个电台覆盖地区与未被覆盖地区的交集
				if (tempSet.size() > 0 &&
				// 表示maxKey还没有选到或者 现在这个k电台所覆盖的地区数大于之前选到的maxKey所覆盖的地区数,此时替换maxKey
						(maxKey == null || tempSet.size() > broadcasts.get(maxKey).size())) {
					maxKey = k;
				}

				// 每进行依次for循环,这里的 tempSet也要置空,同样写在for循环刚开始的时候

			}
			if (maxKey != null) {
				selects.add(maxKey);// 此时maxKey电台真正的被选上,这里加进去然后会把他所覆盖的地区从未覆盖的地区删除了
				allAreas.removeAll(broadcasts.get(maxKey));
			}

			// 此时要把maxKey置空,以防止下一次遍历时,本来已经要结束了,maxKey就是null,但是没有置空,就会又加进去一个电台
			// 然而置空的操作写在while循环刚开始的地方。
		}

		System.out.println(selects);

	}
}

普里姆算法解决两点间最短路径问题

三个链表分别存储:是否存在该节点;该节点与已选区域的边的长度;父节点

public class PrimAlgorithm {
	public static void main(String[] args) {
		char[] data = new char[] { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
		int verxs = data.length;
		int[][] weight = new int[][] { { 10, 5, 7, 10, 10, 10, 2 }, { 5, 10, 10, 9, 10, 10, 3 },
				{ 7, 10, 10, 10, 8, 10, 10 }, { 10, 9, 10, 10, 10, 4, 10 }, { 10, 10, 8, 10, 10, 5, 4 },
				{ 10, 10, 10, 4, 5, 10, 6 }, { 2, 3, 10, 10, 4, 6, 10 }, };

		MGraph mGraph = new MGraph(verxs);

		MinTree minTree = new MinTree();
		minTree.createGraph(mGraph, verxs, data, weight);
		minTree.show(mGraph);

		minTree.prim(mGraph, 0);

	}
}

//创建最小生成树
class MinTree {
	/**
	 * @param graph  图对象
	 * @param verxs  图的顶点个数
	 * @param data   图的各个顶点的值
	 * @param weight 图的邻接矩阵
	 */
	public void createGraph(MGraph graph, int verxs, char[] data, int[][] weight) {
		for (int i = 0; i < verxs; i++) {
			graph.data[i] = data[i];
			for (int j = 0; j < verxs; j++) {
				graph.weight[i][j] = weight[i][j];
			}
		}
	}

	// 显示图的邻接矩阵
	public void show(MGraph graph) {
		for (int[] link : graph.weight) {
			System.out.println(Arrays.toString(link));
		}
	}

	// 编写prim算法,获得最小生成树
	/**
	 * @param graph 邻接矩阵
	 * @param v     表示从图的第几个顶点开始生成
	 */
	public void prim(MGraph graph, int v) {
		int[] visited = new int[graph.verxs];// 用一个一维数组来表示节点是否被访问过了,0表示没有访问,1表示访问过了

		// 刚开始时我们传进来一个节点,先把这个节点设置成已经访问过的
		visited[v] = 1;

		// 定义一个边最小为10(因为我的邻接矩阵中的最大的就是10,这个最小边不可能是10,所以我这里的10就表示的这两个点不连接)
		int minWeight = 10;

		// 定义两个int型的数字来表示顶点的位置
		int h1 = -1;
		int h2 = -1;

		// 此时我们知道,普里姆算法中,如果有n个节点,那将会产生n-1条边,所以:
		for (int k = 0; k < graph.verxs - 1; k++) {

			// 查找被访问过的节点和没有被访问的节点之间最短的那一条边
			for (int i = 0; i < graph.verxs; i++) {// 表示访问过的节点,if()语句给出条件限制
				for (int j = 0; j < graph.verxs; j++) {// 表示没有访问过的节点,if()语句给出条件限制
					if (visited[i] == 1 && visited[j] == 0 && minWeight > graph.weight[i][j]) {
						// 替换掉这个minWeight
						minWeight = graph.weight[i][j];
						// 此时要考虑记录这两个节点,所有定义两个节点,又因为要输出所以定义在for循环之外
						h1 = i;
						h2 = j;

					}
				}
			}

			// 此时必定有一个minWeight,我们输出这个边,和两个点
			System.out.println("节点:" + graph.data[h1] + "和节点:" + graph.data[h2] + "之间权值最小,为:" + minWeight);

			// 最后把找到的这个节点标记为访问过的
			visited[h2] = 1;

			// 重置用到的元素
			minWeight = 10;
			// 因为h1和h2在循环之外定义的所以不用重置,否则也要重置

		}

	}

}

class MGraph {
	int verxs;// 表示节点个数
	char[] data;// 存放节点上的字母(村庄)
	int[][] weight;// 存放边,也就是邻接矩阵

	public MGraph(int verxs) {
		this.verxs = verxs;
		data = new char[verxs];
		weight = new int[verxs][verxs];
	}
}

克鲁斯卡尔算法解决两点间最短路径问题

所有边排序,从小到大依次添加,不构成环的情况下连接所有的顶点

public class KruskalCase {
	public static void main(String[] args) {
		char[] vertexs = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
		int matrix[][] = { { 0, 12, INF, INF, INF, 14, 16 }, { 12, 0, 10, INF, INF, 7, INF },
				{ INF, 10, 0, 3, 5, 6, INF }, { INF, INF, 3, 0, 4, INF, INF }, { INF, INF, 5, 4, 0, 2, 8 },
				{ 16, 7, 6, INF, 2, 0, 9 }, { 14, INF, INF, INF, 8, 9, 0 } };

		KruskalCase kruskalCase = new KruskalCase(vertexs, matrix);

		kruskalCase.print();

		EData[] edges = kruskalCase.getEdges();
		System.out.println("排序前" + Arrays.toString(edges));

		kruskalCase.sortEdges(edges);

		System.out.println("排序后" + Arrays.toString(edges));

		kruskalCase.kruskal();

	}

	private int edgeNum;// 边的个数
	private char[] vertexs;// 顶点数组
	private int[][] matrix;// 邻接矩阵
	private static final int INF = 100;// 表示不能联通

	public KruskalCase(char[] vertexs, int[][] matrix) {
//		 初始化顶点数和边的个数		
//		this.vertexs = vertexs;
//		this.matrix = matrix;

//		这里是复制拷贝的方式,就是在构造器中重新创建一个数组
		int vlen = vertexs.length;
		// 初始化顶点
		this.vertexs = new char[vlen];
		for (int i = 0; i < vertexs.length; i++) {
			this.vertexs[i] = vertexs[i];
		}
		// 初始化边
		this.matrix = new int[vlen][vlen];
		for (int i = 0; i < vlen; i++) {
			for (int j = 0; j < vlen; j++) {
				this.matrix[i][j] = matrix[i][j];
			}
		}
		// 统计边
		for (int i = 0; i < vlen; i++) {
			for (int j = i + 1; j < vlen; j++) {
				if (this.matrix[i][j] != INF) {
					edgeNum++;
				}
			}
		}

	}

	// 打印邻接矩阵
	public void print() {
		for (int i = 0; i < vertexs.length; i++) {
			for (int j = 0; j < vertexs.length; j++) {
				System.out.print(matrix[i][j] + "\t");
			}
			System.out.println();
		}
	}

	// 对边进行排序,冒泡排序
	private void sortEdges(EData[] eDatas) {
		for (int i = 0; i < eDatas.length - 1; i++) {
			for (int j = 0; j < eDatas.length - 1 - i; j++) {
				if (eDatas[j].weight > eDatas[j + 1].weight) {
					EData temp = eDatas[j];
					eDatas[j] = eDatas[j + 1];
					eDatas[j + 1] = temp;
				}
			}
		}
	}

	/**
	 * @param ch 顶点的值
	 * @return 返回ch顶点对应的下标,如果没有就返回-1
	 */
	private int getPosition(char ch) {
		for (int i = 0; i < vertexs.length; i++) {
			if (ch == vertexs[i]) {
				return i;
			}
		}
		return -1;
	}

	private EData[] getEdges() {
		int index = 0;
		EData[] edges = new EData[edgeNum];
		for (int i = 0; i < vertexs.length; i++) {
			for (int j = i + 1; j < vertexs.length; j++) {
				if (matrix[i][j] != INF) {
					edges[index++] = new EData(vertexs[i], vertexs[j], matrix[i][j]);
				}
			}
		}
		return edges;
	}

	/**
	 * 获取下标为i的顶点的终点
	 * 
	 * @param ends 数组就是记录了各个顶点对应的终点是哪个,ends数组是在遍历的过程中逐步形成的
	 * @param i    表示传入顶点对应的下标
	 * @return 返回下标i的顶点对应的终点的下标
	 */
	private int getEnd(int[] ends, int i) {
		while (ends[i] != 0) {
			i = ends[i];
		}
		return i;
	}

	public void kruskal() {
		int index = 0; // 表示最后结果数组的索引

		int[] ends = new int[edgeNum]; // 用来保存已有的最小生成树的每个顶点对应的顶点

		EData[] rets = new EData[edgeNum];// 创建结果数组,保存最后的最小生成树

		EData[] edges = getEdges();
		System.out.println("图中有" + edges.length + "条边,集合为:" + Arrays.toString(edges));

		// 首先排序(从小到大)
		sortEdges(edges);

		// 遍历edges数组,将边添加到最小生成树中,同时判断是否生成回路,如果每生成回路,就加到rets中
		for (int i = 0; i < edgeNum; i++) {
			int p1 = getPosition(edges[i].start);// 获取到当前边的第一个顶点
			int p2 = getPosition(edges[i].end);// 获取到当前边的第二个顶点

			int end1 = getEnd(ends, p1);// 获取p1对应的终点
			int end2 = getEnd(ends, p2);// 获取p2对应的终点

			if (end1 != end2) {// 没有构成回路
				ends[end1] = end2;// 设置end1对应的终点为end2(在现有的最小生成树中)
				rets[index++] = edges[i];// 这条边进入最后的结果数组中
			}

		}

		// 统计并打印最小生成树
		System.out.println("最小生成树为:");
		for (int i = 0; i < index; i++) {
			System.out.println(rets[i]);

		}

	}

}

//创建一个类,其对象实例就是一条边
class EData {
	char start;
	char end;
	int weight;

	public EData(char start, char end, int weight) {
		super();
		this.start = start;
		this.end = end;
		this.weight = weight;
	}

	@Override
	public String toString() {
		return "EData [<" + start + "," + end + ">=" + weight + "]";
	}

}

迪杰斯特拉算法解决最短路径问题

public class DijkstraAlgorithm {
	public static void main(String[] args) {
		char[] vertex = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
		int[][] matrix = new int[vertex.length][vertex.length];
		final int N = 100;// 表示不可连接
		matrix[0] = new int[] { N, 5, 7, N, N, N, 2 };
		matrix[1] = new int[] { 5, N, N, 9, N, N, 3 };
		matrix[2] = new int[] { 7, N, N, N, 8, N, N };
		matrix[3] = new int[] { N, 9, N, N, N, 4, N };
		matrix[4] = new int[] { N, N, 8, N, N, 5, 4 };
		matrix[5] = new int[] { N, N, N, 4, 5, N, 6 };
		matrix[6] = new int[] { 2, 3, N, N, 4, 6, N };

		Graph graph = new Graph(vertex, matrix);
		graph.showGraph();
		graph.djs(6);

		graph.showdjs();
	}
}

class Graph {
	private char[] vertex;// 顶点数组
	private int[][] matrix;// 邻接矩阵
	private VisitedVertex vv;// 已经访问的顶点的集合

	public Graph(char[] vertex, int[][] matrix) {
		this.vertex = vertex;
		this.matrix = matrix;
	}

//显示邻接矩阵
	public void showGraph() {
		for (int[] i : matrix) {
			System.out.println(Arrays.toString(i) + " ");
		}
	}

//迪杰斯特拉算法的实现,index表示出发顶点对应的下标
	public void djs(int index) {
		vv = new VisitedVertex(vertex.length, index);
		updata(index);// 更新index顶点到周围顶底的距离和前驱节点
		for (int i = 1; i < vertex.length; i++) {
			index = vv.updateArr();// 更新并返回新的访问节点
			updata(index);// 更新index顶点到周围顶底的距离和前驱节点
		}
	}

//更新index下标顶点到周围顶点的距离和周围顶点的前驱节点
	public void updata(int index) {
		int len = 0;
		// 遍历邻接矩阵的matrix[index]行
		for (int j = 0; j < matrix[index].length; j++) {
			len = vv.getDis(index) + matrix[index][j];
			// 顶点j没有被访问过,并且这条路的举例小于之前的初始节点到j的举例
			if (!vv.in(j) && len < vv.getDis(j)) {
				vv.updataDis(j, len);
				vv.updataPre(j, index);
			}
		}
	}

//显示结果
	public void showdjs() {
		vv.show();
	}

}

class VisitedVertex {
	public int[] already_arr;// 记录各个顶点是否已经访问过,访问过为1,否则为0.初始为0;
	public int[] pre_visited;// 对应每个顶点的前一个节点的下标,动态更新
	public int[] dis;// 记录从初始节点到其他顶点的距离, 初始化为不连接,用100来表示,节点本身到本身的距离为0

	public VisitedVertex(int length, int index) {
		this.already_arr = new int[length];
		this.pre_visited = new int[length];
		this.dis = new int[length];
		already_arr[index] = 1;
		Arrays.fill(dis, 100);
		dis[index] = 0;
	}

//判断index节点是否已经被访问过了
	public boolean in(int index) {
		return already_arr[index] == 1;
	}

//更新index节点到初始节点的距离为len
	public void updataDis(int index, int len) {
		dis[index] = len;
	}

//跟新pre节点的前驱节点的下标为index
	public void updataPre(int pre, int index) {
		pre_visited[pre] = index;
	}

//获取index节点到初始节点的距离
	public int getDis(int index) {
		return dis[index];
	}

//继续选择并返回新的访问节点
	public int updateArr() {
		int min = 100, index = 0;
		for (int i = 0; i < already_arr.length; i++) {
			if (already_arr[i] == 0 && dis[i] < min) {
				min = dis[i];
				index = i;
			}
		}
		already_arr[index] = 1;
		return index;
	}

//显示最后结果,就是三个数组的输出
	public void show() {
		System.out.println("+==================================+");
		for (int i : already_arr) {
			System.out.print(i + " ");
		}
		System.out.println();
		for (int i : pre_visited) {
			System.out.print(i + " ");
		}
		System.out.println();
		for (int i : dis) {
			System.out.print(i + " ");
		}
		System.out.println();

		// 为了方便看最后结果
		char[] vertex = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
		int count = 0;
		for (int i : dis) {
			if (i != 100) {
				System.out.print(vertex[count] + "-> " + i + "   ");
			} else {
				System.out.println("N ");
			}
			count++;
		}
		System.out.println();

	}
}

弗洛伊德算法解决最短路径问题

public class FloydAlgorithm {
	public static void main(String[] args) {
		char[] vertex = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
		int[][] matrix = new int[vertex.length][vertex.length];
		final int N = 100;// 表示不可连接
		matrix[0] = new int[] { 0, 5, 7, N, N, N, 2 };
		matrix[1] = new int[] { 5, 0, N, 9, N, N, 3 };
		matrix[2] = new int[] { 7, N, 0, N, 8, N, N };
		matrix[3] = new int[] { N, 9, N, 0, N, 4, N };
		matrix[4] = new int[] { N, N, 8, N, 0, 5, 4 };
		matrix[5] = new int[] { N, N, N, 4, 5, 0, 6 };
		matrix[6] = new int[] { 2, 3, N, N, 4, 6, 0 };

		Graph graph = new Graph(7, vertex, matrix);

		graph.floyd();
		graph.show();
	}
}

class Graph {
	private char[] vertex;// 存放顶点
	private int[][] dis;// 保存各个顶点出发到其他顶点之间的距离
	private int[][] pre;// 保存到达目标节点的前驱节点的下标

	public Graph(int length, char[] vertex, int[][] matrix) {
		this.vertex = vertex;
		this.dis = matrix;
		this.pre = new int[length][length];// 这个需要初始化,一开始存放的前驱节点就是自己
		for (int i = 0; i < length; i++) {
			Arrays.fill(pre[i], i);
		}
	}

	// 显示pre数组和dis数组
	public void show() {
		// 为了便于阅读
		char[] vertex = { 'a', 'b', 'c', 'd', 'e', 'f', 'g' };
		for (int i = 0; i < dis.length; i++) {
			for (int j = 0; j < dis.length; j++) {
				System.out.print(vertex[pre[i][j]] + "\t\t");
			}
			System.out.println();
			for (int j = 0; j < dis.length; j++) {
				System.out.print("(" + vertex[i] + "到" + vertex[j] + "=" + dis[i][j] + ")       ");
			}
			System.out.println();
			System.out.println();
		}
	}
//弗洛伊德算法
	public void floyd() {
		int len = 0;
		for (int k = 0; k < dis.length; k++) {// 对中间节点的遍历
			for (int i = 0; i < dis.length; i++) {// 对初始节点的遍历
				for (int j = 0; j < dis.length; j++) {// 对最终节点的遍历
					len = dis[i][k] + dis[k][j];
					if (len < dis[i][j]) {
						dis[i][j] = len;
						pre[i][j] = pre[k][j];// 更新前驱节点
					}
				}
			}
		}
	}

}

回溯算法解决骑士周游问题

public class HouseChess {
	public static void main(String[] args) {
		System.out.println("骑士周游算法:");
		X = 8;
		Y = 8;
		int row = 0;
		int column = 0;

		int[][] chessBoard = new int[X][Y];

		visited = new boolean[X * Y];

		long l1 = System.currentTimeMillis();

		traver(chessBoard, row, column, 1);

		long l2 = System.currentTimeMillis();
		System.out.println("时间:" + (l2 - l1));

		System.out.println("棋盘:");

		for (int[] i : chessBoard) {
			System.out.println(Arrays.toString(i));
		}

	}

	private static int X;// 棋盘的列数
	private static int Y;// 棋盘的行数
	private static boolean visited[];// 表示是否被访问过
	private static boolean finished;// 表示是否全部走完

	/**
	 * 
	 * @param chessBoard 棋盘
	 * @param row        马儿当前在第几行,从0开始
	 * @param column     马儿当前在第几列,从0开始
	 * @param step       第几步,初始位置为第一步
	 */
	public static void traver(int[][] chessBoard, int row, int column, int step) {
		chessBoard[row][column] = step; // 定位初始位置为第一步
		visited[row * X + column] = true; // 初始位置已经被访问
		ArrayList<Point> next = next(new Point(column, row));

		sort(next);
		
		while (!next.isEmpty()) {
			Point p = next.remove(0);
			if (!visited[p.y * X + p.x]) {
				traver(chessBoard, p.y, p.x, step + 1);
			}
		}

		if (step < X * Y && !finished) {
			chessBoard[row][column] = 0;
			visited[row * X + column] = false;
		} else {
			finished = true;
		}
	}

//返回下一步可以走的位置,用一个ArrayList来表示
	public static ArrayList<Point> next(Point point) {
		ArrayList<Point> ps = new ArrayList<Point>();
		Point p1 = new Point();
		if ((p1.x = point.x - 2) >= 0 && (p1.y = point.y - 1) >= 0) {
			ps.add(new Point(p1));
		}
		// 判断马儿可以走6这个位置
		if ((p1.x = point.x - 1) >= 0 && (p1.y = point.y - 2) >= 0) {
			ps.add(new Point(p1));
		}
		// 判断马儿可以走7这个位置
		if ((p1.x = point.x + 1) < X && (p1.y = point.y - 2) >= 0) {
			ps.add(new Point(p1));
		}
		// 判断马儿可以走0这个位置
		if ((p1.x = point.x + 2) < X && (p1.y = point.y - 1) >= 0) {
			ps.add(new Point(p1));
		}
		// 判断马儿可以走1这个位置
		if ((p1.x = point.x + 2) < X && (p1.y = point.y + 1) < Y) {
			ps.add(new Point(p1));
		}
		// 判断马儿可以走2这个位置
		if ((p1.x = point.x + 1) < X && (p1.y = point.y + 2) < Y) {
			ps.add(new Point(p1));
		}
		// 判断马儿可以走3这个位置
		if ((p1.x = point.x - 1) >= 0 && (p1.y = point.y + 2) < Y) {
			ps.add(new Point(p1));
		}
		// 判断马儿可以走4这个位置
		if ((p1.x = point.x - 2) >= 0 && (p1.y = point.y + 1) < Y) {
			ps.add(new Point(p1));
		}
		return ps;
	}

	//排序,非递减
	public static void sort(ArrayList<Point> ps) {
		ps.sort(new Comparator<Point>() {
			
			public int compare(Point o1, Point o2) {
				int count1 = next(o1).size();
				int count2 = next(o2).size();

				if (count1 < count2) {
					return -1;
				} else if (count1 == count2) {
					return 0;
				} else {
					return 1;
				}

			}

		});
	}
}

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java塑造中...

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值