目录
标题:《Java 算法宝典:探秘从排序到回溯的奇妙世界》
摘要: 本文将深入探讨 Java 中的各种基本算法,包括排序、查找、递归、动态规划、图算法、贪心算法、分治算法和回溯算法。通过详细的解释、有趣的例子和可运行的 Java 代码片段,帮助读者轻松掌握这些算法的实现逻辑。无论你是 Java 新手还是经验丰富的开发者,都能从本文中获得宝贵的知识和实用的技巧,提升编程能力。
关键词:Java、算法、排序、查找、递归、动态规划、图算法、贪心算法、分治算法、回溯算法
一、排序算法
1、冒泡排序
- 原理:重复遍历要排序的数列,比较每对相邻元素的大小,若顺序错误则交换它们的位置。
- 例子:假设有一组数字 [5, 3, 8, 4, 2],首先比较 5 和 3,交换位置得到 [3, 5, 8, 4, 2],接着比较 5 和 8,不交换,再比较 8 和 4,交换得到 [3, 5, 4, 8, 2],继续比较 8 和 2,交换得到 [3, 5, 4, 2, 8]。这是第一遍遍历的结果,后面继续重复这个过程,直到整个数列有序。
- Java 代码:
public class BubbleSort {
public static void bubbleSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// 交换 arr[j] 和 arr[j + 1]
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
}
2、选择排序
- 原理:首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然后从剩余未排序元素中继续找最小(大)元素,放到已排序序列的末尾。
- 例子:对于 [5, 3, 8, 4, 2],首先找到最小元素 2,放到第一位得到 [2, 3, 8, 4, 5],然后在剩余元素 [3, 8, 4, 5] 中找到最小元素 3,放到第二位得到 [2, 3, 8, 4, 5],以此类推。
- Java 代码:
public class SelectionSort {
public static void selectionSort(int[] arr) {
int n = arr.length;
for (int i = 0; i < n - 1; i++) {
int minIndex = i;
for (int j = i + 1; j < n; j++) {
if (arr[j] < arr[minIndex]) {
minIndex = j;
}
}
// 交换 arr[i] 和 arr[minIndex]
int temp = arr[i];
arr[i] = arr[minIndex];
arr[minIndex] = temp;
}
}
}
3、插入排序
- 原理:构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
- 例子:以 [5, 3, 8, 4, 2] 为例,首先将 5 视为有序序列,然后处理 3,将 3 插入到 5 前面得到 [3, 5, 8, 4, 2],接着处理 8,保持不变得到 [3, 5, 8, 4, 2],再处理 4,将 4 插入到 3 和 5 之间得到 [3, 4, 5, 8, 2],最后处理 2,将 2 插入到最前面得到 [2, 3, 4, 5, 8]。
- Java 代码:
public class InsertionSort {
public static void insertionSort(int[] arr) {
int n = arr.length;
for (int i = 1; i < n; i++) {
int key = arr[i];
int j = i - 1;
while (j >= 0 && arr[j] > key) {
arr[j + 1] = arr[j];
j--;
}
arr[j + 1] = key;
}
}
}
4、快速排序
- 原理:通过一个基准值将数据分为两部分,一部分数据比基准值小,另一部分数据比基准值大,然后递归地在这两部分数据上重复这个过程。
- 例子:对于 [5, 3, 8, 4, 2],选择第一个元素 5 作为基准值,经过一次划分后得到 [3, 4, 2] 和 [8],然后分别对这两部分继续进行快速排序。
- Java 代码:
public class QuickSort {
public static void quickSort(int[] arr, int low, int high) {
if (low < high) {
int pi = partition(arr, low, high);
quickSort(arr, low, pi - 1);
quickSort(arr, pi + 1, high);
}
}
private static int partition(int[] arr, int low, int high) {
int pivot = arr[high];
int i = low - 1;
for (int j = low; j < high; j++) {
if (arr[j] < pivot) {
i++;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
int temp = arr[i + 1];
arr[i + 1] = arr[high];
arr[high] = temp;
return i + 1;
}
}
5、归并排序
- 原理:采用分治法,将已有序的序列合并成一个新的有序序列。
- 例子:对于 [5, 3, 8, 4, 2],首先将其分为 [5, 3] 和 [8, 4, 2],然后分别对这两部分进行归并排序,得到 [3, 5] 和 [2, 4, 8],最后将这两个有序序列合并得到 [2, 3, 4, 5, 8]。
- Java 代码:
public class MergeSort {
public static void mergeSort(int[] arr) {
if (arr.length > 1) {
int mid = arr.length / 2;
int[] left = new int[mid];
int[] right = new int[arr.length - mid];
System.arraycopy(arr, 0, left, 0, mid);
System.arraycopy(arr, mid, right, 0, arr.length - mid);
mergeSort(left);
mergeSort(right);
merge(arr, left, right);
}
}
private static void merge(int[] arr, int[] left, int[] right) {
int i = 0, j = 0, k = 0;
while (i < left.length && j < right.length) {
if (left[i] < right[j]) {
arr[k++] = left[i++];
} else {
arr[k++] = right[j++];
}
}
while (i < left.length) {
arr[k++] = left[i++];
}
while (j < right.length) {
arr[k++] = right[j++];
}
}
}
二、查找算法
1、线性查找
- 原理:从数组的一端开始,逐个检查数组的每个元素,直到找到所需的值。
- 例子:在 [5, 3, 8, 4, 2] 中查找数字 4,从第一个元素 5 开始,依次比较,直到找到 4。
- Java 代码:
public class LinearSearch {
public static int linearSearch(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1;
}
}
2、二分查找
- 原理:在有序数组中查找特定元素,通过比较数组中间的元素来确定所需元素是否在数组的哪一半,然后根据比较结果缩小搜索范围,直到找到元素或范围为空。
- 例子:在 [2, 3, 4, 5, 8] 中查找数字 4,首先比较中间元素 5,发现 4 比 5 小,所以在左边一半继续查找,中间元素是 3,发现 4 比 3 大,所以在右边一半继续查找,中间元素正好是 4,找到目标。
- Java 代码:
public class BinarySearch {
public static int binarySearch(int[] arr, int target) {
int low = 0;
int high = arr.length - 1;
while (low <= high) {
int mid = low + (high - low) / 2;
if (arr[mid] == target) {
return mid;
} else if (arr[mid] < target) {
low = mid + 1;
} else {
high = mid - 1;
}
}
return -1;
}
}
三、递归算法
原理:递归是一种在问题解决过程中自我调用的算法。它将问题分解为更小的子问题,直到达到基本情况(base case),然后逐步解决这些子问题,最终解决原始问题。
例子:计算阶乘 n!,可以用递归的方式定义为 n! = n * (n - 1)!,当 n = 0 或 1 时,基本情况为 1。
Java 代码:
java
Copy
public class RecursionExample {
public static int factorial(int n) {
if (n == 0 || n == 1) {
return 1;
} else {
return n * factorial(n - 1);
}
}
}
四、动态规划
- 原理:动态规划是一种将复杂问题分解为更小的子问题,并存储这些子问题的解(通常是在表格中),以避免重复计算的算法。它通常用于求解具有重叠子问题和最优子结构特性的问题。
- 例子:计算斐波那契数列的第 n 项,可以用动态规划的方法避免重复计算。定义状态 dp [i] 表示斐波那契数列的第 i 项,状态转移方程为 dp [i] = dp [i - 1] + dp [i - 2]。
- Java 代码:
public class DynamicProgrammingExample {
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];
}
}
标题:《Java 算法奇妙世界:从图算法到回溯,解锁编程新境界》
摘要: 本文将深入探讨 Java 中的基本算法,包括图算法(深度优先搜索 DFS 和广度优先搜索 BFS)、贪心算法、分治算法以及回溯算法。通过详细的解释、有趣的例子和可运行的 Java 代码片段,帮助读者轻松理解这些算法的实现逻辑。无论你是 Java 新手还是经验丰富的开发者,都能从本文中获得宝贵的知识,提升编程技能。快来一起探索 Java 算法的奇妙世界吧!
关键词:Java 算法、图算法、深度优先搜索、广度优先搜索、贪心算法、分治算法、回溯算法
五、图算法
1. 深度优先搜索(DFS)
- 原理:从图的某个顶点开始,尽可能深地搜索图的顶点,直到达到一个顶点没有未被访问的邻接顶点,然后回溯到上一个顶点继续搜索。
- 例子:想象你在一个神秘的迷宫中,你的任务是找到出口。你从一个入口开始,沿着一条路径一直走,直到走到死胡同或者已经没有未探索的方向。这时,你就回溯到上一个岔路口,选择另一条路继续探索。这个过程就类似于深度优先搜索。
- Java 代码:
import java.util.ArrayList;
import java.util.List;
class Graph {
private int V;
private List<List<Integer>> adjList;
Graph(int v) {
V = v;
adjList = new ArrayList<>();
for (int i = 0; i < v; i++) {
adjList.add(new ArrayList<>());
}
}
void addEdge(int v, int w) {
adjList.get(v).add(w);
}
void DFS(int startVertex) {
boolean[] visited = new boolean[V];
DFSUtil(startVertex, visited);
}
private void DFSUtil(int v, boolean[] visited) {
visited[v] = true;
System.out.print(v + " ");
List<Integer> neighbors = adjList.get(v);
for (Integer neighbor : neighbors) {
if (!visited[neighbor]) {
DFSUtil(neighbor, visited);
}
}
}
}
2. 广度优先搜索(BFS)
- 原理:从图的某个顶点开始,逐层遍历图的顶点,使用队列来记录待访问的顶点。
- 例子:假设你在一个花园中,要找到一朵特定的花。你从一个起点开始,先检查离起点最近的区域,然后再逐步扩大范围。每次检查完一个区域后,将其周围未检查的区域放入队列中,等待下一轮检查。这个过程就像是广度优先搜索。
- Java 代码:
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
class Graph {
private int V;
private List<List<Integer>> adjList;
Graph(int v) {
V = v;
adjList = new ArrayList<>();
for (int i = 0; i < v; i++) {
adjList.add(new ArrayList<>());
}
}
void addEdge(int v, int w) {
adjList.get(v).add(w);
}
void BFS(int startVertex) {
boolean[] visited = new boolean[V];
Queue<Integer> queue = new LinkedList<>();
visited[startVertex] = true;
queue.add(startVertex);
while (!queue.isEmpty()) {
int currentVertex = queue.poll();
System.out.print(currentVertex + " ");
List<Integer> neighbors = adjList.get(currentVertex);
for (Integer neighbor : neighbors) {
if (!visited[neighbor]) {
visited[neighbor] = true;
queue.add(neighbor);
}
}
}
}
}
六、贪心算法
- 原理:贪心算法是一种在每一步选择中都采取在当前状态下最好或最优的选择,从而希望导致结果是全局最好或最优的算法。
- 例子:想象你在一个超市购物,你有一个预算,并且想要购买尽可能多的商品。你可以选择价格最低的商品,每次购买一个,直到你的预算用完。这种策略就是贪心算法,虽然不能保证得到全局最优解,但在很多情况下可以得到一个较好的结果。
- Java 代码:
import java.util.Arrays;
import java.util.Comparator;
class Item {
int value;
int weight;
Item(int value, int weight) {
this.value = value;
this.weight = weight;
}
}
class GreedyAlgorithmExample {
public static double fractionalKnapsack(Item[] items, int capacity) {
// 按照价值/重量比进行排序
Arrays.sort(items, Comparator.comparingDouble(i -> (double) i.value / i.weight));
double totalValue = 0;
for (Item item : items) {
if (capacity >= item.weight) {
totalValue += item.value;
capacity -= item.weight;
} else {
totalValue += (double) capacity / item.weight * item.value;
break;
}
}
return totalValue;
}
}
七、分治算法
- 原理:分治算法是一种将问题分解成多个小问题,递归解决小问题,然后合并结果以解决原来的问题的方法。
- 例子:想象你要计算一个大型图书馆中所有书籍的总页数。你可以将图书馆分成几个区域,分别计算每个区域的书籍总页数,然后将这些结果合并起来得到整个图书馆的总页数。
- Java 代码:
public class DivideAndConquerExample {
public static int sum(int[] arr, int low, int high) {
if (low == high) {
return arr[low];
}
int mid = low + (high - low) / 2;
int leftSum = sum(arr, low, mid);
int rightSum = sum(arr, mid + 1, high);
return leftSum + rightSum;
}
}
八、回溯算法
- 原理:回溯算法是一种通过试错的方式尝试分步解决问题的算法。如果某一步不满足要求,它会回退到上一步,尝试另一种可能的选择。
- 例子:想象你在玩一个数独游戏。你从一个空的格子开始,尝试填入一个数字。如果填入的数字导致矛盾,你就回退到上一个格子,尝试另一个数字。这个过程就是回溯算法。
- Java 代码:
public class SudokuSolver {
public static boolean solveSudoku(char[][] board) {
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (board[i][j] == '.') {
for (char k = '1'; k <= '9'; k++) {
if (isValid(board, i, j, k)) {
board[i][j] = k;
if (solveSudoku(board)) {
return true;
} else {
board[i][j] = '.';
}
}
}
return false;
}
}
}
return true;
}
private static boolean isValid(char[][] board, int row, int col, char num) {
for (int i = 0; i < 9; i++) {
if (board[row][i] == num || board[i][col] == num || board[row / 3 * 3 + i / 3][col / 3 * 3 + i % 3] == num) {
return false;
}
}
return true;
}
}
嘿,小伙伴们!看完了这篇博客,是不是对 Java 中的这些基本算法有了更深入的理解呢?快来评论区分享你在使用这些算法时的经验和心得吧!让我们一起在编程的海洋中畅游,共同进步!
标签:arr,Java,int,++,算法,探秘,public From: https://blog.csdn.net/u010425839/article/details/143275301