Java数据结构——八大排序

排序

  • 插⼊排序
  • 希尔排序
  • 直接选择排序
  • 堆排序
  • 冒泡排序
  • 快速排序
  • 归并排序
  • 计数排序

排序的概念
排序:就是将一串东西,按照要求进行排序,按照递增或递减排序起来

稳定性:就是比如排序中有两个相同的数,如果排序后,这两个相同的数相对位置不变,这说明是稳定的,反之不稳定
在这里插入图片描述

插⼊排序

思想:就是将一个后面未排序的数,从后向前面有序的数进行扫描,找到对应为止插入,就像平时玩扑克牌一样
在这里插入图片描述

1.遍历整个数组,定义一个临时遍历tem存储当前要排序的值的值
2.当前元素与其前面元素进行比较
如果当前值大于tem就将这个值向后移动,反之就找到了退出,将该下标后面的值赋值为tem,array[ j + 1] = tem

public class Test {public static void main(String[] args) {int[] array = {3,1,2,3,4};insertSort(array);System.out.println(Arrays.toString(array));}//快速排序public static void insertSort(int[] array){for (int i = 1; i < array.length; i++) {int tem = array[i];int j = i-1;for (; j >=0 ; j--) {//如果存在下标j的值大于tem//就将这个值向后移动if(array[j]>tem){array[j+1] = array[j];}else {break;}}//最后将找到的j的后面那个值赋值给temarray[j+1] = tem;}}
}

运行结果如下
在这里插入图片描述

时间复杂度:O(N^2) ,因为这里最慢是1+2+3……+n,求和 n(n+1) / 2
空间复杂度:O(1),这里就多开辟了tem
稳定性:稳定,这里再遇到<=tem就会退出循环,所以说遇到相同的并不会改变位置
并且可以发现如果元素集合越接近有序,其方式更高效

希尔排序

希尔排序(Shell Sort)是插入排序的一种改进版本
思想:它通过将待排序的列表分成若干子列表,对每个子列表进行插入排序,逐步缩小子列表的间隔,最终完成整个序列的排序

1.先选择增量序列:选择gap,用于将其分为若干子序列,经常就是采用(n / 2 ,n/4……1)
2 .分组进行插入排序,逐渐的缩小增量,直到增量为1,在对整个序列进行一次插入排序,就完成排序了

在这里插入图片描述
在这里插入图片描述

