排序算法:从原理到 Java 实现

文章目录

  • 排序算法:从原理到 Java 实现
    • 一、引言
    • 二、常见排序算法原理及 Java 实现
      • (一)冒泡排序(Bubble Sort)
      • (二)选择排序(Selection Sort)
      • (三)插入排序(Insertion Sort)
      • (四)快速排序(Quick Sort)
      • (五)归并排序(Merge Sort)
      • (六)堆排序(Heap Sort)
    • 三、性能比较与分析
      • (一)时间复杂度
      • (二)空间复杂度
      • (三)稳定性
    • 四、题外话
      • (一)稳定性是什么?
      • (二)稳定性在实际应用中是一个重要的考虑因素吗?
      • (三)有些算法又稳定又快,为什么还需要有那么多排序算法?
    • 五、总结

排序算法:从原理到 Java 实现

一、引言

排序算法是计算机科学中最基本和最重要的算法之一。无论是在数据库查询、文件系统管理还是在日常的编程任务中,我们都经常需要对数据进行排序。本文将深入探讨几种常见的排序算法,包括冒泡排序、选择排序、插入排序、快速排序、归并排序以及堆排序,并通过 Java 代码实现来帮助读者更好地理解它们的工作原理。

二、常见排序算法原理及 Java 实现

(一)冒泡排序(Bubble Sort)

  1. 原理
    • 冒泡排序是一种简单的排序算法,它重复地遍历要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。
    • 遍历数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。
  2. Java 实现
public class BubbleSort {public static void sort(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+1] 和 arr[j]int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}
}

(二)选择排序(Selection Sort)

  1. 原理
    • 首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置。
    • 再从剩余未排序元素中继续寻找最小(大)元素,然后放到已排序序列的末尾。
    • 以此类推,直到所有元素均排序完毕。
  2. Java 实现
public class SelectionSort {public static void sort(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;}}
}

(三)插入排序(Insertion Sort)

  1. 原理
    • 把待排序的数组分成已排序和未排序两部分。
    • 初始时,已排序部分只有一个元素,即数组的第一个元素。
    • 从第二个元素开始,将每个元素插入到已排序部分的适当位置,使得已排序部分始终保持有序。
  2. Java 实现
public class InsertionSort {public static void sort(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 = j - 1;}arr[j + 1] = key;}}
}

(四)快速排序(Quick Sort)

  1. 原理
    • 通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小。
    • 然后分别对这两部分记录继续进行排序,以达到整个序列有序。
  2. Java 实现
public class QuickSort {public static void sort(int[] arr, int low, int high) {if (low < high) {int pi = partition(arr, low, high);sort(arr, low, pi - 1);sort(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;}
}

(五)归并排序(Merge Sort)

  1. 原理
    • 采用分治策略,将待排序数组分成两个子数组,分别对两个子数组进行排序。
    • 然后将两个已排序的子数组合并成一个有序的数组。
  2. Java 实现
public class MergeSort {public static void sort(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);sort(left);sort(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++];}}
}

(六)堆排序(Heap Sort)

  1. 原理
    • 堆排序是利用堆这种数据结构而设计的一种排序算法。堆是一种完全二叉树,它分为大顶堆和小顶堆。
    • 大顶堆的每个节点的值都大于或等于其子节点的值,小顶堆的每个节点的值都小于或等于其子节点的值。
    • 堆排序的基本思想是将待排序的序列构建成一个堆,然后将堆顶元素与堆的最后一个元素交换,再对剩余的元素重新构建堆,直到整个序列有序。
  2. Java 实现
