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

java冒泡排序 常规排序和优化排序

冒泡排序原理在于两两比较,看你需要把大值放最前面还是最后面,

我们看看把大值放在后面:比如数组[7, 5, 6]

开始排序第1个数字 :7 arr:[7, 5, 6]


开始排序第2个数字 :5 arr:[7, 5, 6]
 第1次 比较<5>和<7> -----5<7:true  交换位置


开始排序第3个数字 :6 arr:[5, 7, 6]
 第2次 比较<6>和<5> -----6<5:false
 第3次 比较<6>和<7> -----6<7:true 交换位置


已排序:[5, 6, 7]

 

代码:

 public static void sort(Integer[] arr){
        int num=1;
        for (int i=0;i<arr.length;i++){
            System.out.print("\n第"+(i+1)+"次排序开始排序第"+(i+1)+"个数字:"+arr[i] +" arr:"+Arrays.toString(arr));
            
            for (int j=0;j<i;j++){
                System.out.print("\n 第"+num+"次 比较<"+arr[i]+">和<"+arr[j]+"> -----"+arr[i]+"<"+arr[j]+":"+(arr[i]<arr[j]));
                if(arr[i]<arr[j]){
                    exchange(arr,i,j);
                }
                num++;
            }
        }
        System.out.print("\n已排序:"+Arrays.toString(arr));
    }


    public static void exchange(Integer[] arr, int i, int j){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
public static void main(String[] args){

        //Integer[] arr=new Integer[]{70,40,90,20,50,10,60,30,80};
        //Integer[] arr=new Integer[]{70,40,90,60,30,80};
        Integer[] arr=new Integer[]{7,5,6};
        //原始排序比较36次
        sort(arr);
    }

我们改一个长一点的数字排序试下

开始排序第1个数字 :70 arr:[70, 40, 90, 60, 30, 80]


开始排序第2个数字 :40 arr:[70, 40, 90, 60, 30, 80]
 第1次 比较<40>和<70> -----40<70:true


开始排序第3个数字 :90 arr:[40, 70, 90, 60, 30, 80]
 第2次 比较<90>和<40> -----90<40:false
 第3次 比较<90>和<70> -----90<70:false


开始排序第4个数字 :60 arr:[40, 70, 90, 60, 30, 80]
 第4次 比较<60>和<40> -----60<40:false
 第5次 比较<60>和<70> -----60<70:true
 第6次 比较<70>和<90> -----70<90:true


开始排序第5个数字 :30 arr:[40, 60, 70, 90, 30, 80]
 第7次 比较<30>和<40> -----30<40:true
 第8次 比较<40>和<60> -----40<60:true
 第9次 比较<60>和<70> -----60<70:true
 第10次 比较<70>和<90> -----70<90:true


开始排序第6个数字 :80 arr:[30, 40, 60, 70, 90, 80]
 第11次 比较<80>和<30> -----80<30:false
 第12次 比较<80>和<40> -----80<40:false
 第13次 比较<80>和<60> -----80<60:false
 第14次 比较<80>和<70> -----80<70:false
 第15次 比较<80>和<90> -----80<90:true


已排序:[30, 40, 60, 70, 80, 90]

乱序情况下我们总共比较15次,其中有很多比较是没有用的,比如下图

第11次到14次其实是不需要排序的,我们是否可以针对优化呢,

我们看下同样的数组如果完全反序要多少次比较

开始排序第1个数字 :30 arr:[30, 40, 60, 70, 80, 90]
开始排序第2个数字 :40 arr:[30, 40, 60, 70, 80, 90]
 第1次 比较<40>和<30> -----40<30:false
开始排序第3个数字 :60 arr:[30, 40, 60, 70, 80, 90]
 第2次 比较<60>和<30> -----60<30:false
 第3次 比较<60>和<40> -----60<40:false
开始排序第4个数字 :70 arr:[30, 40, 60, 70, 80, 90]
 第4次 比较<70>和<30> -----70<30:false
 第5次 比较<70>和<40> -----70<40:false
 第6次 比较<70>和<60> -----70<60:false
开始排序第5个数字 :80 arr:[30, 40, 60, 70, 80, 90]
 第7次 比较<80>和<30> -----80<30:false
 第8次 比较<80>和<40> -----80<40:false
 第9次 比较<80>和<60> -----80<60:false
 第10次 比较<80>和<70> -----80<70:false
开始排序第6个数字 :90 arr:[30, 40, 60, 70, 80, 90]
 第11次 比较<90>和<30> -----90<30:false
 第12次 比较<90>和<40> -----90<40:false
 第13次 比较<90>和<60> -----90<60:false
 第14次 比较<90>和<70> -----90<70:false
 第15次 比较<90>和<80> -----90<80:false
已排序:[30, 40, 60, 70, 80, 90]

同样的代码,已经排好序的情况下还是会比较15次,我们优化一下,首先看如下优化之后的比较结果:

 排序:30 原始数据arr:[30, 40, 60, 70, 80, 90]--最小值不用排序
 排序:40 原始数据arr:[30, 40, 60, 70, 80, 90]--只有两位数,而且40大于30不用排序
 排序:60 原始数据arr:[30, 40, 60, 70, 80, 90]--
 排序:70 原始数据arr:[30, 40, 60, 70, 80, 90]--
 排序:80 原始数据arr:[30, 40, 60, 70, 80, 90]--
 排序:90 原始数据arr:[30, 40, 60, 70, 80, 90]--
已排序:[30, 40, 60, 70, 80, 90]

 下面是优化后的代码,看上去比较复杂,可以跟着注释自己跑一下,主要是加了一个中间值去比较,没有每次都比较所有的值

已经排好序的情况下我只用了直接在外部判断没有进二层循环

 
  
 public static void dichotomy(Integer[] arr){
        int num=1;
        for (int i=0;i<arr.length;i++){
       //取中间值,取模,不等于0就加一除2,索引2的中间值是1,3%2!=0所以3+1=4,4%2=0,4的中间数4除2等于2
int mid =(i%2==0)?i/2:(i+1)/2;
System.out.print(
"\n 排序:"+arr[i] +" 原始数据arr:"+Arrays.toString(arr)); if((i>=1 && arr[i]>arr[i-1]) || i<1){ System.out.print("--最小值不用排序"); continue; } boolean booI=true; //小于中间数 if(arr[i]<arr[mid ] && booI){ for (int j=mid ;j<i;j++){ System.out.print("\n 第"+num+"次 开始排序第"+(i+1)+"个数字 "+arr[i]+" 小于中间数"+arr[mid ]+" 比较<"+arr[i]+">和<"+arr[j]+"> -----"+arr[i]+"<"+arr[j]+":"+(arr[i]<arr[j])); //直接挪到中间,booI等于false说明现在这个值只是挪到中间,下一步还是要挪一次
              
if(arr[i]<arr[j]){ exchange(arr,i,j); booI=false; } num++; } }else //大于中间数 if(arr[i]>arr[mid] && booI){ for (int j=i;j>mid ;j--){ System.out.print("\n 第"+num+"次 大于中间数"+arr[mid]+" 比较<"+arr[j]+">和<"+arr[j-1]+"> -----"+arr[j]+"<"+arr[j-1]+":"+(arr[j]<arr[j-1])); //大于中间数从当前往前挪
              
if(arr[j]<arr[j-1]){ exchange(arr,j,j-1); }else break; num++; } }
      //挪到中间的值再进行比较,取最优的比较方案

       //中间值小于第一位说明是最小值,并且 booI=false已经被挪到中间,现在要挪到最前面
