目录

一、冒泡排序(Bubble Sort)

原理​

二、选择排序(Selection Sort)

原理​

三、插入排序(Insertion Sort)

原理​

四、快速排序(Quick Sort)

原理​

五、归并排序(Merge Sort)

原理​

六、希尔排序(Shell Sort)

原理​

七、总结


作为一名 Java 初学者,掌握排序算法是编程路上的重要一步。排序算法不仅能帮助我们更好地理解数据处理逻辑,还能在实际开发中解决各种问题。

一、冒泡排序(Bubble Sort)

泡排序是最基础的排序算法之一,它的核心思想是通过重复遍历要排序的数组,每次比较相邻的两个元素,如果它们的顺序错误就把它们交换过来。

原理​

就像水中的气泡会逐渐上浮一样,越大的元素会经由交换慢慢 “浮” 到数组的末端。具体来说,每一轮遍历都会将当前未排序部分中最大的元素移动到正确的位置。

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]) {// 交换元素int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}}public static void main(String[] args) {int[] arr = {64, 34, 25, 12, 22, 11, 90};bubbleSort(arr);System.out.println("排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

 排序后的数组:
 11 12 22 25 34 64 90 

优缺点​:

  • 优点:实现简单,易于理解,是入门排序算法的好选择。​
  • 缺点:效率较低,时间复杂度为 O (n²),在处理大规模数据时性能不佳。

二、选择排序(Selection Sort)

选择排序的思路相对直观,它每次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。

原理​

首先在未排序序列中找到最小元素,存放到排序序列的起始位置,然后,再从剩余未排序元素中继续寻找最小元素,放到已排序序列的末尾。以此类推,直到所有元素均排序完毕。

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;}}// 将最小元素与未排序部分的第一个元素交换int temp = arr[minIndex];arr[minIndex] = arr[i];arr[i] = temp;}}public static void main(String[] args) {int[] arr = {64, 25, 12, 22, 11};selectionSort(arr);System.out.println("排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

排序后的数组:
11 12 22 25 64 

优缺点​:

  • 优点:实现简单,相较于冒泡排序,交换次数更少。​
  • 缺点:时间复杂度仍为 O (n²),不适合处理大量数据。

三、插入排序(Insertion Sort)

插入排序的工作方式类似于我们整理手中的扑克牌,它将数组分为已排序和未排序两部分,每次从为排序部分中取出一个元素,插入到已排序部分的正确位置。

原理​

从第一个元素开始,该元素可以认为已经被排序;取出下一个元素,在已经排序的元素序列中从后向前扫描;如果该元素(已排序)大于新元素,将该元素移到下一位置;重复上一步骤,直到找到已排序的元素小于或者等于新元素的位置;将新元素插入到该位置后;重复以上步骤。

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;// 将大于key的元素向后移动一位while (j >= 0 && arr[j] > key) {arr[j + 1] = arr[j];j = j - 1;}arr[j + 1] = key;}}public static void main(String[] args) {int[] arr = {12, 11, 13, 5, 6};insertionSort(arr);System.out.println("排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

 排序后的数组:
5 6 11 12 13 

优缺点​:

  • 优点:对于近乎有序的数组,插入排序的效率很高,时间复杂度可接近 O (n);实现也较为简单。​
  • 缺点:在处理完全无序的大规模数据时,时间复杂度仍为 O (n²)。

四、快速排序(Quick Sort)

快速排序是一种高效的排序算法,它采用了分治法的思想,通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,然后分别对这两部分记录继续进行排序,以达到整个序列有序的目的。

原理​

选择一个元素作为 “基准”(pivot),通常选择数组的第一个元素、最后一个元素或中间元素。然后将所有比基准值小的元素放在基准前面,所有比基准值大的元素放在基准后面,这个过程称为分区(partition)操作。接着,对基准前后的两个子数组分别重复上述过程,直到子数组的长度为 1 或 0。

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];// i表示小于基准元素的区域的边界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;}public static void main(String[] args) {int[] arr = {10, 7, 8, 9, 1, 5};int n = arr.length;quickSort(arr, 0, n - 1);System.out.println("排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