public class HeapSort {public static void sort(int[] arr) {int n = arr.length;// 构建大顶堆for (int i = n / 2 - 1; i >= 0; i--) {heapify(arr, n, i);}// 排序for (int i = n - 1; i > 0; i--) {// 将堆顶元素与最后一个元素交换int temp = arr[0];arr[0] = arr[i];arr[i] = temp;// 对剩余的元素重新构建堆heapify(arr, i, 0);}}private static void heapify(int[] arr, int n, int i) {int largest = i;int left = 2 * i + 1;int right = 2 * i + 2;if (left < n && arr[left] > arr[largest]) {largest = left;}if (right < n && arr[right] > arr[largest]) {largest = right;}if (largest!= i) {int temp = arr[i];arr[i] = arr[largest];arr[largest] = temp;// 递归调整子树heapify(arr, n, largest);}}
}

三、性能比较与分析

(一)时间复杂度

  1. 冒泡排序、选择排序、插入排序:
    • 这三种排序算法的时间复杂度都是O(n^2),其中n是待排序数组的长度。在最坏情况下,即数组完全逆序时,需要进行n(n-1)/2次比较和交换操作。
  2. 快速排序:
    • 平均时间复杂度为O(nlogn),最坏情况下为O(n^2)。当每次划分都不均匀时,会退化为冒泡排序的时间复杂度。但在实际应用中,快速排序的性能通常非常好。
  3. 归并排序:
    • 无论在最好、最坏还是平均情况下,时间复杂度都是O(nlogn)。这是因为归并排序每次都将数组分成两个子数组,然后分别对两个子数组进行排序,最后将两个已排序的子数组合并成一个有序的数组。
  4. 堆排序:
    • 时间复杂度为O(nlogn)。堆排序的时间复杂度主要取决于构建堆和调整堆的过程。构建堆的时间复杂度为O(n),调整堆的时间复杂度为O(logn),因此堆排序的总时间复杂度为O(nlogn)。

(二)空间复杂度

  1. 冒泡排序、选择排序、插入排序:
    • 这三种排序算法都是原地排序算法,空间复杂度为O(1)。它们只需要常数级别的额外空间来进行排序操作。
  2. 快速排序:
    • 平均情况下空间复杂度为O(logn),最坏情况下为O(n)。快速排序在递归过程中需要使用栈空间来存储函数调用的上下文信息。
  3. 归并排序:
    • 空间复杂度为O(n)。归并排序在合并两个子数组时需要额外的空间来存储临时结果。
  4. 堆排序:
    • 空间复杂度为O(1)。堆排序是原地排序算法,只需要常数级别的额外空间来进行排序操作。

(三)稳定性

  1. 冒泡排序、插入排序、归并排序:
    • 这三种排序算法是稳定的排序算法,即如果两个元素相等,在排序后它们的相对顺序不会改变。
  2. 选择排序、快速排序、堆排序:
    • 这三种排序算法是不稳定的排序算法。例如,在选择排序中,每次选择最小元素并与当前位置的元素交换时,可能会改变相等元素的相对顺序。

四、题外话

(一)稳定性是什么?

排序算法的不稳定性是指在排序过程中,具有相同值的元素的相对顺序可能会发生改变。

例如,对于一个包含多个具有相同值元素的序列进行不稳定排序时,这些相同值元素在排序后的相对位置与初始状态相比可能会不同;而稳定排序算法则能保证具有相同值的元素在排序前后的相对位置不变。

(二)稳定性在实际应用中是一个重要的考虑因素吗?

一、稳定性重要的场景

  1. 数据库排序
    • 在数据库管理系统中,如果对包含多个字段的记录进行排序,稳定性可以确保在主要字段值相同时,按照次要字段的原始顺序排列。例如,先按照成绩降序排序,成绩相同的情况下按照学号升序排序。如果排序算法不稳定,可能会导致学号的顺序变得混乱,影响查询结果的准确性和可预测性。
  2. 多关键字排序
    • 当需要根据多个属性对对象进行排序时,稳定性可以确保在前面的属性值相同的情况下,后面的属性排序不会破坏已有的顺序。比如对学生先按照班级排序,再在班级内按照成绩排序。如果算法不稳定,可能会导致在班级内成绩相同的学生的相对顺序发生变化,给后续的分析和处理带来麻烦。
  3. 金融交易排序
    • 在金融领域,交易记录的顺序可能具有重要意义。如果对交易按照时间戳和金额进行排序,稳定性可以确保在时间戳相同的情况下,交易的原始顺序得以保留。这对于审计、合规性检查以及分析交易趋势等任务非常重要,因为顺序的变化可能会影响对交易流程和时间顺序的理解。

二、稳定性不太重要的场景