if(arr[0]>arr[mid] && !booI){ for (int j=0;j<mid;j++){ System.out.print("\n 第"+num+"次 小于中间数并且是最小值"+arr[mid]+" 比较<"+arr[mid]+">和<"+arr[j]+"> -----"+arr[mid]+"<"+arr[j]+":"+(arr[mid]<arr[j])); if(arr[mid]<arr[j]){ exchange(arr,j,mid); } num++; } }else
          // booI=false已经被挪到中间,又不是最小值,所以就从中间值前一位开始比较
          if(arr[mid-1]>arr[mid] && !booI){ for (int j=mid;j>0;j--){ System.out.print("\n 第"+num+"次 小于中间数靠近中间数取"+arr[mid]+"前一位比较<"+arr[j]+">和<"+arr[j-1]+"> -----"+arr[j]+"<"+arr[j-1]+":"+(arr[j]<arr[j-1]));
              //当当前值小于则挪,不小于则跳出循环,因为之前比较过小值前面是已经排好序的,遇到不小于的值就可以跳出循环不用比较了,直接跳出开始下一次循环
              if(arr[j]<arr[j-1]){ exchange(arr,j-1,j); }else break; num++; } } } System.out.print("\n已排序:"+Arrays.toString(arr)); }

改了中间一个值执行结果排序四次比原来少了十一次

