JAVA排序

目录

再看各种排序前我们先了解一下什么叫 稳定性

插入排序:

希尔排序:(插入排序的优化)

测试插入排序和希尔排序(插入排序的优化)排序时间对比

选择排序:

选择排序的优化:

正确的 选择排序优化

快速排序(挖坑法:未优化)

快速排序的优化1

快速排序优化2

优化快速排序需要注意的点

使用双指针法进行快速排序

堆排序

再看各种排序前我们先了解一下什么叫 稳定性

比如一组数据arr[i]下标与arr[j下标]相等,arr[i]在前面,arr[j]在arr[i]后面,排序后这两个数据仍然是arr[i]在arr[j]前面,arr[j]在arr[i]后面,这就叫稳定

插入排序:

优势:  越有序查找速度越快

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

空间复杂度:  O(1)

稳定性:稳定

public void insertSort(int[] arr){//i负责引路,j负责把i后面的数据都变得有序for(int i = 1; i < arr.length; i++){for(int j = i - 1; j >= 0; j--){//想想为什么不是arr[j] > arr[i]:因为j会变化if(arr[j] > arr[j+1]){//交换int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}else{break;}}}}

希尔排序:(插入排序的优化)

将所有数据进行分组,先分成许多组,这样每组数据就会变少,在将组的数据排序,

即使时间复杂度是O(N^2)也没事,因为数据少,就算N的平方也没多少

然后逐渐减少组的数量每组的数据就会变多,但数据越趋近有序,所以查找速度越快(因为插入排序数据越趋于有序查找速度越快)

最后让 insertSort(arr,1)是为了确保让 希尔排序 排序成功

 public void xiErSort(int[] arr){int len = arr.length;//为什么不是while(len >= 0)呢? 反例: len为2时:2 = 2 / 2;会死循环//并且len > 0 说明while(len > 0){//对数据进行分组len = len / 2;//对分组后的数据进行插入排序insertSort(arr,len);}//保证 希尔排序 是有序的insertSort(arr,1);}private void insertSort(int[] arr,int len){for(int i = len; i < arr.length; i++){for(int j = i - len; j >= 0; j = j - len){if(arr[j] > arr[j+len]){//交换int tmp = arr[j];arr[j] = arr[j+len];arr[j+len] = tmp;}else{break;}}}}

问个问题:为何 xiEr方法里的最后要加一段insertSort(arr,1)?

答:为了让希尔排序是彻彻底底有序的,这样虽然看起来和插入排序一样,但因为经过前面的代码数据已经趋于有序,所以最后加个插入排序其实时间复杂度也不高

测试插入排序和希尔排序(插入排序的优化)排序时间对比

可以看到希尔排序比插入排序快很多

选择排序:

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

空间复杂度:  O(1)

稳定性:  不稳定

思路:找到数组里的最小值和最左边i下标交换,如何i++,继续找i后面的最小值然后和i交换,这样就能从小到大排序了

 //选择排序public void selectSort(int[] arr){int i = 0;for(i = 0; i < arr.length; i++){int min = i;for(int j = i+1; j < arr.length; j++){//找到数组中最小的数据对应 下标minif(arr[j] < arr[min]){min = j;}}//找到最小值min和数组i下标交换数据int tmp = arr[min];arr[min] = arr[i];arr[i] = tmp;}

问个问题:为什么min不写在这里?

原因是为了让min变量不断变化将数组里的最小值按从小到大顺序排好,放在箭头所指位置就不变化了,也就是说只能将数据放在相同的位置不动

选择排序的优化:

之前是找到最小值就换位置,那我能不能一次找到最小值和最大值再换位置?将最小值换到数据偏左的位置,将最大值放到数据偏右边的位置

为什么呢?原因是 如果 最大值MAX = left的时候就会把原来的最大值下标移到其它下标处(听懂掌声)

正确的 选择排序优化

    //选择排序的优化方案//之前是找到最小值就换位置,那我能不能一次找到最小值和最大值再换位置?将最小值换到数据偏左的位置,将最大值放到数据偏大的位置public void selectSort2(int[] arr){//left放最小,right放最大值int left = 0;int right = arr.length - 1;while(left < right){//用来放最大值和最小值下标int MAX = left;int min = left;//j下标用来找数据for(int j = left + 1; j <= right; j++){//找最大值if(arr[j] > arr[MAX]){MAX = j;}//找最小值if(arr[j] < arr[min]){min = j;}}//最小值和数组left下标交换swap(arr,left,min);//如果最大值MAX在left处的话由于left交换后最大值位置变为min下标了if(MAX == left){MAX = min;}swap(arr,right,MAX);//left++用来找下一个最小数据//right--用来找下一个最大数据right--;left++;}}//用来交换数据位置private void swap(int[] arr,int i,int j){int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}

为什么范围是 j <= right,而不是 j < arr.length()
因为如果判定范围在 j < arr.length() 的话下面的代码就会把
原本在右边放好最大值 重新掉换成错误位置位置

快速排序(挖坑法:未优化)

时间复杂度O(N*logN)

空间复杂度O(logN)

大体上是找到一个 基准点,基准点的左边得数据都比基准点小,基准点的右边数据都比基准点大

然后递归分成左树和右树

  //快速排序(挖坑法:未优化)//为了接口的和其他的一样我们参数就设为int[] arrpublic void quickSort(int[] arr){quickSort_(arr,0,arr.length-1);}public void quickSort_(int[] arr,int left,int right){//为什么是left >= right就结束,而不是left > right呢?//因为当 left == right 就说明 左边或右边只有一个数字呢,一个数字必然是有序的if(left >= right){return;}int index = centreIndex(arr,left,right);//这样 左边 就比基准值index小了, 右边 比基准值大//将数组按基准值的左边划为左树,基准值的右边划分为右树//左边quickSort_(arr,left,index - 1);//右边quickSort_(arr,index+1,right);}//找到基准下标位置public int centreIndex(int[] arr,int left,int right){int tmp = arr[left];while(left < right){//找到右边比基准值小的数while(left < right && arr[right] >= tmp){right--;}//右边遇到比基准值小的,和左边left换位置swap(arr,left,right);//找到左边比基准值大的数while(left < right && arr[left] <= tmp){left++;}//左边遇到比基准值大的,和右边right换位置swap(arr,left,right);}//出到这里说明 left == rightif(left == right){arr[left] = tmp;}return left;}//用来交换数据位置private void swap(int[] arr,int i,int j){int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}

问?为什么红圈圈起来的都使用的是 >=

答:第一处if(left >= right) 中 判断条件是 >= 是因为 当left == right的时候说明在递归到最后left == riight的时候说明 只有一个数字,一个数字不管怎么样都是有序

第二处第三处的while(left < right && arr[left] >= tmp)是为了防止死循环,如果数据像下面数组一样没有>=就死循环了

问:为什么在找基准值方法centreIndex_()里的while(left < right && arr[left] >= tmp)while循环里有while(left < right),原因还是上面那幅图,为了防止数组下标越界

快速排序的优化1

1.为了防止数组里的数据有序而出现单分支的情况,我们会先使用三数取中的方法将数组里的数据打乱,使得数组里的数据无法有序,从而快速排序也不会出现单分支的情况了

光是左树或右树复杂度是最高的

快速排序优化2

1.我们使用快速排序时快到最后发现最后树的节点是最多的,但整体趋近于有序,并且最后一两层就占据了整个数据的60%甚至70%,所以我们可以在快速排序的最后一两层使用 插入排序 的方法来优化, 插入排序的特点就是 数组越有序,插入排序效果越快

  //快速查找(挖坑法:优化1)//优化它是单分支的数据public void quickSort2(int[] arr){quickSort_2(arr,0,arr.length - 1);}private void quickSort_2(int[] arr,int left,int right){if(left >= right){return;}//为了防止出现数组有序而出现的 单分支的情况
//        使用 三数去中法int centreIndex = num(arr,left,right);//swap(arr,0,centreIndex)swap(arr,left,centreIndex);//调换完成就不会出现 数组有序而出现的 单分支 的情况啦//找基准值int index = centreIndex2(arr,left,right);//递归左树 和右树quickSort_2(arr,left,index-1);quickSort_2(arr,index+1,right);}//基准值private int centreIndex2(int[] arr,int left,int right){int tmp = arr[left];while(left < right){while(left < right && arr[right] >= tmp){right--;}swap(arr,left,right);while(left <right && arr[left] <= tmp){left++;}swap(arr,left,right);}// left == rightif(left == right) {arr[left] = tmp;}return left;}//三数去中private int num(int[] arr,int left,int right){//取数组最左边,最右边和中间,取中间大小的值int mid = (left+right) / 2;//将三个数放到数组里int[] arrays = new int[3];arrays[0] = arr[left];arrays[1] = arr[mid];arrays[2] = arr[right];//排序Arrays.sort(arrays);if(arrays[1] == arr[left]){return left;}else if(arrays[1] == arr[mid]){return mid;}return right;}//用来交换数据位置private void swap(int[] arr,int i,int j){int tmp = arr[i];arr[i] = arr[j];arr[j] = tmp;}//挖坑法的优化(插入排序)private void insertSort2(int[] arr,int left,int right){for(int i = left + 1; i <= right; i++){for(int j = i - 1; j >= left; j--){if(arr[j] > arr[j+1]){//第一个比第二个大,交换int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}}

优化快速排序需要注意的点

使用双指针法进行快速排序

思路:和普通快速排序的思路差不多,先找基准值,基准值的左边小于基准值,基准值的右边大于基准值,然后使用递归直到left >= right时结束,双指针快速排序主要与普通快排就是使用了双指针的方法进行找基准值

  public static void double_index(int[] arr){if(arr.length == 0){return;}double_Index(arr,0,arr.length-1);}private static void double_Index(int[] arr, int left, int right) {if(left >= right){return;}//找基准int index = find_Index(arr,left,right);double_Index(arr,left,index - 1);double_Index(arr,index+1,right);}//找基准值private static int find_Index(int[] arr, int left, int right) {int tmp = arr[left];int slow = left;int fast = slow + 1;for(fast = slow + 1; fast <= right; fast++){if(arr[fast] < tmp){slow++;if(slow != fast){swap(arr,slow,fast);}}}swap(arr,left,slow);return slow;}private static void swap(int[] arr, int slow, int fast) {int tmp = arr[slow];arr[slow] = arr[fast];arr[fast] = tmp;}

双指针主要看这几行代码

slow指针永远指向数组里比tmp小的最后一个数据,而fast指针则是数组里找比tmp小的数据

堆排序

先根据数组创建成一个堆

小到大排序就创建成大根堆,从大到小排序就创建成小根堆

创建完堆后就将 堆顶元素 和 堆的末尾元素 调换位置,这样堆顶元素(最大的)就放到最后,然后在将调换的堆顶元素重新建成大根堆,在继续调换,这样就会形成一个从小到大排序的数组

  public static void prioritySort(int[] arr){if(arr.length == 0){return;}//首先先拿这个数组用来创建一个堆//从小到大排序的话就创建 大根堆//从大到小排序的话就创建 小根堆for (int father = (arr.length - 1) / 2; father >= 0; father--) {create(arr,father,arr.length);}int len = arr.length;//排序while(len > 0){//交换int tmp = arr[0];arr[0] = arr[len-1];arr[len-1] = tmp;len--;//重新将换了的堆顶元素变为 大根堆create(arr,0,len);
//            len--;}}//从小到大排序(创建大根堆)private static void create(int[] arr,int father,int len){int child = (father * 2)+1;while(child < len){//找到最大的孩子节点if(child+1 < len && arr[child+1] > arr[child]){child++;}//这样child指向的就是最大的孩子节点了//最大的孩子节点 和 父亲节点比较if(arr[child] > arr[father]){//交换int tmp = arr[father];arr[father] = arr[child];arr[child] = tmp;father = child;child = (father * 2)+1;
//                child = father;
//                father = (child-1)/2;}else{break;}}}

冒泡排序:感觉没什么好讲的这个:一般不会用它

    //冒泡排序(优化)public static void Sort2(int[] arr){for(int i = 0; i < arr.length; i++){boolean judge = false;for(int j = 0; j < arr.length-1-i; j++){if(arr[j] > arr[j+1]){//交换int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;judge = true;}//else {//   break//}}if(!judge){return;}}}

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

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

相关文章

server2012 通过防火墙开启局域网内限定IP进行远程桌面连接

我这里需要被远程桌面的电脑系统版本为windows server2012 1、打开允许远程连接设置 2、开启防火墙 3、设置允许“远程桌面应用”通过防火墙 勾选”远程桌面“ 3、入站规则设置 高级设置→入站规则→远程桌面-用户模式(TCP-In) 进入远程桌面属性的作用域——>远程IP地址—…

实体店做商城小程序如何

互联网电商深入各个行业&#xff0c;传统线下店商家无论产品销售还是服务业&#xff0c;仅靠以往的经营模式&#xff0c;很难拓展到客户&#xff0c;老客流失严重&#xff0c;同时渠道单一&#xff0c;无法实现外地客户购物及线上客户赋能等。 入驻第三方平台有优势但也有不足…

Spring Web MVC入门

一&#xff1a;了解Spring Web MVC (1)关于Java开发 &#x1f31f;Java开发大多数场景是业务开发 比如说京东的业务就是电商卖货、今日头条的业务就推送新闻&#xff1b;快手的业务就是短视频推荐 (2)Spring Web MVC的简单理解 &#x1f497;Spring Web MVC&#xff1a;如何使…

分布估计算法(Estimation of distribution algorithm,EDA)

概论 分布估计算法&#xff08;Estimation of distribution algorithm&#xff0c;EDA&#xff09;是一种新兴的基于统计学原理的随机优化算法。 为什么要叫这个名字呢&#xff1f; 首先&#xff0c;“分布”指的就是概率分布。 其次&#xff0c;“估计”指的是这个概率分布…

通过requests库使用HTTP编写的爬虫程序

使用Python的requests库可以方便地编写HTTP爬虫程序。以下是一个使用requests库的示例&#xff1a; import requests# 发送HTTP GET请求 response requests.get("http://example.com")# 检查响应状态码 if response.status_code 200:# 获取响应内容html response.…

Docker实战之二

一、前言 前一篇 Docker实战之一 我们介绍了Dokcer 镜像和容器基本概念&#xff0c;这一节我们来具体制作一个镜像文件并进行快速部署&#xff0c;这个镜像文件是我们的测试环境&#xff0c;主要包含JDK1.8、Nginx、Git、Node、Gradle&#xff0c;基础镜像为CentOS&#xff0c…

Java练习题2020-3

统计从1到N的整数中,所有立方值的平方根为整数的数的个数 输入说明&#xff1a;整数 N(N<10000)&#xff1b; 输出说明&#xff1a;符合条件的数的个数&#xff0c;如4^3648^2 输入样例&#xff1a;10 输出样例&#xff1a;3 (说明&#xff1a;样例中符合条件的3个数是1、4、…

用低代码平台代替Excel搭建进销存管理系统

目录 一、用低代码平台搭建系统 1.需求调研 2.基于痛点梳理业务流程 3.低代码实现 &#xff08;1&#xff09;基础资料模块 &#xff08;2&#xff09;采购管理模块 &#xff08;3&#xff09;销售管理模块 &#xff08;4&#xff09;库存管理模块 &#xff08;5&…

【点云】有序/无序点云区别(详细详解)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

Windows server部署filebeat到kafka

需求&#xff1a;Windows dhcp日志需要实时传输到elk或者其他告警平台。 1、filebeat下载地址&#xff1a;https://www.elastic.co/cn/downloads/beats/filebeat 2、下载后解压后配置filebeat.yml文件&#xff0c; 3、README.md文件中有运行的操作方法&#xff1a;cmd上进入f…

为什么网上的流量卡都有禁发地区呢?流量卡管控地区整理!

在网上购买过流量卡的朋友应该都知道&#xff0c;但凡是运营商推出的大流量优惠套餐&#xff0c;在套餐详情中都是有禁发地区&#xff0c;只不过每张卡的禁发地区不同而已。 设置禁发地区的主要目的还是为了防止一些电信诈骗案件的发生&#xff0c;或者违法违规利用电话卡的情…

C语言数据结构之数据结构入门

目录 数据结构介绍 数据结构发展史 何为算法 数据结构基础 基本概念和术语 四大逻辑结构&#xff08;Logic Structure&#xff09; 数据类型 理解复杂度概念 时间空间复杂度定义 度量时间复杂度的方法 程序运行时的内存与地址 编程预备 数据结构介绍 数据结构发展…

python:多波段遥感影像分离成单波段影像

作者:CSDN @ _养乐多_ 在遥感图像处理中,我们经常需要将多波段遥感影像拆分成多个单波段图像,以便进行各种分析和后续处理。本篇博客将介绍一个用Python编写的程序,该程序可以读取多波段遥感影像,将其拆分为单波段图像,并保存为单独的文件。本程序使用GDAL库来处理遥感影…

LMFLOSS:专治解决不平衡医学图像分类的新型混合损失函数 (附代码)

论文地址&#xff1a;https://arxiv.org/pdf/2212.12741.pdf 代码地址&#xff1a;https://github.com/SanaNazari/LMFLoss 1.是什么&#xff1f; LMFLOSS是一种用于不平衡医学图像分类的混合损失函数。它是由Focal Loss和LDAM Loss的线性组合构成的&#xff0c;旨在更好地处…

SpringSecurity 认证实战

一. 项目数据准备 1.1 添加依赖 <dependencies><!--spring security--><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><!--web起步依赖-…

语雀故障事件——P0级别事故启示录 发生肾么事了? 怎么回事?

前言 最近&#xff0c;阿里系的语雀出了一个大瓜&#xff0c;知名在线文档编辑与协同工具语雀发生故障&#xff0c;崩溃近10小时。。。。最后&#xff0c;官方发布了一则公告&#xff0c;我们一起来看看这篇公告&#xff0c;能不能有所启发。 目录 前言引出一、语雀P0故障回顾…

重复控制器的性能优化

前言 重复控制器在控制系统中是比较优秀的控制器&#xff0c;在整流逆变等周期性输入信号时&#xff0c;会有很好的跟随行&#xff0c;通常可以单独使用&#xff0c;也可以与其他补偿器串联并联使用。 这里我来分析一下重复控制器的重复控制器的应用工况以及其的优缺点。 分析…

Mybatis-Plus(企业实际开发应用)

一、Mybatis-Plus简介 MyBatis-Plus是MyBatis框架的一个增强工具&#xff0c;可以简化持久层代码开发MyBatis-Plus&#xff08;简称 MP&#xff09;是一个 MyBatis 的增强工具&#xff0c;在 MyBatis 的基础上只做增强不做改变&#xff0c;为简化开发、提高效率而生。 官网&a…

Python深度学习实战-基于class类搭建BP神经网络实现分类任务(附源码和实现效果)

实现功能 上篇文章介绍了用Squential搭建BP神经网络&#xff0c;Squential可以搭建出上层输出就是下层输入的顺序神经网络结构&#xff0c;无法搭出一些带有跳连的非顺序网络结构&#xff0c;这个时候我们可以选择类class搭建封装神经网络结构。 第一步&#xff1a;import ten…