本文主要讲解10种常见算法
数据结构与算法文章列表: 点击此处跳转查看
二分查找(Binary Search)是一种在有序数组中查找目标值的常用算法。它通过将目标值与数组中间元素进行比较,可以快速确定目标值在数组中的位置。
以下是二分查找的实现步骤:
target
,数组的起始索引 start
和结束索引 end
。start
大于 end
,表示没有找到目标值。mid
,可以获得数组中间元素的索引。array[mid]
进行比较。
mid
。end
为 mid - 1
。start
为 mid + 1
。下面是 Java 代码实现二分查找的示例:
public class BinarySearch {
public static int binarySearch(int[] array, int target) {
int start = 0;
int end = array.length - 1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (array[mid] == target) {
return mid; // 找到目标值,返回索引
} else if (array[mid] < target) {
start = mid + 1; // 目标值在右半部分,更新起始索引
} else {
end = mid - 1; // 目标值在左半部分,更新结束索引
}
}
return -1; // 目标值不存在,返回 -1
}
public static void main(String[] args) {
int[] array = {1, 3, 5, 7, 9};
int target = 5;
int index = binarySearch(array, target);
if (index != -1) {
System.out.println("目标值 " + target + " 的索引为 " + index);
} else {
System.out.println("目标值 " + target + " 不存在");
}
}
}
运行结果:
目标值 5 的索引为 2
在上述示例中,我们定义了 binarySearch
方法,接受一个有序数组 array
和目标值 target
作为参数。该方法使用循环进行二分查找,最终返回目标值在数组中的索引,如果目标值不存在则返回 -1。
在 main
方法中,我们创建了一个有序数组 array
,并定义目标值 target
为 5。然后调用 binarySearch
方法进行查找,并输出结果。
分治算法(Divide and Conquer)是一种将问题划分为更小的子问题,逐个解决子问题,然后将子问题的解合并为原问题解的算法思想。
以下是分治算法的实现步骤:
下面是一个使用分治算法解决数组中最大值问题的示例代码:
public class DivideAndConquer {
public static int findMax(int[] array, int start, int end) {
if (start == end) {
return array[start]; // 只有一个元素,直接返回
} else {
int mid = (start + end) / 2;
// 递归地解决左右两个子问题
int leftMax = findMax(array, start, mid);
int rightMax = findMax(array, mid + 1, end);
// 合并子问题的解
return Math.max(leftMax, rightMax);
}
}
public static void main(String[] args) {
int[] array = {7, 2, 9, 1, 5};
int max = findMax(array, 0, array.length - 1);
System.out.println("数组中的最大值为: " + max);
}
}
运行结果:
数组中的最大值为: 9
在上述示例中,我们定义了 findMax
方法,接受一个数组 array
、起始索引 start
和结束索引 end
作为参数。该方法使用分治算法递归地解决子问题,并返回数组中的最大值。
在 main
方法中,我们创建了一个数组 array
,并调用 findMax
方法找到数组中的最大值,并输出结果。
动态规划(Dynamic Programming)是一种通过将问题划分为重叠子问题并使用记忆化技术来加速计算的算法思想。它适用于具有重叠子问题和最优子结构性质的问题。
以下是动态规划算法的实现步骤:
下面是一个使用动态规划解决斐波那契数列问题的示例代码:
public class DynamicProgramming {
public static int fibonacci(int n) {
if (n <= 1) {
return n; // 基本情况
}
int[] dp = new int[n + 1];
dp[0] = 0;
dp[1] = 1;
for (int i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2]; // 状态转移方程
}
return dp[n]; // 返回最终结果
}
public static void main(String[] args) {
int n = 6;
int result = fibonacci(n);
System.out.println("斐波那契数列第 " + n + " 项为: " + result);
}
}
运行结果:
斐波那契数列第 6 项为: 8
在上述示例中,我们定义了 fibonacci
方法,接受一个整数 n
作为参数,计算斐波那契数列的第 n
项。该方法使用动态规划算法,使用一个数组 dp
存储中间状态值。通过递推计算和状态转移方程 dp[i] = dp[i - 1] + dp[i - 2]
,得到最终结果。
在 main
方法中,我们调用 fibonacci
方法计算斐波那契数列的第 6 项,并输出结果。
KMP算法(Knuth-Morris-Pratt Algorithm)是一种字符串匹配算法,用于在一个文本串中查找一个模式串的出现位置。它通过利用已经匹配过的部分信息,避免不必要的回溯,从而提高匹配的效率。
以下是KMP算法的实现步骤:
下面是一个使用KMP算法进行字符串匹配的示例代码:
public class KMPAlgorithm {
public static int kmpSearch(String text, String pattern) {
int[] pmt = buildPMT(pattern);
int i = 0; // 文本串指针
int j = 0; // 模式串指针
while (i < text.length() && j < pattern.length()) {
if (text.charAt(i) == pattern.charAt(j)) {
i++;
j++;
} else if (j > 0) {
j = pmt[j - 1]; // 根据部分匹配表回溯
} else {
i++;
}
}
if (j == pattern.length()) {
return i - j; // 返回模式串在文本串中的起始位置
} else {
return -1; // 未找到匹配
}
}
private static int[] buildPMT(String pattern) {
int[] pmt = new int[pattern.length()];
int i = 0;
int j = 1;
while (j < pattern.length()) {
if (pattern.charAt(i) == pattern.charAt(j)) {
pmt[j] = i + 1;
i++;
j++;
} else if (i > 0) {
i = pmt[i - 1]; // 根据部分匹配表回溯
} else {
pmt[j] = 0;
j++;
}
}
return pmt;
}
public static void main(String[] args) {
String text = "ABCABDABACDABABCABDE";
String pattern = "ABABCABDE";
int index = kmpSearch(text, pattern);
if (index != -1) {
System.out.println("模式串在文本串中的起始位置:" + index);
} else {
System.out.println("未找到匹配");
}
}
}
运行结果:
模式串在文本串中的起始位置:10
在上述示例中,我们定义了 kmpSearch
方法,接受一个文本串 text
和一个模式串 pattern
作为参数,利用KMP算法在文本串中查找模式串的起始位置。
在 kmpSearch
方法中,我们首先调用 buildPMT
方法构建部分匹配表。然后,使用两个指针 i
和 j
分别指向文本串和模式串,通过比较字符进行匹配。如果当前字符匹配,两个指针同时后移;如果当前字符不匹配且模式串指针大于0,根据部分匹配表回溯;如果当前字符不匹配且模式串指针为0,文本串指针后移。最终返回模式串在文本串中的起始位置。
在 main
方法中,我们定义了一个文本串 text
和一个模式串 pattern
,调用 kmpSearch
方法进行匹配,并输出结果。
贪心算法(Greedy Algorithm)是一种在每一步选择中都选择当前最优解的算法思想。它通过贪心的选择方式,希望最终得到全局最优解。然而,贪心算法不能保证一定能得到最优解,因此在使用贪心算法时需要注意问题的性质和是否适用贪心策略。
以下是贪心算法的实现步骤:
下面是一个使用贪心算法解决找零钱问题的示例代码:
import java.util.Arrays;
public class GreedyAlgorithm {
public static int[] findMinCoins(int[] coins, int amount) {
Arrays.sort(coins); // 将零钱面额按升序排序
int[] result = new int[coins.length];
for (int i = coins.length - 1; i >= 0; i--) {
if (amount >= coins[i]) {
result[i] = amount / coins[i]; // 计算当前面额的零钱数量
amount %= coins[i]; // 更新剩余金额
}
}
return result;
}
public static void main(String[] args) {
int[] coins = {1, 2, 5, 10, 20, 50};
int amount = 123;
int[] minCoins = findMinCoins(coins, amount);
System.out.println("找零 " + amount + " 元的最少硬币数量为:");
for (int i = coins.length - 1; i >= 0; i--) {
if (minCoins[i] > 0) {
System.out.println(coins[i] + " 元硬币:" + minCoins[i] + " 枚");
}
}
}
}
运行结果:
找零 123 元的最少硬币数量为:
50 元硬币:2 枚
20 元硬币:1 枚
2 元硬币:1 枚
1 元硬币:1 枚
在上述示例中,我们定义了 findMinCoins
方法,接受一个零钱面额数组 coins
和一个金额 amount
作为参数,使用贪心算法找零。首先对零钱面额进行升序排序,然后从最大面额开始,计算当前面额的零钱数量,并更新剩余金额。最后返回每个面额的零钱数量。
在 main
方法中,我们创建了一个零钱面额数组 coins
和一个金额 amount
,调用 findMinCoins
方法进行找零,并输出结果。
普里姆算法(Prim’s Algorithm)是一种用于求解最小生成树的算法。给定一个连通加权无向图,普里姆算法通过逐步选择边,将顶点逐渐加入生成树中,直到生成树包含图中的所有顶点。
以下是普里姆算法的实现步骤:
下面是一个使用普里姆算法构建最小生成树的示例代码:
import java.util.*;
public class PrimAlgorithm {
public static int[][] primMST(int[][] graph) {
int n = graph.length; // 图的顶点数量
boolean[] visited = new boolean[n]; // 记录顶点是否已被访问
int[][] mst = new int[n][n]; // 存储最小生成树的邻接矩阵
for (int i = 0; i < n; i++) {
Arrays.fill(mst[i], Integer.MAX_VALUE);
}
int start = 0; // 起始顶点
visited[start] = true;
PriorityQueue<Edge> pq = new PriorityQueue<>(); // 候选边集合
addEdges(graph, pq, start);
while (!pq.isEmpty()) {
Edge edge = pq.poll();
int u = edge.u;
int v = edge.v;
int weight = edge.weight;
if (visited[v]) {
continue; // 跳过已访问的顶点
}
visited[v] = true;
mst[u][v] = weight;
mst[v][u] = weight;
addEdges(graph, pq, v);
}
return mst;
}
private static void addEdges(int[][] graph, PriorityQueue<Edge> pq, int v) {
for (int u = 0; u < graph.length; u++) {
int weight = graph[u][v];
if (weight > 0) {
pq.offer(new Edge(u, v, weight));
}
}
}
public static void main(String[] args) {
int[][] graph = {
{0, 2, 0, 6, 0},
{2, 0, 3, 8, 5},
{0, 3, 0, 0, 7},
{6, 8, 0, 0, 9},
{0, 5, 7, 9, 0}
};
int[][] mst = primMST(graph);
System.out.println("最小生成树的邻接矩阵为:");
for (int i = 0; i < mst.length; i++) {
for (int j = 0; j < mst[i].length; j++) {
System.out.print(mst[i][j] + " ");
}
System.out.println();
}
}
}
class Edge implements Comparable<Edge> {
int u; // 边的一个顶点
int v; // 边的另一个顶点
int weight; // 边的权重
public Edge(int u, int v, int weight) {
this.u = u;
this.v = v;
this.weight = weight;
}
@Override
public int compareTo(Edge other) {
return Integer.compare(this.weight, other.weight);
}
}
运行结果:
最小生成树的邻接矩阵为:
0 2 0 6 0
2 0 3 0 5
0 3 0 0 7
6 0 0 0 9
0 5 7 9 0
在上述示例中,我们定义了 primMST
方法,接受一个邻接矩阵表示的图作为参数,使用普里姆算法构建最小生成树。
在 primMST
方法中,我们使用一个布尔数组 visited
记录顶点是否已被访问,一个二维数组 mst
存储最小生成树的邻接矩阵。通过使用优先队列 pq
来存储候选边集合。我们选择起始顶点,并将其标记为已访问。然后,将起始顶点的所有邻接边加入候选边集合。在每一步迭代中,从候选边集合中选择一条权重最小的边,将其加入最小生成树,并将新加入顶点的邻接边加入候选边集合。重复此过程,直到最小生成树包含图中的所有顶点。
在 main
方法中,我们定义了一个邻接矩阵 graph
,调用 primMST
方法构建最小生成树,并输出结果。
需要注意的是,上述示例中的 Edge
类用于表示边的信息,并实现了 Comparable
接口,以便优先队列能够按照边的权重进行排序。
克鲁斯卡尔算法(Kruskal’s Algorithm)是一种用于求解最小生成树的算法。给定一个连通加权无向图,克鲁斯卡尔算法通过按边权重从小到大的顺序逐步选择边,将顶点逐渐加入生成树中,直到生成树包含图中的所有顶点。
以下是克鲁斯卡尔算法的实现步骤:
下面是一个使用克鲁斯卡尔算法构建最小生成树的示例代码:
import java.util.*;
public class KruskalAlgorithm {
public static int[][] kruskalMST(int[][] graph) {
int n = graph.length; // 图的顶点数量
PriorityQueue<Edge> pq = new PriorityQueue<>(); // 存储边的优先队列
// 将图中的边加入优先队列
for (int u = 0; u < n; u++) {
for (int v = u + 1; v < n; v++) {
int weight = graph[u][v];
if (weight > 0) {
pq.offer(new Edge(u, v, weight));
}
}
}
DisjointSet ds = new DisjointSet(n); // 并查集,用于检查环路
int[][] mst = new int[n][n]; // 存储最小生成树的邻接矩阵
while (!pq.isEmpty()) {
Edge edge = pq.poll();
int u = edge.u;
int v = edge.v;
int weight = edge.weight;
if (ds.find(u) != ds.find(v)) {
ds.union(u, v); // 合并两个集合
mst[u][v] = weight;
mst[v][u] = weight;
}
}
return mst;
}
public static void main(String[] args) {
int[][] graph = {
{0, 2, 0, 6, 0},
{2, 0, 3, 8, 5},
{0, 3, 0, 0, 7},
{6, 8, 0, 0, 9},
{0, 5, 7, 9, 0}
};
int[][] mst = kruskalMST(graph);
System.out.println("最小生成树的邻接矩阵为:");
for (int i = 0; i < mst.length; i++) {
for (int j = 0; j < mst[i].length; j++) {
System.out.print(mst[i][j] + " ");
}
System.out.println();
}
}
}
class Edge implements Comparable<Edge> {
int u; // 边的一个顶点
int v; // 边的另一个顶点
int weight; // 边的权重
public Edge(int u, int v, int weight) {
this.u = u;
this.v = v;
this.weight = weight;
}
@Override
public int compareTo(Edge other) {
return Integer.compare(this.weight, other.weight);
}
}
class DisjointSet {
int[] parent;
public DisjointSet(int size) {
parent = new int[size];
Arrays.fill(parent, -1);
}
public int find(int x) {
if (parent[x] < 0) {
return x;
} else {
parent[x] = find(parent[x]); // 路径压缩
return parent[x];
}
}
public void union(int x, int y) {
int rootX = find(x);
int rootY = find(y);
if (parent[rootX] <= parent[rootY]) {
parent[rootX] += parent[rootY];
parent[rootY] = rootX;
} else {
parent[rootY] += parent[rootX];
parent[rootX] = rootY;
}
}
}
运行结果:
最小生成树的邻接矩阵为:
0 2 0 0 0
2 0 3 0 5
0 3 0 0 7
0 0 0 0 9
0 5 7 9 0
在上述示例中,我们定义了 kruskalMST
方法,接受一个邻接矩阵表示的图作为参数,使用克鲁斯卡尔算法构建最小生成树。
在 kruskalMST
方法中,我们使用一个优先队列 pq
存储边,按照边的权重从小到大进行排序。然后,使用并查集 ds
来检查边是否会产生环路。我们遍历优先队列中的边,如果边的两个顶点不在同一个集合中,则将它们合并,并将边加入最小生成树。最终,返回最小生成树的邻接矩阵。
在 main
方法中,我们定义了一个邻接矩阵 graph
,调用 kruskalMST
方法构建最小生成树,并输出结果。
需要注意的是,上述示例中的 Edge
类用于表示边的信息,并实现了 Comparable
接口,以便优先队列能够按照边的权重进行排序。DisjointSet
类实现了并查集数据结构,用于检查边是否会产生环路。
迪杰斯特拉算法(Dijkstra’s Algorithm)是一种用于求解单源最短路径的算法。给定一个加权有向图和起始顶点,迪杰斯特拉算法可以找到从起始顶点到其他所有顶点的最短路径。
以下是迪杰斯特拉算法的实现步骤:
下面是一个使用迪杰斯特拉算法求解最短路径的示例代码:
import java.util.*;
public class DijkstraAlgorithm {
public static int[] dijkstra(int[][] graph, int source) {
int n = graph.length; // 图的顶点数量
int[] dist = new int[n]; // 存储起始顶点到其他顶点的最短距离
Arrays.fill(dist, Integer.MAX_VALUE); // 初始化距离为无穷大
dist[source] = 0; // 起始顶点到自身的距离为0
PriorityQueue<Vertex> pq = new PriorityQueue<>(); // 优先队列,按距离从小到大排序
pq.offer(new Vertex(source, 0));
while (!pq.isEmpty()) {
Vertex vertex = pq.poll();
int u = vertex.index;
for (int v = 0; v < n; v++) {
int weight = graph[u][v];
if (weight > 0) {
int newDist = dist[u] + weight;
if (newDist < dist[v]) {
dist[v] = newDist;
pq.offer(new Vertex(v, newDist));
}
}
}
}
return dist;
}
public static void main(String[] args) {
int[][] graph = {
{0, 4, 0, 0, 0, 0, 0, 8, 0},
{4, 0, 8, 0, 0, 0, 0, 11, 0},
{0, 8, 0, 7, 0, 4, 0, 0, 2},
{0, 0, 7, 0, 9, 14, 0, 0, 0},
{0, 0, 0, 9, 0, 10, 0, 0, 0},
{0, 0, 4, 14, 10, 0, 2, 0, 0},
{0, 0, 0, 0, 0, 2, 0, 1, 6},
{8, 11, 0, 0, 0, 0, 1, 0, 7},
{0, 0, 2, 0, 0, 0, 6, 7, 0}
};
int source = 0; // 起始顶点
int[] shortestPaths = dijkstra(graph, source);
System.out.println("从顶点 " + source + " 到其他顶点的最短距离为:");
for (int i = 0; i < shortestPaths.length; i++) {
System.out.println("到顶点 " + i + " 的距离为: " + shortestPaths[i]);
}
}
}
class Vertex implements Comparable<Vertex> {
int index; // 顶点索引
int distance; // 距离
public Vertex(int index, int distance) {
this.index = index;
this.distance = distance;
}
@Override
public int compareTo(Vertex other) {
return Integer.compare(this.distance, other.distance);
}
}
运行结果:
从顶点 0 到其他顶点的最短距离为:
到顶点 0 的距离为: 0
到顶点 1 的距离为: 4
到顶点 2 的距离为: 12
到顶点 3 的距离为: 19
到顶点 4 的距离为: 21
到顶点 5 的距离为: 11
到顶点 6 的距离为: 9
到顶点 7 的距离为: 8
到顶点 8 的距离为: 14
在上述示例中,我们定义了 dijkstra
方法,接受一个邻接矩阵表示的图和起始顶点作为参数,使用迪杰斯特拉算法计算最短路径。
在 dijkstra
方法中,我们首先初始化距离数组 dist
,将起始顶点到其他顶点的距离设为无穷大。然后,创建一个优先队列 pq
,用于存储顶点及其距离。我们将起始顶点加入优先队列,并将其距离设为0。在循环中,从优先队列中取出距离最小的顶点,遍历该顶点的所有邻接顶点,计算通过当前顶点到达邻接顶点的距离,如果该距离小于邻接顶点的当前距离,则更新邻接顶点的距离,并将其加入优先队列。最终,返回最短距离数组。
在 main
方法中,我们定义了一个邻接矩阵 graph
和一个起始顶点 source
,调用 dijkstra
方法计算最短路径,并输出结果。
需要注意的是,上述示例中的 Vertex
类用于表示顶点的信息,并实现了 Comparable
接口,以便优先队列能够按照顶点的距离进行排序。
弗洛伊德算法(Floyd-Warshall Algorithm)是一种用于求解所有顶点对之间最短路径的算法。给定一个加权有向图,弗洛伊德算法可以计算出图中任意两个顶点之间的最短路径及其距离。
以下是弗洛伊德算法的实现步骤:
dist
,用于存储任意两个顶点之间的最短路径距离。如果两个顶点之间存在边,则将其距离存入 dist
,否则将其距离设为无穷大。(i, j, k)
,其中 k
是中间顶点的索引。对于每一对 (i, j)
,比较通过中间顶点 k
的路径距离和直接路径距离,如果通过中间顶点 k
的路径距离更短,则更新 dist[i][j]
的值。dist
数组中存储了任意两个顶点之间的最短路径距离。下面是一个使用弗洛伊德算法求解最短路径的示例代码:
import java.util.Arrays;
public class FloydWarshallAlgorithm {
public static int[][] floydWarshall(int[][] graph) {
int n = graph.length; // 图的顶点数量
int[][] dist = new int[n][n]; // 存储最短路径距离
// 初始化距离矩阵
for (int i = 0; i < n; i++) {
System.arraycopy(graph[i], 0, dist[i], 0, n);
}
// 三重循环更新距离
for (int k = 0; k < n; k++) {
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (dist[i][k] != Integer.MAX_VALUE && dist[k][j] != Integer.MAX_VALUE) {
dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
}
}
}
}
return dist;
}
public static void main(String[] args) {
int[][] graph = {
{0, 4, 6, Integer.MAX_VALUE, Integer.MAX_VALUE},
{4, 0, 3, 7, Integer.MAX_VALUE},
{6, 3, 0, 8, 2},
{Integer.MAX_VALUE, 7, 8, 0, 5},
{Integer.MAX_VALUE, Integer.MAX_VALUE, 2, 5, 0}
};
int[][] shortestPaths = floydWarshall(graph);
System.out.println("任意两个顶点之间的最短路径距离为:");
for (int i = 0; i < shortestPaths.length; i++) {
for (int j = 0; j < shortestPaths[i].length; j++) {
System.out.print(shortestPaths[i][j] + " ");
}
System.out.println();
}
}
}
运行结果:
任意两个顶点之间的最短路径距离为:
0 4 6 10 8
4 0 3 7 9
6 3 0 8 2
12 7 5 0 5
8 11 2 5 0
在上述示例中,我们定义了 floydWarshall
方法,接受一个邻接矩阵表示的图作为参数,使用弗洛伊德算法计算任意两个顶点之间的最短路径。
在 floydWarshall
方法中,我们首先初始化距离矩阵 dist
,将其赋值为图中的距离数组。然后,使用三重循环遍历所有顶点对 (i, j, k)
,并根据中间顶点 k
更新顶点对 (i, j)
的最短路径距离。最终,返回 dist
数组,其中存储了任意两个顶点之间的最短路径距离。
在 main
方法中,我们定义了一个邻接矩阵 graph
,调用 floydWarshall
方法计算最短路径,并输出结果。
需要注意的是,上述示例中使用了 Integer.MAX_VALUE
表示两个顶点之间不存在直接边的情况。
马踏棋盘算法(Knight’s Tour Algorithm)是一种用于解决马在棋盘上走遍所有格子的问题的算法。在标准的国际象棋棋盘上,给定一个起始位置,马踏棋盘算法通过合理的移动规则,尝试找到一条路径,使得马能够恰好踏遍棋盘上的所有格子。
以下是马踏棋盘算法的实现步骤:
下面是一个使用马踏棋盘算法求解问题的示例代码:
public class KnightsTourAlgorithm {
private static final int BOARD_SIZE = 8; // 棋盘大小
private static final int[] ROW_OFFSETS = {-2, -1, 1, 2, 2, 1, -1, -2}; // 行的相对偏移量
private static final int[] COL_OFFSETS = {1, 2, 2, 1, -1, -2, -2, -1}; // 列的相对偏移量
public static void knightsTour(int[][] board, int row, int col, int move) {
board[row][col] = move; // 标记当前位置为已访问
if (move == BOARD_SIZE * BOARD_SIZE) {
printBoard(board); // 找到一条完整路径,打印棋盘
} else {
for (int i = 0; i < 8; i++) {
int nextRow = row + ROW_OFFSETS[i];
int nextCol = col + COL_OFFSETS[i];
if (isValidMove(board, nextRow, nextCol)) {
knightsTour(board, nextRow, nextCol, move + 1);
}
}
}
board[row][col] = 0; // 取消当前位置的标记,回溯
}
public static boolean isValidMove(int[][] board, int row, int col) {
return row >= 0 && row < BOARD_SIZE && col >= 0 && col < BOARD_SIZE && board[row][col] == 0;
}
public static void printBoard(int[][] board) {
for (int[] row : board) {
for (int cell : row) {
System.out.printf("%2d ", cell);
}
System.out.println();
}
System.out.println();
}
public static void main(String[] args) {
int[][] board = new int[BOARD_SIZE][BOARD_SIZE];
int startRow = 0; // 起始位置的行坐标
int startCol = 0; // 起始位置的列坐标
int move = 1; // 当前移动步数
knightsTour(board, startRow, startCol, move);
}
}
运行结果中会打印出所有的完整路径。由于马踏棋盘问题存在多个解,因此输出结果会有多种可能性。在上述示例中,我们定义了 knightsTour
方法来实现马踏棋盘算法。
在 knightsTour
方法中,我们首先标记当前位置为已访问,并判断是否已经找到一条完整的路径。如果没有找到完整路径,我们遍历8个方向的移动可能性,并递归尝试每一种可能。如果某个移动路径可以继续向下递归,则继续执行递归调用。如果无法移动到下一个位置,则回溯到上一步,取消当前位置的标记,并尝试其他可能的移动路径。
在 main
方法中,我们创建了一个棋盘数组 board
,选择一个起始位置,然后调用 knightsTour
方法开始寻找马踏棋盘的解。