【数据结构与算法】《Java 算法宝典:探秘从排序到回溯的奇妙世界》

news2025/1/16 20:14:15

在这里插入图片描述

目录

  • 标题:《Java 算法宝典:探秘从排序到回溯的奇妙世界》
  • 一、排序算法
    • 1、冒泡排序
    • 2、选择排序
    • 3、插入排序
    • 4、快速排序
    • 5、归并排序
  • 二、查找算法
    • 1、线性查找
    • 2、二分查找
  • 三、递归算法
  • 四、动态规划
  • 五、图算法
    • 1. 深度优先搜索(DFS)
    • 2. 广度优先搜索(BFS)
  • 六、贪心算法
  • 七、分治算法
  • 八、回溯算法

标题:《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 中的这些基本算法有了更深入的理解呢?快来评论区分享你在使用这些算法时的经验和心得吧!让我们一起在编程的海洋中畅游,共同进步!😎

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2225236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux系统编程】——Linux入门指南:从零开始掌握操作系统的核心(指令篇)

文章目录 查看 Linux 主机 ip以及登录主机Linux基础文件操作指令man&#xff1a;查看命令的手册页&#xff0c;了解命令的详细用法。pwd&#xff1a;显示当前目录路径。cd&#xff1a;切换目录。ls&#xff1a;列出当前目录下的文件和文件夹。mkdir&#xff1a;创建新目录。 文…

ArrayList和Array、LinkedList、Vector 间的区别

一、ArrayList 和 Array 的区别 ArrayList 内部基于动态数组实现&#xff0c;比 Array&#xff08;静态数组&#xff09; 使用起来更加灵活&#xff1a; ArrayList 会根据实际存储的元素动态地扩容或缩容&#xff0c;而 Array 被创建之后就不能改变它的长度了。ArrayList 允许…

el-table相关的功能实现

1. 表格嵌套表格时&#xff0c;隐藏父表格的全选框 场景&#xff1a;当table表格设置复选&#xff08;多选&#xff09;功能时&#xff0c;如何隐藏表头的复选框&#xff0c;不让用户一键多选。 <el-table :header-cell-class-name"cellClass">// 表头复选框禁…

102. 管道漫游案例

通过一个轨迹线生成一个管道几何体&#xff0c;然后相机沿着该轨迹线移动&#xff0c;注意相机的方向要沿着轨迹线的切线方向&#xff0c;这样会形成一个管道漫游的效果。 管道几何体TubeGeometry、纹理贴图相机对象Camera的.position属性和.lookAt()方法 管道模型 课件源码“…

动态规划算法专题(九):完全背包问题

目录 1. 【模板】完全背包 1.1 算法原理 1.2 算法代码 1.3 空间优化 1.4 空间优化版本代码 2. 零钱兑换 2.1 算法原理 2.2 算法代码 3. 零钱兑换 II 3.1 算法原理 3.2 算法代码 4. 完全平方数 4.1 算法原理 4.2 算法代码 完全背包问题的初始化与 01 背包的初…

电动汽车与软件定义汽车(SDV)时代的汽车行业变革

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

LeetCode437. 路径总和 III(2024秋季每日一题 50)

给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点到子节点&am…

.NET Core WebApi第3讲:第一个Web Api项目

一、.NEt Core 1、运行模板项目 1&#xff09;仍然有controllers&#xff0c;说明WebApi是基于MVC模式的&#xff0c;只是对比之下这里没有MVC中的views。 因为WebApi只会向前台发送数据&#xff0c;不会向前台发送HTML页面。 2、验证模板项目的api 1&#xff09;法1&#xf…

第12次CCF CSP认证真题解

1、最小差值 题目链接&#xff1a;https://sim.csp.thusaac.com/contest/12/problem/0 100分代码&#xff1a; #include <iostream> #include <algorithm> using namespace std; int main(int argc, char *argv[]) {int n;cin >> n;int a[1010],b[1010];f…

【模型学习】

https://zhuanlan.zhihu.com/p/522344841 from transformers import AutoTokenizer tokenizer AutoTokenizer.from_pretrained(model_checkpoint) tokenizer("男女主角亦有专属声优这一模式是由谁改编的&#xff1f;", "任天堂游戏谜之村雨城") { input_…

数通自学——计算机网络基础知识IP地址、局域网、广域网、NAT、端口映射、子网掩码、网关、IPV4、IPV6

