掌握排序艺术:Java 中常见排序算法的深度解析与实战

news2024/12/26 19:15:53

排序是计算机科学中的一个基本问题,它在数据处理、搜索和分析中扮演着重要角色。Java提供了多种内置的排序方法,但了解不同排序算法的工作原理及其优缺点对于优化性能和选择合适的解决方案至关重要。本文将详细介绍几种常见的排序算法,包括它们的基本原理、带有详细中文注释的Java代码实现以及使用时需要注意的事项。

1. 冒泡排序 (Bubble Sort)

原理

冒泡排序是一种简单的排序算法,它重复地遍历要排序的列表,比较相邻的元素并根据需要交换它们的位置。这个过程会使得每次遍历后最大的未排序元素“冒泡”到列表的末尾。

代码案例

public static void bubbleSort(int[] arr) {
    int n = arr.length; // 获取数组长度
    for (int i = 0; i < n - 1; i++) { // 外层循环控制遍历次数
        for (int j = 0; j < n - 1 - i; j++) { // 内层循环进行相邻元素比较
            if (arr[j] > arr[j + 1]) { // 如果前一个元素大于后一个元素
                // 交换 arr[j] 和 arr[j+1]
                int temp = arr[j]; // 临时存储 arr[j]
                arr[j] = arr[j + 1]; // 将 arr[j+1] 的值赋给 arr[j]
                arr[j + 1] = temp; // 将 temp 的值赋给 arr[j+1]
            }
        }
    }
}

注意事项

  • 冒泡排序的时间复杂度为O(n^2),在大数据集上效率较低。
  • 适合小规模或几乎已排序的数据集。

优缺点

  • 优点:实现简单,易于理解。
  • 缺点:效率低,特别是当数据量较大时。

2. 选择排序 (Selection Sort)

原理

选择排序通过不断选择剩余元素中的最小值,并将其放置在已排序部分的末尾来工作。该算法分为两部分:已排序部分和未排序部分。

代码案例

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[i] = arr[minIndex]; // 将最小值放到已排序部分
        arr[minIndex] = temp; // 将原位置的值放到空位
    }
}

注意事项

  • 时间复杂度同样为O(n^2),不适合大规模数据。
  • 算法稳定,但效率不高。

优缺点

  • 优点:实现简单,不需要额外空间。
  • 缺点:时间复杂度高,效率低下。

3. 插入排序 (Insertion Sort)

原理

插入排序通过构建有序序列,对未排序数据进行扫描,找到合适位置并插入。类似于人们整理扑克牌的过程。

代码案例

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; // 插入当前元素
    }
}

注意事项

  • 最好情况下的时间复杂度为O(n),平均和最坏情况下为O(n^2)。
  • 对于小规模数据或部分有序的数据效果较好。

优缺点

  • 优点:实现简单,适用于小规模数据。
  • 缺点:效率低于其他高级排序算法。

4. 快速排序 (Quick Sort)

原理

快速排序采用分治策略,选择一个基准元素,将数组分成两部分,一部分都比基准小,另一部分都比基准大。然后递归地对这两部分进行排序。

代码案例

public static void quickSort(int[] arr, int low, int high) {
    if (low < high) { // 只有当左边界小于右边界时才继续
        int pivotIndex = partition(arr, low, high); // 分割数组
        quickSort(arr, low, pivotIndex - 1); // 递归排序左子数组
        quickSort(arr, pivotIndex + 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++;
            // 交换 arr[i] 和 arr[j]
            int temp = arr[i];
            arr[i] = arr[j];
            arr[j] = temp;
        }
    }
    // 交换 arr[i+1] 和 arr[high] (pivot)
    int temp = arr[i + 1];
    arr[i + 1] = arr[high];
    arr[high] = temp;
    return i + 1; // 返回基准的最终位置
}

注意事项

  • 平均时间复杂度为O(n log n),但在最坏情况下(如已经排序的数组)可能退化为O(n^2)。
  • 选择合适的基准可以提高性能。

优缺点

  • 优点:平均情况下非常高效,适用于大规模数据。
  • 缺点:不稳定排序,最坏情况下效率较低。

5. 归并排序 (Merge Sort)

原理

归并排序也是一种分治算法,它将数组分成两个子数组,分别对它们进行排序,然后再将结果合并成一个有序数组。

代码案例

public static void mergeSort(int[] arr, int left, int right) {
    if (left < right) { // 只有当左边界小于右边界时才继续
        int mid = (left + right) / 2; // 计算中间位置
        mergeSort(arr, left, mid); // 递归排序左半部分
        mergeSort(arr, mid + 1, right); // 递归排序右半部分
        merge(arr, left, mid, right); // 合并两个有序数组
    }
}