排序后的数组:
1 5 7 8 9 10 

优缺点​:

  • 优点:平均时间复杂度为 O (n log n),效率高,在实际应用中广泛使用。​
  • 缺点:在最坏情况下(如数组已经有序),时间复杂度会退化为 O (n²);不稳定,可能会改变相等元素的相对顺序。

五、归并排序(Merge Sort)

归并排序同样基于分治法,它的核心是将两个或两个以上的有序表合并成一个新的有序表。​

原理​

将待排序数组不断二分,直到每个子数组只包含一个元素(此时子数组自然有序)。然后,将这些有序的子数组两两合并,每次合并都得到一个更大的有序数组,重复这个过程,直到最终得到一个完整的有序数组。

public class MergeSort {// 合并两个有序子数组public 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++;}}// 归并排序主方法public static void mergeSort(int[] arr, int left, int right) {if (left < right) {// 找到中间点int mid = left + (right - left) / 2;// 递归排序左右两部分mergeSort(arr, left, mid);mergeSort(arr, mid + 1, right);// 合并已排序的两部分merge(arr, left, mid, right);}}public static void main(String[] args) {int[] arr = {12, 11, 13, 5, 6, 7};int n = arr.length;mergeSort(arr, 0, n - 1);System.out.println("排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

排序后的数组:
5 6 7 11 12 13 

优缺点​

  • 优点:时间复杂度稳定为 O (n log n),不受输入数据的影响;是稳定的排序算法。​
  • 缺点:需要额外的存储空间,空间复杂度为 O (n)。

六、希尔排序(Shell Sort)

希尔排序是插入排序的一种改进版本,它通过将数组按照一定的间隔分组,对每组进行插入排序,然后逐渐缩小间隔,直到间隔为 1,此时进行最后一次插入排序,使数组完全有序。​

原理​

先确定一个增量序列,增量序列可以有多种选择,常见的有初始增量为数组长度的一半,之后每次减半,直到增量为 1。对于每个增量,将数组中所有距离为该增量的元素组成一个子数组,对每个子数组进行插入排序。随着增量逐渐减小,子数组的长度逐渐增大,当增量为 1 时,整个数组就是一个子数组,此时进行一次插入排序,数组就会变得有序。

public class ShellSort {public static void shellSort(int[] arr) {int n = arr.length;// 初始增量为数组长度的一半,之后每次减半for (int gap = n / 2; gap > 0; gap /= 2) {// 对每个子数组进行插入排序for (int i = gap; i < n; i++) {int temp = arr[i];int j;// 移动同组中比temp大的元素for (j = i; j >= gap && arr[j - gap] > temp; j -= gap) {arr[j] = arr[j - gap];}arr[j] = temp;}}}public static void main(String[] args) {int[] arr = {12, 34, 54, 2, 3};shellSort(arr);System.out.println("排序后的数组:");for (int num : arr) {System.out.print(num + " ");}}
}

排序后的数组:
2 3 12 34 54 

优缺点​