  1. 一般数据分析
    • 在某些数据分析任务中,只关注数据的整体分布和统计特征,而不关心相同值元素的具体顺序。例如,计算数据集的均值、中位数、标准差等统计量时,排序的稳定性并不影响结果。此时,可以选择更高效的不稳定排序算法,以提高计算速度。
  2. 图像和信号处理
    • 在图像和信号处理领域,数据通常以矩阵或向量的形式表示,排序操作相对较少。而且,即使进行排序,通常也是对单个维度进行,并且不关心相同值元素的顺序。例如,在对图像的像素强度进行排序以找到最大值或最小值时,稳定性不是关键因素。

(三)有些算法又稳定又快,为什么还需要有那么多排序算法?

一、不同场景的适用性不同

  1. 数据特点
    • 不同的数据集可能具有不同的特点。例如,对于近乎有序的数据集,插入排序可能非常高效;而对于数据量大且分布比较随机的情况,快速排序等更复杂的算法可能表现更好。
    • 如果数据中包含大量重复元素,稳定排序可能更有优势以保持相同元素的相对顺序,但在某些情况下,对稳定性要求不高时,不稳定排序算法可能速度更快。
  2. 数据规模
    • 对于小型数据集,简单的排序算法如冒泡排序可能就足够快,而复杂的稳定且快速的算法可能会引入过多的开销。
    • 对于超大规模数据集,可能需要考虑分布式排序等特殊的方法,而不仅仅是传统的单一算法。

二、算法的空间复杂度

稳定且快速的排序算法可能需要较大的额外空间。例如,归并排序虽然稳定且在很多情况下效率较高,但它需要额外的与输入数据规模相同的空间来进行合并操作。在内存受限的环境中,这可能成为一个问题。

三、实现复杂性和资源需求

  1. 编程复杂性
    • 一些稳定且快速的排序算法可能在实现上比较复杂,需要更多的代码和调试时间。这可能会增加开发成本和引入潜在的错误。
  2. 硬件资源
    • 某些算法可能对特定的硬件资源有较高的要求。例如,一些算法可能更适合在具有大量内存的系统上运行,而在资源受限的嵌入式系统或移动设备上,可能需要更简单、资源需求低的排序算法。

四、特殊需求