private static void merge(int[] arr, int left, int mid, int right) {
    int n1 = mid - left + 1; // 左半部分的长度
    int n2 = right - mid; // 右半部分的长度

    int[] L = new int[n1]; // 创建左半部分的临时数组
    int[] R = new int[n2]; // 创建右半部分的临时数组

    for (int i = 0; i < n1; i++)
        L[i] = arr[left + i]; // 复制数据到左半部分
    for (int j = 0; j < n2; j++)
        R[j] = arr[mid + 1 + j]; // 复制数据到右半部分

    int i = 0, j = 0; // 初始化指针
    int k = left; // 初始化结果数组的起始位置
    while (i < n1 && j < n2) { // 合并两个有序数组
        if (L[i] <= R[j]) { // 如果左半部分的元素较小
            arr[k] = L[i]; // 将左半部分的元素放入结果数组
            i++;
        } else { // 如果右半部分的元素较小
            arr[k] = R[j]; // 将右半部分的元素放入结果数组
            j++;
        }
        k++; // 移动结果数组的指针
    }

    while (i < n1) { // 如果左半部分还有剩余元素
        arr[k] = L[i];
        i++;
        k++;
    }

    while (j < n2) { // 如果右半部分还有剩余元素
        arr[k] = R[j];
        j++;
        k++;
    }
}

注意事项

  • 时间复杂度始终为O(n log n),但需要额外的空间。
  • 是一种稳定的排序算法。

优缺点

  • 优点:稳定且效率高,适用于大规模数据。
  • 缺点:需要额外的存储空间。

总结

每种排序算法都有其特定的应用场景和限制。冒泡排序和选择排序虽然简单,但效率较低;插入排序适用于小规模或部分有序的数据;快速排序和归并排序则更适合处理大规模数据。在实际应用中,应根据具体情况选择合适的排序算法。理解和掌握这些算法的原理和实现,有助于开发者编写出更高效、更可靠的程序。

希望这篇文章能帮助您更好地理解和应用Java中的各种排序算法!

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

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

相关文章

html+css网页设计马林旅行社移动端4个页面

htmlcss网页设计马林旅行社移动端4个页面 网页作品代码简单&#xff0c;可使用任意HTML辑软件&#xff08;如&#xff1a;Dreamweaver、HBuilder、Vscode 、Sublime 、Webstorm、Text 、Notepad 等任意html编辑软件进行运行及修改编辑等操作&#xff09;。 获取源码 1&#…

Linux系统编程之进程控制

概述 在Linux系统中&#xff0c;创建一个新的进程后&#xff0c;如何对该进程进行有效的控制&#xff0c;是一项非常重要的操作。控制进程状态的操作主要包括&#xff1a;进程的执行、进程的等待、进程的终止等。下面&#xff0c;我们将逐个进行介绍。 进程的执行 创建进程后&a…

猜数字的趣味小游戏——rand函数、srand函数、time函数的使用

文章目录 前言一、随机数的生成1.1. rand函数1.2. srand函数1.3. time函数 二、设置随机数的范围三、猜数字游戏的代码实现总结 前言 上一篇博客我们写了一个电脑关机的小游戏&#xff0c;我篇博客我们写一个猜数字的小游戏&#xff0c;学习rand函数、srand函数、time函数的使…

ScratchLLMStepByStep:一步一步构建大语言模型教程

前言 在学习大语言模型的时候&#xff0c;总会遇到各种各样的名词&#xff0c;像自注意力、多头、因果、自回归、掩码、残差连接、归一化等等。这些名词会让学习者听的云里雾里&#xff0c;觉得门槛太高而放弃。 本教程将会带你从零开始&#xff0c;一步一步的去构建每一个组…

从0开始学PHP面向对象内容之常用设计模式(享元)

二、结构型设计模式 7、享元模式&#xff08;Flyweight Pattern&#xff09; 这里是引用享元模式&#xff08;Flyweight Pattern&#xff09; 是一种结构型设计模式&#xff0c;旨在通过共享对象来减少内存使用&#xff0c;尤其适用于大量相似对象的场景。通过共享和重用对象的…

时钟约束在STA中的作用

时钟约束在STA中的作用 1.约束作为声明2.约束作为断言3.约束作为指令4.约束作为异常5. 约束的角色变化 简介&#xff1a; STA工具从相应的设计描述中获取电路描述&#xff0c;HDL是最常用的形式。它还接受库输入–主要用来了解依赖技术的特性&#xff0c;如通过特定门的延迟值。…

Springboot 修改post请求接口入参或重新赋值

前言 很久之前写过一篇就是自动填充接口参数的&#xff0c;利用的 HandlerMethodArgumentResolver 自定义注解 Springboot Controller接口默认自动填充 业务实体参数值_springboot设置入参默认值-CSDN博客 现在这一篇也差不多&#xff0c;达到的目的就是重新去给post请求的参数…

机器学习:精确率与召回率的权衡