改用原始数据的数组,排序9次比原来少了6次

 

 

我在代码中加上了很多不需要判断就跳出循环的操作。

可以看上图代码,思路是这样的,我取中间值进行排序,小于中间数就直接挪过去(挪到中间数),当大于中间数的就近(n-1)开始挪,

后面一个步骤就是把挪到中间的值再进行一次比较,如果是最小值就直接挪到第一位,如果不是就从中间值的前一位开始比较。

代码中有比较清楚的注释,暂时只想到这么去优化,欢迎讨论。自己可以用长一点的数组测试一样

 

转载于:https://www.cnblogs.com/theone-unicorn/p/10649077.html

相关文章:

  • Chef宣布100%开源,要走红帽模式?\n
  • Go语言入门之指针的使用
  • Oracle redo解析之-4、rowid的计算
  • D语言/DLang 2.085.1 发布,修复性迭代
  • D3.js入门
  • 数据结构中的各种树简单解释
  • 世界冠军之路:菜鸟车辆路径规划求解引擎研发历程
  • shiro app
  • 控制台报错 index:0,size:0
  • 14Linux_BIND-Linux就该这么学
  • WordPress 5.2 Beta 3 发布,要求 PHP 5.6.20 以上版本
  • springboot 2 Hikari 多数据源配置问题(dataSourceClassName or jdbcUrl is required)
  • JAVA 多用户商城系统b2b2c-Spring Cloud Stream 介绍
  • 实现Kubernetes跨集群服务应用的高可用
  • scss rem 转换函数
  • 【翻译】Mashape是如何管理15000个API和微服务的(三)
  • 5、React组件事件详解
  • 8年软件测试工程师感悟——写给还在迷茫中的朋友
  • Apache Zeppelin在Apache Trafodion上的可视化
  • Debian下无root权限使用Python访问Oracle
  • docker容器内的网络抓包
  • Kibana配置logstash,报表一体化
  • PHP 程序员也能做的 Java 开发 30分钟使用 netty 轻松打造一个高性能 websocket 服务...
  • PHP那些事儿
  • 百度贴吧爬虫node+vue baidu_tieba_crawler
  • 持续集成与持续部署宝典Part 2:创建持续集成流水线
  • 更好理解的面向对象的Javascript 1 —— 动态类型和多态
  • 人脸识别最新开发经验demo
  • 入门级的git使用指北
  • 使用docker-compose进行多节点部署
  • 微信端页面使用-webkit-box和绝对定位时,元素上移的问题
  • 移动互联网+智能运营体系搭建=你家有金矿啊!
  • media数据库操作,可以进行增删改查,实现回收站,隐私照片功能 SharedPreferences存储地址:
  • No resource identifier found for attribute,RxJava之zip操作符
  • # 手柄编程_北通阿修罗3动手评:一款兼具功能、操控性的电竞手柄
  • #宝哥教你#查看jquery绑定的事件函数
  • $con= MySQL有关填空题_2015年计算机二级考试《MySQL》提高练习题(10)
  • (1)SpringCloud 整合Python
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (Matlab)使用竞争神经网络实现数据聚类
  • (Redis使用系列) Springboot 实现Redis 同数据源动态切换db 八
  • (ZT)薛涌:谈贫说富
  • (免费分享)基于springboot,vue疗养中心管理系统
  • (三)Honghu Cloud云架构一定时调度平台
  • (学习日记)2024.03.25:UCOSIII第二十二节:系统启动流程详解
  • (转)IOS中获取各种文件的目录路径的方法
  • (转)平衡树
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .NET Windows:删除文件夹后立即判断,有可能依然存在
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .net 发送邮件
  • .net 桌面开发 运行一阵子就自动关闭_聊城旋转门家用价格大约是多少,全自动旋转门,期待合作...
  • .NetCore Flurl.Http 升级到4.0后 https 无法建立SSL连接
  • .NET开发人员必知的八个网站
  • @ModelAttribute使用详解