  1. 实时性要求
    • 在某些实时系统中,对排序的时间要求非常严格,可能需要根据具体的实时约束选择特定的算法,而不一定是通用的稳定且快速的算法。
  2. 特定数据类型或结构
    • 对于特定的数据类型,如链表、树等数据结构,可能需要专门设计的排序算法,而通用的稳定且快速的排序方法可能并不适用。

综上所述,虽然稳定且快速的排序方法在很多情况下是理想的选择,但不能解决所有的排序问题,需要根据具体的应用场景和需求来选择最合适的排序算法。

五、总结

排序算法是计算机科学中的基础算法之一,掌握不同的排序算法对于提高编程能力和解决实际问题非常重要。本文介绍了六种常见的排序算法,包括冒泡排序、选择排序、插入排序、快速排序、归并排序以及堆排序,并通过 Java 代码实现展示了它们的工作原理。在实际应用中,我们需要根据数据规模、时间复杂度、空间复杂度和稳定性等因素选择合适的排序算法。希望本文能够帮助读者更好地理解排序算法,并在实际编程中灵活运用。

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

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

相关文章

【时间之外】IT人求职和创业应知【27】

目录 新闻一物理智能公司完成4亿美元融资 新闻二A股IPO和再融资受理、审核回暖 新闻三AI流量变现财富峰会举办 认知和思考决定了你的赚钱能力。以下是今天可能引起你思考的热点新闻&#xff1a; 今日关键字&#xff1a;没吃过猪肉&#xff0c;还没见过猪跑吗&#xff1f; 新…

【前端开发入门】JavaScript快速入门--函数技巧

目录 引言一、函数基本注意事项1. 函数定义2. 默认参数3. 函数返回值及闭包3.1 举个函数返回值的简单例子3.2 当我需要利用函数内部变量做一些运算时&#xff0c;就需要使用js的闭包 二、函数注释1. 单行注释2. 多行注释3. 进阶玩法 三、总结 引言 本系列教程旨在帮助一些零基础…

权威认证!蓝卓获评IDC数字工厂领导者

日前&#xff0c;全球领先的IT市场研究和咨询公司IDC公布了《IDC MarketScape: 中国数字工厂整体解决方案厂商评估&#xff0c;2024》。其中&#xff0c;蓝卓成功入选IDC中国数字工厂整体解决方案厂商&#xff0c;位列领导者象限。 数字工厂整体解决方案领导者 《IDC MarketSc…

$tab的所有用法以及vue关闭页面的方法汇总

1、最简单粗暴的就是直接window.close(); 2.可以设置一个窗口的显示隐藏变量&#xff0c;比如点击新增按钮时&#xff0c;新增页面窗口就进行显示&#xff0c;点击关闭就把这个值置为flase 在最外层绑定open 初始值设为false 点击新增和修改按钮时&#xff0c;把状态置为true即…

全同态加密基于多项式环计算的图解

全同态加密方案提供了一种惊人的能力 —— 能够在不知道数据具体内容的情况下对数据进行计算。这使得你可以在保持潜在敏感源数据私密的同时&#xff0c;得出问题的答案。 这篇文章的整体结构包括多项式环相关的数学介绍&#xff0c;基于多项式环的加密和解密是如何工作的&…

10天进阶webpack---(2)webpack模块兼容性处理

回顾CMJ和ESM的区别 CMJ的本质可以使用一个函数概括 // require函数的伪代码 function require(path){if(该模块有缓存吗){return 缓存结果;}function _run(exports, require, module, __filename, __dirname){// 模块代码会放到这里}var module {exports: {}}_run.call(mod…

【STM32】NVIC / EXTI / AFIO 介绍

文章目录 中断系统NVIC简介NVIC基本结构NVIC优先级分组EXTI外部中断EXIT基本结构AFIO复用IO口EXTI内部框图 AFIO / EXTI / NVIC 相关函数AFIO相关函数EXTI相关函数NVIC相关函数 旋转编码器简介对射式红外传感器计次接线图CountSensor&#xff08;传感器&#xff09;驱动程序封装…

【Linux内核大揭秘】程序地址空间

文章目录 什么是程序地址空间地址空间的组成虚拟内存技术 如何理解程序地址空间页表页表的细节关于堆区 在Linux中如何查看各个分段的信息总结 什么是程序地址空间 程序地址空间是一个程序在执行期间可以访问的内存范围。它由操作系统为每个进程分配&#xff0c;以确保进程之间…

nginx代理出现的请求头中获取不到acc_token问题

1.问题 程序开发完成之后&#xff0c;发现页面登录之后&#xff0c;获取不到用户信息。发现时没有获取到token信息。本地程序开发完成&#xff0c;后端服务成功署到服务器。通过云服务器开放对应的端口&#xff0c;使用本地的前端服务&#xff0c;直接连接服务器后端服务&…

WordPress之generatepress主题安装

1.打开主题列表 2.如果没有自己需要主题点击安装新主题 点击安装并启用 3.不喜欢的 主题可以点击主题进去删除 4.主题自定义编辑 打开自定义&#xff0c;可以修改布局&#xff0c;颜色&#xff0c;排版等等

MySQL之JDBC入门详解

01-JDBC入门 一、JDBC概念 jdbc : java database connection , java数据库连接 jdbc是sun公司定义的java程序访问数据库的规范。 二、JDBC操作需要6步 三、入门程序 1、使用eclipse打开一个新的工作空间 2、切换到java视图界面 3、创建java工程&#xff1a;01-jdbc-helloworl…

BackTrader-Commission 06

Backtrader 策略实例&#xff0c;该部分内容通过使用backtrader对常用的策略实例的编写&#xff0c;提高和熟悉backtrader的实际场景的使用。 [Backtrader]实例:均线策略 [Backtrader] 实例:MACD策略 [Backtrader] 实例:KDJ 策略 [Backtrader] 实例:RSI 与 EMA 结合 [Backtrade…

WordPress伪静态设置

为什么要设置WordPress伪静态&#xff0c;搜索引擎优化&#xff08;SEO&#xff09;中&#xff0c;静态URL通常被认为更易于搜索引擎爬虫抓取和索引&#xff0c;有助于提高网站的搜索引擎排名。 WordPress伪静态设置方法主要依赖于服务器环境&#xff0c;以下是针对不同服务器…

sublime python出现中文乱码怎么办

一、乱码现象 利用sublime自带编译快捷方式ctrlB会出现中文乱码的情况。 print("没有循环数据!") print("完成循环!") 二、寻找原因 1、由于之前我已经安装了插件ConvertToUTF8&#xff0c;排除文本编码错误问题。 2、相同的代码在插件sublimerepl搭建的…

【ARM Linux 系统稳定性分析入门及渐进 1.2 -- Crash 工具依赖内容】

请阅读:【Linux 维测及Crash使用专栏】 文章目录 Prerequisites1. 内核对象文件2. 内存镜像3. 平台处理器类型4. Linux 内核版本 Prerequisites crash 工具需要依赖下面的内容&#xff1a; 1. 内核对象文件 vmlinux 文件&#xff1a;需要一个 vmlinux 内核对象文件&#xff…

电路设计过程就是波形整形过程

这种说法有一定的道理。在电路设计中&#xff0c;常常需要对输入的电信号波形进行处理和调整&#xff0c;以满足后续电路或系统的要求&#xff0c;这在某种程度上可以理解为波形整形的过程。 例如&#xff0c;在数字电路中&#xff0c;输入的信号可能存在噪声、干扰或者不符合…

计算机视觉-显著性检测实验报告

实验四 显著性检测实验 一、实验目的 掌握多种显著性检测算法的基本原理。学会使用计算机程序实现不同的显著性检测方法。通过对比不同的显著性检测算法&#xff0c;理解各算法的优缺点。分析显著性检测在实际图像处理应用中的效果和局限性。 二、实验内容和要求 1&#x…

05-Dubbo的应用及注册和SPI机制

05-Dubbo的应用及注册和SPI机制 Dubbo 的服务注册中应用级注册优化 Dubbo 的注册中心 Dubbo 支持很多种注册中心&#xff0c;支持的主流注册中心包括&#xff1a;ZooKeeper、Nacos、Redis Dubbo 需要引入注册中心依赖&#xff0c;并且配置注册中心地址&#xff0c;这里以 ZooKe…

【 AI 大模型:重塑软件开发的新势力】

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

南宁周边乡村游微信小程序ssm+论文源码调试讲解

第二章 开发工具及关键技术介绍 2.1微信开发者工具 微信开发者工具现在已经被小程序开发团队开发运行&#xff0c;目前微信开发者工具任然在不断的完善中&#xff0c;在开发小程序时经常要不断的更新。可以使用微信扫码登陆开发者工具&#xff0c;开发者工具将使用这个微信帐号…