计算机网络基础知识IP地址、局域网、广域网、NAT、端口映射、子网掩码、网关、IPV4、IPV6 一、IP地址1、概念引入2、概念3、组成及分类 二、局域网和广域网1、局域网2、广域网 三、NAT与端口映射四、公网IP、私网IP五、IPV4与IPV6 一、IP地址 1、概念引入 现在思考一个问题&a…

IntelliJ IDEA 查看类class的结构Structure轮廓outline窗口, 快捷键是Alt+7

IntelliJ IDEA 查看类class的结构Structure轮廓outline窗口, 快捷键是Alt7 idea的结构Structure窗口相当于Eclipse的outline 快捷键是: Alt7 或者点击左上角主菜单面包屑,打开主菜单 然后菜单找到-视图&#xff08;View&#xff09;→ 工具窗口&#xff08;Tool Windows&…

鸿蒙开发--点击下拉菜单,同时最下面出现遮罩层的实现方法

效果展示 实现 除去最上面的Naviation标题&#xff08;房源列表&#xff09;&#xff0c;该页面有两个SearchFilter搜索筛选&#xff08;包括其中的下拉菜单&#xff09;&#xff0c;RoomList房源列表 根目录容器 显然&#xff0c;两个组件之间存在覆盖关系&#xff0c;所以…

【密码学】全同态加密张量运算库解读 —— TenSEAL

项目地址&#xff1a;https://github.com/OpenMined/TenSEAL 论文地址&#xff1a;https://arxiv.org/pdf/2104.03152v2 TenSEAL 是一个在微软 SEAL 基础上构建的用于对张量进行同态加密操作的开源Python库&#xff0c;用于在保持数据加密的状态下进行机器学习和数据分析。 Ten…

ssm旅游网页开发与设计+jsp

系统包含&#xff1a;源码论文 所用技术&#xff1a;SpringBootVueSSMMybatisMysql 免费提供给大家参考或者学习&#xff0c;获取源码请私聊我 需要定制请私聊 目 录 摘 要 I 目 录 III 第1章 绪论 1 1.1 研究背景 1 1.2目的和意义 1 1.3 论文研究内容 1 第2章 程序…

银河麒麟V10系统下libopenblas.so.0和libllmlmf库的安装

1、当前linux服务器系统是银河麒麟V10&#xff0c;具体的内核和cpu型号如下&#xff1a; 2、使用:uname -a来进行查询 Linux localhost.localdomain 4.19.90-89.16.v2401.ky10.x86_64 #1 SMP Sat Sep 14 13:09:47 CST 2024 x86_64 x86_64 x86_64 GNU/Linux 3、在部署QT开发的应…

vue通过JSON文件生成KML文件源码

可以使用封装的json解析器进行JSON数据获取&#xff0c;读取点的经度、维度、高程等数据&#xff0c;再使用对应的KML文件生成函数使用该源码下载KML文件&#xff08;固定KML生成&#xff1a;js模板式生成大疆上云kml文件&#xff08;含详细注释&#xff0c;已封装成函数&#…

从病理AI的基础模型发展历程,看未来的医学AI发展趋势|个人观点·24-10-23

小罗碎碎念 在临床相关的人工智能&#xff08;AI&#xff09;模型发展方面&#xff0c;传统上需要大量标注数据集&#xff0c;这使得AI的进步主要围绕大型中心和私营企业展开。所以&#xff0c;在这期推文中&#xff0c;我会介绍一些已经商用的模型&#xff0c;并且为计划进军…

Minio文件服务器:SpringBoot实现文件上传

在Minio文件服务器部署成功后(参考上篇文章Minio文件服务器&#xff1a;安装)接下来我们通过SpringBoot框架写一个接口&#xff0c;来实现文件的上传功能&#xff1a;文件通过SpringBoot接口&#xff0c;上传到Minio文件服务器。并且&#xff0c;如果上传的文件是图片类型&…

裴蜀定理与欧几里得算法——蓝桥杯真题中的应用

目录 裴蜀定理&#xff08;Bzouts Theorem&#xff09;1、定义2、推论3、欧几里得算法4、多个整数的裴蜀定理扩展 真题挑战解题思路代码实现与详细注释代码解析 裴蜀定理&#xff08;Bzout’s Theorem&#xff09; 1、定义 对于任意两个整数 a 和 b &#xff0c;如果它们的最…