高精度意味着如果诊断得了那种罕见病的病人&#xff0c;可能病人确实有&#xff0c;这是一个准确的诊断&#xff0c;高召回率意味着如果有一个还有这种罕见疾病的病人&#xff0c;也许算法会正确的识别他们确实患有这种疾病&#xff0c;事实中&#xff0c;在精确与召回之间往往…

海盗王用golang重写的AccountServer功能

自从用golang重写了海盗王的网关gateserver以来&#xff0c;一直想把accountserver也重写了&#xff0c;但是一直没有进行。 趁上次刚写好那个golang版的更新器&#xff0c;还有些熟悉&#xff0c;于是把原来AccountServer的C代码重写读了个大概。它原版的写得太过于复杂&#…

【动态规划】小S的货船租赁冒险

文章目录 一、问题描述输入格式输出格式 问题背景二、动态规划思想三、代码实现细节初始化二维数组遍历每种货船遍历预算并更新状态提前剪枝优化 四、代码实现算法复杂度分析优化思路 一、问题描述 李华在码头租货船&#xff0c;有 Q 种货船可以租赁。第 i 种货船的数量为 m[i…

基于 MVC 架构的 SpringBoot 高校行政事务管理系统:设计优化与实现验证

摘 要 身处网络时代&#xff0c;随着网络系统体系发展的不断成熟和完善&#xff0c;人们的生活也随之发生了很大的变化&#xff0c;人们在追求较高物质生活的同时&#xff0c;也在想着如何使自身的精神内涵得到提升&#xff0c;而读书就是人们获得精神享受非常重要的途径。为了…

【k8s 深入学习之 event 聚合】event count累记聚合(采用 Patch),Message 聚合形成聚合 event(采用Create)

参考 15.深入k8s:Event事件处理及其源码分析 - luozhiyun - 博客园event 模块总览 EventRecorder:是事件生成者,k8s组件通过调用它的方法来生成事件;EventBroadcaster:事件广播器,负责消费EventRecorder产生的事件,然后分发给broadcasterWatcher;broadcasterWatcher:用…

HTML5动漫主题网站——天空之城 10页 html+css+设计报告成品项目模版

&#x1f4c2;文章目录 一、&#x1f4d4;网站题目 二、✍️网站描述 三、&#x1f4da;网站介绍 四、&#x1f310;网站演示 五、⚙️网站代码 &#x1f9f1;HTML结构代码 &#x1f492;CSS样式代码 六、&#x1f527;完整源码下载 七、&#x1f4e3;更多 一、&#…

day2 美化后的登录

import sysfrom PyQt6.QtGui import QIcon, QPixmap from PyQt6.QtWidgets import QApplication, QWidget, QLabel from PyQt6 import uicclass MyWidget(QWidget):def __init__(self):super().__init__()self.setWindowTitle("猫咪乐园")uiuic.loadUi("./untit…

uniapp 自定义导航栏增加首页按钮,仿微信小程序操作胶囊

实现效果如图 抽成组件navbar.vue&#xff0c;放入分包 <template><view class"header-nav-box":style"{height:Props.imgShow?:statusBarHeightpx,background:Props.imgShow?:Props.bgColor||#ffffff;}"><!-- 是否使用图片背景 false…

Android KEY的哪些事儿

目录 一、APK应用签名 1、什么是APK应用签名&#xff1f; 1.1 目的和作用&#xff1f; 1.2 长什么样子&#xff1f; 2、APK应用签名使用流程 步骤一&#xff1a;如何生成APK应用签名文件&#xff1f; 步骤二&#xff1a;如何集成APK应用签名文件&#xff1f; 步骤三&am…

Docker中安装GeoServer

一、准备工作 #创建数据持久化目录 mkdir -p /usr/local/application/geoserver/data_dir#授权 chmod 777 -R /usr/local/application/ 这一步是为了在容器外部管理GeoServer的数据&#xff0c;使得数据能够持久化存储。 二、拉取GeoServer镜像 从Docker Hub拉取GeoServer的…

Create Stunning Word Clouds with Ease!

Looking to craft breathtaking word clouds? WordCloudStudio is your go-to solution! Whether you’re a marketer, educator, designer, or simply someone who loves visualizing data, this app has everything you need. Download now: https://apps.apple.com/app/wor…

【JavaEE初阶】落霞与孤鹜齐飞,秋水共长天一色 - (重点)线程

本篇博客给大家带来的是线程的知识点, 由于时间有限, 分三天来写, 本篇为线程第二篇. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅…

java_判断语句——acwing

题目一&#xff1a;倍数 665. 倍数 - AcWing题库 代码 import java.util.Scanner;public class Main{public static void main(String[] args) {Scanner sc new Scanner(System.in);int a sc.nextInt(), b sc.nextInt();if(a%b0 || b%a0) System.out.printf("Sao Mu…