  • 优点:相较于插入排序,希尔排序在处理大规模数据时效率更高,平均时间复杂度优于 O (n²),具体取决于增量序列的选择。​
  • 缺点:时间复杂度受增量序列影响较大,不同的增量序列可能会导致不同的性能;是不稳定的排序算法。

七、总结

以上六种排序算法各有特点,适用于不同的场景。

冒泡排序、选择排序和插入排序是基础的排序算法,实现简单但效率较低,适合处理小规模数据或作为学习排序算法的入门内容。​

快速排序、归并排序和希尔排序是更高级的排序算法,它们在处理大规模数据时表现更出色。快速排序平均效率高,应用广泛;归并排序时间稳定且稳定,但需要额外空间;希尔排序是插入排序的改进,性能优于基础的插入排序。

同时,Java 类库中提供的 Arrays.sort () 方法内部采用了多种高效排序算法的组合,在大多数情况下能满足我们的需求,但了解各种排序算法的原理和实现,能帮助我们更好地理解和使用这些工具。

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

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Gitee如何成为国内企业DevOps转型的首选平台?

Gitee如何成为国内企业DevOps转型的首选平台&#xff1f; 在数字化转型浪潮中&#xff0c;DevOps已成为提升企业研发效能的关键引擎。作为国内领先的代码托管与协作平台&#xff0c;Gitee凭借本土化优势与全流程支持能力&#xff0c;正成为越来越多企业DevOps实践的核心载体。本…

​Excel——SUMPRODUCT 函数

SUMPRODUCT 是 Excel 中最强大的函数之一&#xff0c;可以用于 ​多条件求和、加权计算、数组运算​ 等复杂场景。下面通过 ​基础语法 实用案例​ 彻底讲透它的用法&#xff01;​一、基础语法​SUMPRODUCT(数组1, [数组2], [数组3], ...)​功能​&#xff1a;将多个数组的对…

告别虚函数性能焦虑:深入剖析C++多态的现代设计模式

🚀 引言:当多态遇上性能瓶颈 我经常被问到这样一个问题:“既然virtual函数这么方便,为什么在一些高性能场景下,大家却避之不及?” 答案很简单:性能。 在我参与的多个HPC项目和游戏引擎开发中,virtual函数调用往往成为性能分析工具中最显眼的那个红点。一个看似无害…

k8s-MongoDB 副本集部署

前提准备一套 k8s 集群worker 节点上的 /nfs/data 目录挂载到磁盘一、NFS 高可用方案&#xff08;NFSkeepalivedSersync&#xff09;本方案 NFS 的高可用方案&#xff0c;应用服务器为 Client &#xff0c;两台文件服务器分别 Master 和 Slave&#xff0c;使用 keepalived 生成…

BI 系统数据看板全解析:让数据可视化驱动业务决策

BI 系统数据看板全解析&#xff1a;让数据可视化驱动业务决策在 BI 系统中&#xff0c;数据看板是连接原始数据与业务洞察的 “桥梁”。它将零散的业务指标转化为直观的可视化图表&#xff0c;让产品经理、运营人员等角色能快速把握业务动态。一个设计精良的数据看板&#xff0…

图机器学习(14)——社交网络分析

图机器学习&#xff08;14&#xff09;——社交网络分析0. 前言1. 数据集分析1.1 数据集介绍1.2 使用 networkx 加载数据集2. 网络拓扑和社区检测2.1 网络拓扑2.2 社区检测0. 前言 社交网站的崛起是近年来数字媒体领域最活跃的发展趋势之一&#xff0c;数字社交互动已经融入人…

深入解析Hadoop MapReduce中Reduce阶段排序的必要性

MapReduce概述与Reduce阶段简介MapReduce作为Hadoop生态系统的核心计算框架&#xff0c;其设计思想源自Google论文&#xff0c;通过"分而治之"的理念实现海量数据的并行处理。该模型将计算过程抽象为两个关键阶段&#xff1a;Map阶段负责数据分解和初步处理&#xff…

7月23日华为机考真题第二题-200分

📌 点击直达笔试专栏 👉《大厂笔试突围》 💻 春秋招笔试突围在线OJ 👉 笔试突围OJ bishipass.com 02. 图书馆资源分配系统 问题描述 A先生是一位图书馆管理员,负责管理图书采购和分配工作。图书馆收到了来自不同出版社的图书批次,同时有多位读者代表排队申请图书…

基于深度学习的图像分类:使用ResNet实现高效分类

最近研学过程中发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击链接跳转到网站人工智能及编程语言学习教程。读者们可以通过里面的文章详细了解一下人工智能及其编程等教程和学习方法。下面开始对正文内容的…

JVM:工具

JVMjpsjstatjmapjhatjstackjconsolejvisualvmjps jps&#xff08; Java Virtual Machine Process Status Tool &#xff09;&#xff0c;是 JDK 中的一个命令行工具&#xff0c;用于列出当前正在运行的 JVM 实例的信息。其对于监控和管理运行在多个 JVM 上的 Java 应用程序特别…

Elasticsearch Circuit Breaker 全面解析与最佳实践

一、Circuit Breaker 简介 Elasticsearch 是基于 JVM 的搜索引擎&#xff0c;其内存管理十分重要。为了避免单个操作或查询耗费过多内存导致节点不可用&#xff0c;Elasticsearch 引入了 Circuit Breaker&#xff08;熔断器&#xff09;机制。当内存使用达到熔断器预设阈值时&a…

ARM-定时器-定时器函数封装配置

以TIMER7为例&#xff0c;对定时器函数进行封装注意事项&#xff1a;GD32中TIMER7是高级定时器&#xff0c;相关详细请参考上一篇文章。main.c//main.c#include "gd32f4xx.h" #include "systick.h" #include <stdio.h> #include "main.h" …

【日志】unity俄罗斯方块——边界限制检测

Bug修复记录 项目场景 尝试使用Unity独自制作俄罗斯方块&#xff08;也许很没有必要&#xff0c;网上随便一搜就有教程&#xff09; 问题描述 俄罗斯方块的边缘检测出错了&#xff0c;对方块进行旋转后&#xff0c;无法到达最左侧或者最下侧的位置&#xff0c;以及其他问题。演…

C++ string:准 STL Container

历史STL 最初是一套独立的泛型库&#xff08;Alexander Stepanov 等人贡献&#xff09;&#xff0c;后来被吸纳进 C 标准库&#xff1b;std::basic_string 则是早期 C 标准&#xff08;Cfront / ARM 时代&#xff09;就存在的“字符串类”&#xff0c;并非 STL 原生物。std::st…

Golang学习笔记--语言入门【Go-暑假学习笔记】

目录 基础语法部分相关概念 基础语法部分概念详解 可见性 导包 内部包 运算符 转义字符 函数 风格 函数花括号换行 代码缩进 代码间隔 花括号省略 三元表达式 数据类型部分相关概念 数据类型部分概念详解 布尔类型 整型 浮点型 复数类型 字符类型 派生类型…

linux中kill 命令使用详解

在Linux系统里&#xff0c;kill命令的主要功能是向进程发送信号&#xff0c;以此来控制进程的运行状态。下面为你详细介绍它的使用方法&#xff1a; 基础语法 kill [选项] [进程ID]进程ID也就是PID&#xff0c;可通过ps、pgrep或者top等命令来获取。 常用信号及其含义 信号可以…

Nginx 安装与 HTTPS 配置指南:使用 OpenSSL 搭建安全 Web 服务器

Nginx 安装与 HTTPS 配置指南:使用 OpenSSL 搭建安全 Web 服务器 一、Nginx安装 1. 安装依赖项 sudo yum groupinstall "Development Tools" -y # 非必须 sudo yum install pcre pcre-devel zlib zlib-devel openssl openssl-devel -y2.下载Nginx wget http://n…

写个 flask todo app,简洁,实用

- 此项目虽然看起来简单&#xff0c;实际上&#xff0c;修改成自己喜欢的样子&#xff0c;也是费时间的。 - 别人都搞AI 相关的项目&#xff0c;而我还是搞这种基础的东西。不要灰心。 - 积累。不论项目大小&#xff0c;不论难易&#xff0c;只看是否有用。项目地址&#xff1a…

4麦 360度定位

要在 ESP32 上用 4 个麦克风实现 360 声源定位&#xff0c;通常思路是通过 时延估计&#xff08;TDOA&#xff09; 几何计算&#xff0c;核心流程&#xff1a;阵列布置将 4 个麦克风等间距布置成正方形&#xff08;或圆形&#xff09;。记阵列中心为原点&#xff0c;麦克风编号…

使用yolov10模型检测视频中出现的行人,并保存为图片

一、使用yolov10模型检测视频中出现的行人&#xff0c;并保存为图片&#xff0c;detect_person.py代码如下&#xff1a;from ultralytics import YOLOv10 import glob import os import cv2 import argparsedef detect_person(videoPath, savePath):if not os.path.exists(save…