当前位置: 首页 > news >正文

【Java】—— 常见的排序算法

一、排序的概念

排序的定义:将一组数据按照特定的顺序重新排列的过程。

排序的目的:是使数据更易于查找、比较和分析。

排序的适应范围:可以应用于各种数据类型。

排序的稳定性:指当出现相同元素时,排序后相同元素的先后顺序保持不变,则称这个排序为稳定排序

内部排序:指在内存中进行排序

外部排序:指借助硬盘完成排序

二、常见排序算法的实现

1、直接插入排序

核心思想:

将数组分为 已排序区间 和 未排序区间 , 初始情况下,已排序区间就是空,未排序区间就是整个数组,每次从 未排序区间 中选择一个元素,插入到 已排序区间 的合适位置上。

代码实现:

    private static void insertSort(int[] arr){//bound 变量表示边界//[0,bound) 区间表示有序区间//[bound,arr.length) 区间是无序区间for(int bound = 1; bound < arr.length ; bound++ ){//循环内部进行一次的插入操作//value 就是无序区间的第一个元素int value = arr[bound];//用这个元素在有序区间从后向前比较int cur = bound - 1;for(;cur >= 0 ; cur--){//前一个的值大于bound那么if(arr[cur] > value){arr[cur + 1] = arr[cur];}else {break;}}//交换元素arr[cur+1] = value;}}

特性:元素集合越接近有序,直接插⼊排序算法的时间效率越⾼

时间复杂度:O(n^2)

空间复杂度:O(1);

稳定性:稳定

2、希尔排序

核心思想:

希尔排序是对插入排序的一种优化,引入了 gap(间隔) 的概念,将元素分成多个组,并分别进行插入排序。再不断缩小 gap 直到 gap 为 1 时,就是普通的插入排序。

代码实现:

    private static void shellSort(int[] arr){//计算一个合适的gap值,再不断缩小int gap = arr.length / 2;while (gap >= 1){insertSortGap(arr,gap);gap /= 2;}}private static void insertSort(int[] arr){//bound 变量表示边界//[0,bound) 区间表示有序区间//[bound,arr.length) 区间是无序区间for(int bound = 1; bound < arr.length ; bound++ ){//循环内部进行一次的插入操作//value 就是无序区间的第一个元素int value = arr[bound];//用这个元素在有序区间从后向前比较int cur = bound - 1;for(;cur >= 0 ; cur--){//前一个的值大于bound那么if(arr[cur] > value){arr[cur + 1] = arr[cur];}else {break;}}//交换元素arr[cur+1] = value;}}

希尔排序的时间复杂度不好计算,因为 gap 的取值有很多

3、直接选择排序

核心思想:

将元素划分为 有序区间 和 无序区间,初始情况下 有序区间 为 空 ,每一次遍历都从无序区间里找到最小值,把这个最小值依次放到有序区间

代码实现:

    private static void selectSort(int[] arr){for(int bound = 0;bound < arr.length - 1;bound++){for (int cur = bound + 1 ; cur < arr.length ; cur++){if(arr[cur] < arr[bound]){int temp = arr[cur];arr[cur] = arr[bound];arr[bound] = temp;}}}}

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:不稳定

4、堆排序

核心思想:

堆排序(Heapsort)是指利用堆积树(堆)这种数据结构所设计的一种排序算法,它是选择排序的一 种。它是通过堆来进行选择数据。需要注意的是排升序要建大堆,排降序建小堆。

代码实现:

    private static void selectSort(int[] arr){for(int bound = 0;bound < arr.length - 1;bound++){for (int cur = bound + 1 ; cur < arr.length ; cur++){if(arr[cur] < arr[bound]){int temp = arr[cur];arr[cur] = arr[bound];arr[bound] = temp;}}}}private static void headSort(int[] arr){//1.建堆createHeap(arr);int bound = arr.length - 1;for(int i = 0; i < arr.length ; i++){//交换堆顶和待排序区间的最后一个元素int temp = arr[0];arr[0] = arr[bound];arr[bound] = temp;//重新调整堆//通过 bound 表示堆的元素个数shiftDown(arr,bound,0);//最后一个元素归入到 已排序区间bound--;}}private static void createHeap(int[] arr){//从最后一个非叶子节点触发,从后往前遍历for(int i=(arr.length-1-1)/2 ; i >= 0 ; i--){shiftDown(arr, arr.length, i);}}private static void shiftDown(int[] arr,int length,int index){int parent = index;int child = 2 * parent + 1;while (child < length){//建立大堆,需要取左右子节点中较大值if(child + 1 < length && arr[child + 1] > arr[child]){child += 1;}//比较 child 和 parent 元素大小if(arr[child] > arr[parent]){int temp = arr[child];arr[child] = arr[parent];arr[parent] = temp;}else{break;}parent = child;child = 2 * parent + 1;}}

时间复杂度:O(N*logN)

空间复杂度:O(1)

稳定性:不稳定

5、冒泡排序

核心思想:

通过不断比较相邻元素,一趟过后,最大(最小)的一个元素就会在数组中最末尾的位置,再进行 n - 1 次就可以达到有序

代码实现:

    private static void bubbleSort(int[] arr){for(int bound = 0;bound < arr.length-1 ; bound++){for (int cur = arr.length - 1 ; cur > bound ; cur--){if(arr[cur-1] > arr[cur]){int temp = arr[cur - 1];arr[cur - 1] = arr[cur];arr[cur] = temp;}}}}

时间复杂度:O(N^2)

空间复杂度:O(1)

稳定性:稳定

6、快速排序

核心思想:

任取待排序区间中选出某元素作为基准值,按照该排序码将待排序集合分割成两个子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后左右子序列重复该过程,直到所有元素都排列在相应位置上为止。

代码实现:

    //此处约定[left,right]闭区间为待处理区间//快速排序入口private static void quickSort(int[] arr){quickSort(arr,0, arr.length-1);}//快速排序辅助递归的方法private static void quickSort(int[] arr,int left,int right){if(left >= right){//待处理区间为空或者只有一个元素,无需排序return;}//针对区间进行整理,返回值 index 表示基准值所在的下标int index = partition(arr,left,right);//递归左半区间quickSort(arr,left,index-1);//递归右半区间quickSort(arr,index+1,right);}private static int partition(int[] arr,int left,int right){//设定最右侧元素为基准值int value = arr[right];//设定两个下标,分别从左往右和右往左int l = left;int r = right;while (l < r){while (l < r && arr[l] <= value){l++;}while (l < r && arr[r] >= value){r--;}swap(arr,l,r);}//循环完成交换重合位置和基准值swap(arr,l,right);return l;}private static void swap(int[] arr,int i,int j){int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}

快速排序在大多数情况下的表现都是非常优秀的,除了个别极端情况会让时间复杂度到O(N^2)

时间复杂度:O(N*logN)

空间复杂度:O(logN)

稳定性:不稳定

7、归并排序

核心思想:

通过递归将待排序的数组分成两个子数组,直到每个子数组只包含一个元素。此时,单个元素的数组自然是有序的。将两个有序的子数组合并成一个有序的数组。合并时,从两个子数组的起始位置开始比较,选择较小的元素放入结果数组中,直到其中一个子数组的所有元素都被合并。然后将另一个子数组的剩余元素直接放入结果数组中。

代码实现:

    //归并排序入口方法private static void mergeSort(int[] arr){mergeSort(arr,0,arr.length-1);}private static void mergeSort(int[] arr,int left,int right){//如果子区间没有元素或只有一个元素就不再递归if(left >= right){return;}//把区间分为等长的两个区间,不强制完全相等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){//创建临时数组保存合并的结果,临时数组的长度应该是 right - left + 1int[] result = new int[right - left + 1];//通过判断大小尾插到新数组中int resultSize = 0;//两个下标指向每个区间的开头int cur1 = left;int cur2 = mid + 1;while (cur1 <= mid && cur2 <= right){if(arr[cur1] <= arr[cur2]){result[resultSize++] = arr[cur1];cur1++;}else{result[resultSize++] = arr[cur2];cur2++;}}//处理前面奇数划分不均的情况while (cur1 <= mid){result[resultSize++] = arr[cur1++];}while (cur2 <= right){result[resultSize++] = arr[cur2++];}//把临时数组的结果写回到 arr 的 [left,right] 中for(int i=0;i<result.length;i++){arr[left + i] = result[i];}}

归并排序的思考更多的是解决在磁盘中的外排序问题

时间复杂度:O(N*logN)

空间复杂度:O(N)

稳定性:稳定

三、小结

除了上文提到的这几种,还有许多其他的排序算法,例如 计数排序 ,基数排序 ,桶排序 等等,应该结合实际情况选择使用,学好排序算法的原理可以用这些思想去解决其他的问题。

相关文章:

  • Modelsim的入门使用和Verilog编写
  • 在 Ubuntu 24.04 LTS 上 Docker 部署 DB-GPT
  • 汇舟问卷:国外问卷调查如何闭坑
  • 【RocketMQ 生产者和消费者】- 生产者启动源码-启动流程(1)
  • 选新手机的参考:CPU型号、内存、外存、屏幕、摄像头以及电池等。
  • 如何测试JWT的安全性:全面防御JSON Web Token的安全漏洞
  • AI Agent开发第73课-预训练qwen3-如何加入自己的语料
  • ElasticSearch操作
  • 边缘计算是什么?逻辑视域下的边缘计算:分布式计算范式的理论基础与逻辑结构分析
  • 二分算法的补充说明
  • TMP1827认证流程
  • 从法律视角看湖北理元理律师事务所的债务优化实践
  • 数据结构与算法-线性表-双向链表(Double Linked List)
  • C++ 中的 **常变量** 与 **宏变量** 比较
  • 25.5.22学习总结
  • window 显示驱动开发-指定 GDI 硬件加速渲染操作
  • Python-标准库
  • 浅谈测试驱动开发TDD
  • 微服务架构的演变过程
  • 关于大语言模型的问答?
  • 做网站服务器一年多少钱/桂林网站设计制作
  • 台州网站建设网站推广/外贸接单十大网站
  • 大航母网站建设/品牌策划是做什么的
  • 日本a片女人和狗做的网站/seo搜索引擎推广
  • 网站建设报价明细表/东莞疫情最新数据
  • wordpress 远程管理/seo长尾关键词优化