public class Test {public static void main(String[] args) {int[] array = {3,1,2,3,4};shellSort(array);System.out.println(Arrays.toString(array));}public static void shellSort(int[] array){int gap = array.length;//先进行分组进行插入排序while(gap>1){gap = gap/2;//确定分几组shell(array,gap);}}public  static void shell(int[] array,int gap){for (int i = gap; i < array.length; i++) {//根据组进行排序int tem = array[i];int j = i-gap;for (; j >=0 ; j-=gap) {//如果存在下标j的值大于tem//就将这个值向后移动if(array[j]>tem){array[j+gap] = array[j];}else {break;}}array[j+gap] = tem;}}
}

运行结果如下
在这里插入图片描述

希尔排序是直接插入排序的一种优化
稳定性:不稳定
时间复杂度:O(N) ~ O(N ^ 2)
空间复杂度:O(1)

直接选择排序

思想:每次从待排序数据元素中找到最小或最大的一个元素,放在待排序的起始位置,直到全部都排完
实现:遍历整个待排序列,记录当前下标i,再遍历其后面的元素,判断是否有比它小的,如果有记录当前下标,然后进行交换
在这里插入图片描述

public class Test {public static void main(String[] args) {int[] array = {3,1,2,3,4};selectSort(array);System.out.println(Arrays.toString(array));}//选择排序public static void selectSort(int[] array){for (int i = 0; i < array.length; i++) {int minIndex = i;for (int j = i+1; j <array.length ; j++) {if(array[j]<array[minIndex]){//记录最小元素下标minIndex=j;}}//进行交换swap(array,i,minIndex);}}public static void swap(int[] array,int i,int j){int tem = array[i];array[i] = array[j];array[j] = tem;}
}

在这里插入图片描述

时间复杂度:O(N^2)
空间复杂度:O(1)
稳定性:不稳定

堆排序

思想:就是利用堆这种数据结构进行排序
大根堆:用于排升序序列
小根堆:用于排降序序列
在这里插入图片描述

思路:以排升序为例
1.先将其数组创建为大根堆
2.定义一个end表示最后一个元素下标,每次堆顶元素都是最大的,将堆顶元素和堆底元素交换,将end–,相当于将堆底元素删除,这时就还要重新向下调整为大根堆
3.直到end为0的时候截止

public class Test {public static void main(String[] args) {int[] array = {3,1,2,3,4};heapSort(array);System.out.println(Arrays.toString(array));}//堆排序//从小到大,就使用大堆,每次把最后一个元素确定public static void heapSort(int[] array){//创建大根堆creatHeap(array);//每次将最后一个与第一个交换int end = array.length-1;while(end>0){swap(array,0,end);siftDown(array,0,end);//去掉最后一个从新排序end--;}}//建立大根堆堆private static void creatHeap(int[] array) {//从最下面的父亲节点开始调整for (int parent = (array.length-1-1)/2; parent >=0 ; parent--) {siftDown(array,parent,array.length);}}//向下调整private static void siftDown(int[] array, int parent, int length) {int child = 2*parent+1;while (child<length){if(child+1<length&&array[child]<array[child+1]){child++;}if(array[child]>array[parent]){swap(array,child,parent);parent = child;child = 2*parent+1;}else{break;}}}public static void swap(int[] array,int i,int j){int tem = array[i];array[i] = array[j];array[j] = tem;}
}

在这里插入图片描述

时间复杂度:O(N*logN),调整堆O(logN),需要遍历整个数组,每次可能都要调整堆
空间复杂度:O(1)
稳定性:不稳定

冒泡排序

冒泡排序(Bubble Sort)是一种简单的排序算法,它通过重复地遍历待排序的列表,比较相邻的元素并交换它们的位置来实现排序。每遍历一次就确定一个最后一个元素
在这里插入图片描述

public class Test {public static void main(String[] args) {int[] array = {3,1,2,3,4};bubberSort(array);System.out.println(Arrays.toString(array));}public static void bubberSort(int[] array){//外层确定比较几趟/for (int i = 0; i < array.length-1; i++) {//内层确定每趟比较次数for (int j = 0; j < array.length-i-1; j++) {if(array[j]>array[j+1]){int tem = array[j];array[j] = array[j+1];array[j+1] = tem;}}}}
}

快速排序

快速排序(Quick Sort)是一种高效的排序算法,使用的是分治法的思想
就是找到一个基准值,将列表分为两部分,左边一部分是小于基准值,右边一部分是大于基准值,分别在此基准值的左边和右边,重复同样的操作
因此这里可以是使用递归来写的

1.通常以第一个为基准值,然后进行调整左右
2.递归其这个基准值下标左边 和 右边 ,直到左边下标>=右边下标就结束递归
3.这里找到基准值使用Hoare方法来来进行调整,就是high下标先从右向左找到比基准值小的值,low下标从左向右找到比基准值大的值,进行交换,low >= high ,就说明结束了,将此时的low下标与基准值进行交换

public class Test {public static void main(String[] args) {int[] array = {3,1,2,11,4};QuickSort(array);System.out.println(Arrays.toString(array));}//快速排序public static void QuickSort(int[] array){Quick(array, 0, array.length-1);}public static void Quick(int[] array,int left,int right){//截止条件if(left>=right){return;}//递归,先将其以key为界限分为两组//key左右两边又可以分组int key = Hoare(array,left,right);Quick(array,left,key-1);//递归左边Quick(array,key+1,right);//递归右边}//调整基准值位置,并返回其下标private static int Hoare(int[] array, int low, int high) {int i = low;int tem = array[low];while (low<high){//1.后面找到比前面基准值小的while (low<high&&array[high]>=tem){high--;}//2.从前面找比基准值大的while (low<high&&array[low]<=tem){low++;}//2.交换swap(array,low,high);}//与基准值进行交换swap(array,i,low);return low;}public static void swap(int[] array,int i,int j){int tem = array[i];array[i] = array[j];array[j] = tem;}
}

上面是使用的是Hoare方法来调整其列表
在这里插入图片描述
当然这里也可以使用挖坑法
挖坑法:就是先定义一个临时变量来存放我们的基准值
1.先从后向前找high下标一个小于临时变量的值,将这个值放入放入low下标
2.从前向后找low下标一个大于临时变量的值,将这个值放入high下标地方
重复操作,直到low>=high就结束,最后将low下标的值修改为tem基准值

这里调整基准值方法不仅可以使用Hoare方法,这里也可以使用挖坑法
1.先将基准值拿出来
2.先从后向左找一个小于基准值的值放入坑中,此时该位置就便相当于为坑
3.在从左向右找一个大于基准值的值放入坑中, 此时该位置就便相当于为坑

在这里插入图片描述

//挖坑法private static int parttion(int[] array,int low,int high){int tem =array[low];while (low<high){while (low<high&&array[high]>=tem){high--;}array[low] = array[high];while (low<high&&array[low]<=tem){low++;}array[high] = array[low];}array[low] = tem;return low;}

快速排序优化:三数取中
比如序列:1 2 3 4进行快速排序,这样会使其时间复杂度为N^2,因为其快速排序像构建二叉树一样,这样会浪费时间,因此可以使用一个方法
将low 、mid 和 high下标的值其中最中间的值作为基准值

在这里插入图片描述
上面找基准值就是找其第一个元素,但有时候第一个元素并不是最好的,所以可以找第一个、中间、最后一个其中中间的值,作为基准值这样更合理

//这里利用三数取中,获取其三个钟最中间元素的下标private static int mid(int[] array, int low, int high) {int mid = (low+high)/2;if(array[low]<array[high]){if(array[mid]<array[low]){return low;}else if(array[mid]>array[high]){return high;}else {return mid;}}else{if(array[mid]<array[high]){return high;}else if(array[mid]>array[low]){return low;}else {return mid;}}}

时间复杂度:O(N * log N) ~ O (N ^2),因为每次进行基准值调整就像在构建一颗完全二叉树,构建数的复杂度为log N
这里又要重复N次 ,但是如果其数列有序的话,时间复杂度可能为O (N ^2)
空间复杂度:O(log N),因为底层就像一颗二叉树
稳定性:不稳定

快速排序非递归形式
这里采用非递归,但是还是要使用挖坑法或者Hoare 方法进行基准值调整
这里是使用stack进行操作,这里如果符合条件就将其下标入栈,缩小其基准值调整范围,一部分一部分调整,不断的将下标入栈和出栈操作,当栈为空的时候就结束了

在这里插入图片描述

在这里插入图片描述

public class Test {public static void main(String[] args) {int[] array = {3,1,2,11,99,33,22,11,4,7,8};quickSortNor(array);System.out.println(Arrays.toString(array));}//快速排序非递归public static void quickSortNor(int[] array) {int start = 0;int end = array.length-1;int par = parttion(array,0,end);Stack<Integer> stack = new Stack<>();if(par>start+1){stack.push(start);stack.push(par-1);}if(par<end-1){stack.push(par+1);stack.push(end);}while (!stack.isEmpty()){end = stack.pop();start = stack.pop();par = parttion(array,start,end);if(par>start+1){stack.push(start);stack.push(par-1);}if(par<end-1){stack.push(par+1);stack.push(end);}}}private static int parttion(int[] array,int low,int high){int tem =array[low];while (low<high){while (low<high&&array[high]>=tem){high--;}array[low] = array[high];while (low<high&&array[low]<=tem){low++;}array[high] = array[low];}array[low] = tem;return low;}
}

运行结果如下
在这里插入图片描述

归并排序

归并排序(Merge sort)就是采用分治法将其分为子序列,先将子序列变为有序,在将子序列归并进行排序,最终整体就有序了

在这里插入图片描述
就是分解合并两个操作
先将其分解到不能分解,合并过程中并且注意合并成是有序的数列,就这样一直和并子序列,最后整体的序列就有序了
在这里插入图片描述

public class Test {public static void main(String[] args) {int[] array = {3,1,2,11,4,7,8};mergeSort(array);System.out.println(Arrays.toString(array));}//归并排序public static void mergeSort(int[] array){mergeSortChild(array,0,array.length-1);}//使用递归实现private static void mergeSortChild(int[] array, int left, int right) {if(left>=right){return;}//每次将其分为两部分进行排序int mid = (left+right)/2;//递归左边mergeSortChild(array,left,mid);//递归右边mergeSortChild(array,mid+1,right);//合并merge(array,left,mid,right);}//合并private static void merge(int[] array,int left,int mid,int right){int tem[] = new int[right-left+1];int k = 0;int s1 = left;int e1 = mid;int s2 = mid+1;int e2 = right;//将这两个合并成一个有序数组while (s1<=e1&&s2<=e2){if(array[s1]<=array[s2]){tem[k++] = array[s1++];}else {tem[k++] = array[s2++];}}//最后将另一个没有放进去的放进去while (s1<=e1){tem[k++] = array[s1++];}while (s2<=e2){tem[k++] = array[s2++];}//最后将这个合并好的放入array数组中for (int i = 0;i<tem.length;i++){array[i+left] = tem[i];}}
}

运行结果如下
在这里插入图片描述

时间复杂度:O(N*log N),和快速排序一样
空间复杂度:O(N)
稳定性能:稳定

计数排序

上面的排序都是不断的进行比较移动进行排序,而计数排序是非比较型
1.他就是通过数组下标来存放对应的值,如果这个值和某个下标相同就将该下标的对应的值++,相当于用一个count数组来记录每个数出现的次数放在对应下标上
2. 全部放完以后,循环这个count数组,如果对应count[i] ! = 0 ,说明此下标存放值了,就将下标放入array数组中

注意这里再对应下标存放的时候,可能出现92  -  99这样范围的序列
因此这里再存放的时候下标可以减去最前面的值,下标-92,将这个作为下标
最后取出放入array数组的时候,要加上92

)

public class Test {public static void main(String[] args) {int[] array = {3,1,2,11,4,7,8};countSort(array);System.out.println(Arrays.toString(array));}//计算排序public static void countSort(int[] array){int min = array[0];int max = array[0];//1.获取其最大值和最小值for (int i = 1; i < array.length; i++) {if(array[i]>max){max = array[i];}if(array[i]<min){min = array[i];}}//确定数组长度//在对应下标存放于下标相同的值int range = max - min + 1;int[] count = new int[range];for (int i = 0; i < array.length; i++) {//将array[i]对应的值为count的下标,遇到就++int index = array[i];//这里之所以要减去min,是因为这里可能出现越界问题//如果是92 - 99的值,但是下标并不是这样的,减去最前面的值count[index-min]++;}int k = 0;for (int i = 0; i < count.length; i++) {while (count[i]!=0){//由于前面下标减去一个min,这里要加回来array[k] = i+min;count[i]--;k++;}}}
}

时间复杂度:O(n + k),n是列表长度,k是数据范围
空间复杂度:O(n + k) ,需要额外的计数数组和结果数组

排序方式最好最坏空间复杂度稳定性
冒泡排序O(N^2)O(N^2)O(1)稳定
插入排序O(N)O(N^2)O(1)稳定
选择排序O(N^2)O(N^2)O(1)不稳定
希尔排序O(N)O(N^2)O(1)不稳定
堆排序O(N*logN)O(N*logN)O(1)不稳定
快速排序O(N*logN)O(N^2)O(logN~N)不稳定
归并排序O(N*logN)O(N*logN)O(N)稳定

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

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

相关文章

WPF响应式UI的基础:INotifyPropertyChanged

INotifyPropertyChanged 1 实现基础接口2 CallerMemberName优化3 数据更新触发策略4 高级应用技巧4.1 表达式树优化4.2 性能优化模式4.3 跨平台兼容实现 5 常见错误排查 在WPF的MVVM架构中&#xff0c; INotifyPropertyChanged是实现数据驱动界面的核心机制。本章将深入解析属…

低空城市场景下的多无人机任务规划与动态协调!CoordField:无人机任务分配的智能协调场

作者&#xff1a;Tengchao Zhang 1 ^{1} 1 , Yonglin Tian 2 ^{2} 2 , Fei Lin 1 ^{1} 1, Jun Huang 1 ^{1} 1, Patrik P. Sli 3 ^{3} 3, Rui Qin 2 , 4 ^{2,4} 2,4, and Fei-Yue Wang 5 , 1 ^{5,1} 5,1单位&#xff1a; 1 ^{1} 1澳门科技大学创新工程学院工程科学系&#xff0…

解决Java项目NoProviderFoundException报错

前言 在Java开发中&#xff0c;jakarta.validation.NoProviderFoundException 是一个令人困惑的运行时错误&#xff0c;常因校验框架依赖缺失或版本冲突导致。 问题复现&#xff1a;用户注册校验失败 业务场景 开发一个用户注册功能&#xff0c;要求&#xff1a; 校验邮箱…

重构跨境收益互换价值链:新一代TRS平台的破局之道

当香港券商面对内地汹涌的结构化产品需求&#xff0c;一套智能化的TRS系统正成为打开万亿市场的金钥匙 在跨境金融的暗流涌动中&#xff0c;一家中资背景的香港券商正面临甜蜜的烦恼&#xff1a;内地高净值客户对港股、美股的杠杆交易需求激增&#xff0c;但传统TRS业务深陷操作…

实验设计如何拯救我的 CEI VSR 28G 设计

为了确定总体设计裕量&#xff0c;CEI 28G VSR/100 Gb 以太网设计需要分析 500 万种通道变化、收发器工艺和均衡设置的组合。蛮力模拟需要 278 天&#xff0c;这显然超出了可用的时间表。 相反&#xff0c;我们使用实验设计 &#xff08;DOE&#xff09; 和响应面建模 &#x…

【仿生机器人】刀剑神域——爱丽丝苏醒计划,需求文档

仿生机器人"爱丽丝"系统架构设计需求文档 一、硬件基础 已完成头部和颈部硬件搭建 25个舵机驱动表情系统 颈部旋转功能 眼部摄像头&#xff08;视觉输入&#xff09; 麦克风阵列&#xff08;听觉输入&#xff09; 颈部发声装置&#xff08;语音输出&#xff09…

【Day44】

DAY 44 预训练模型 知识点回顾&#xff1a; 预训练的概念常见的分类预训练模型图像预训练模型的发展史预训练的策略预训练代码实战&#xff1a;resnet18 作业&#xff1a; 尝试在cifar10对比如下其他的预训练模型&#xff0c;观察差异&#xff0c;尽可能和他人选择的不同尝试通…

python打卡训练营打卡记录day44

知识点回顾&#xff1a; 预训练的概念常见的分类预训练模型图像预训练模型的发展史预训练的策略预训练代码实战&#xff1a;resnet18 作业&#xff1a; 尝试在cifar10对比如下其他的预训练模型&#xff0c;观察差异&#xff0c;尽可能和他人选择的不同尝试通过ctrl进入resnet的…

Vue跨层级通信

下面,我们来系统的梳理关于 Vue跨层级通信 的基本知识点: 一、跨层级通信核心概念 1.1 什么是跨层级通信 跨层级通信是指在组件树中,祖先组件与后代组件(非直接父子关系)之间的数据传递和交互方式。这种通信模式避免了通过中间组件层层传递 props 的繁琐过程。 1.2 适用…

webPack基本使用步骤

webPack基本使用步骤 关于webPackwebPack配置的几个概念entry&#xff08;入口&#xff09;output&#xff08;输出&#xff09;loader&#xff08;输出&#xff09;plugin&#xff08;插件&#xff09;mode&#xff08;模式&#xff09; 基本使用过程示例1.创建测试目录和代码…

龙虎榜——20250604

上证指数缩量收阳线&#xff0c;量能依然在5天线上&#xff0c;股价也在5天线上。 深证指数放量收阳线&#xff0c;量能站上5天均线&#xff0c;但仍受中期60天均线压制。 2025年6月4日龙虎榜行业方向分析 1. 黄金 代表标的&#xff1a;曼卡龙、菜百股份。 驱动逻辑&#…

Viggle:开启视频人物替换新纪元

Viggle 的出现&#xff0c;为视频人物替换带来了前所未有的变革&#xff0c;为创作者和爱好者们打开了一扇通往无限可能的大门。 一、Viggle 技术原理剖析 Viggle 是一款基于先进人工智能技术的创新平台&#xff0c;其核心在于能够精准实现静态图片与动态视频的融合转化。它…

【BUG解决】关于BigDecimal与0的比较问题

这是一个很细小的知识点&#xff0c;但是很容易被忽略掉&#xff0c;导致系统问题&#xff0c;因此记录下来 问题背景 明明逻辑上看a和b都不为0才会调用除法&#xff0c;但是系统会报错&#xff1a;java.lang.ArithmeticException异常&#xff1a; if (!a.equals(BigDecimal…

千年之后再出发,铜官窑驶入微短剧的数字航道

过去一年里&#xff0c;微短剧已经成为走向全民关注、平台扶持、政策引导的“内容新主流”。从市值百亿的爆款平台到走出国门的“短剧出海”&#xff0c;微短剧正在重塑中国数字文化的表达方式与产业结构&#xff0c;也成为各地竞相争夺的“新蓝海”。 就在这样的背景下&#…

数据库管理-第333期 Oracle 23ai:RAC打补丁完全不用停机(20250604)

数据库管理333期 2025-06-04 数据库管理-第333期 Oracle 23ai&#xff1a;RAC打补丁完全不用停机&#xff08;20250604&#xff09;1 概念2 要求3 操作流程4 转移失败处理总结 数据库管理-第333期 Oracle 23ai&#xff1a;RAC打补丁完全不用停机&#xff08;20250604&#xff0…

Trae CN IDE自动生成注释功能测试与效率提升全解析

Trae CN IDE 的自动注释功能可以通过 AI 驱动的代码分析生成自然语言注释&#xff0c;以下是具体测试方法和优势总结&#xff1a; 一、Python 代码注释生成测试 1. 测试环境 IDE&#xff1a;Trae CN IDE&#xff08;需确认支持 Python&#xff09;代码示例&#xff1a; def …

软考 系统架构设计师系列知识点之杂项集萃(79)

接前一篇文章&#xff1a;软考 系统架构设计师系列知识点之杂项集萃&#xff08;78&#xff09; 第141题 软件测试一般分为两个大类&#xff1a;动态测试和静态测试。前者通过运行程序发现错误&#xff0c;包括&#xff08;&#xff09;等方法&#xff1b;后者采用人工和计算机…

有公网ip但外网访问不到怎么办?内网IP端口映射公网连接常见问题和原因

有公网IP但外网访问不到的核心原因通常包括&#xff1a;端口未正确映射、防火墙限制、DNS解析问题、运营商端口屏蔽或路由配置错误‌。需依次排查这些关键环节&#xff0c;其中端口映射和防火墙设置是最常见的原因。‌‌ ‌内网IP端口映射公网连接常见问题和原因及解决方案 1…

HttpServletResponse 对象用来做什么?

HttpServletResponse 对象是由 Servlet 容器创建并传递给 Servlet 的 service() 方法&#xff08;以及间接传递给 doGet(), doPost() 等方法&#xff09;的。它的核心作用是让 Servlet 能够向客户端&#xff08;通常是浏览器&#xff09;发送 HTTP 响应。 通过 HttpServletRes…

FTPS、HTTPS、SMTPS以及WebSockets over TLS的概念及其应用场景

一、什么是FTPS&#xff1f; FTPS&#xff0c;英文全称File Transfer Protocol with support for Transport Layer Security (SSL/TLS)&#xff0c;安全文件传输协议&#xff0c;是一种对常用的文件传输协议(FTP)添加传输层安全(TLS)和安全套接层(SSL)加密协议支持的扩展协议。…