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

我们看看把大值放在后面:比如数组[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)开始挪,

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

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

java冒泡排序 常规排序和优化排序的更多相关文章

  1. PHP处理一个5G文件,使用内存512M的,数据为整形,从大到小排序,优化排序算法

    $file='./new.txt'; $fp = fopen($file, "r"); $chunk = 4096;//一次处理1M的字节 1M=1024*1024 $fs = f ...

  2. 过三关 Java冒泡排序选择排序插入排序小练习

    材料:猴子排序,按照身高来从小到大来排序. 第一关: 老猴子带领小猴子队伍按大小逐一比较,交换,开始高矮排列队伍.(冒泡排序) 第二关: 太慢了,给第一关增加难度,进行选择排序 第三关: 最后,尝试选 ...

  3. java 冒泡排序 二分查找 选择排序 插入排序

    下面这个程序是先定义一个整型数组,然后将其中的元素反序赋值,再用冒泡排序进行排序以后用二分查找来查找其中是否有某个数,返回值为-1时表示这个数可能小于这个数组的最小值或大小这个数组的最大值,-2表示这 ...

  4. 几种常见排序算法之Java实现(插入排序、希尔排序、冒泡排序、快速排序、选择排序、归并排序)

    排序(Sorting) 是计算机程序设计中的一种重要操作,它的功能是将一个数据元素(或记录)的任意序列,重新排列成一个关键字有序的序列. 稳定度(稳定性)一个排序算法是稳定的,就是当有两个相等记录的关 ...

  5. 排序方法整理Java - 冒泡排序、选择排序、插入排序、快速排序

    /** * 排序方法整理 * @author zhyea * */ public class Sort { /** * 冒泡排序,从小到大. * 冒泡排序是比较相邻的两个元素,若顺序错误,则执行交换. ...

  6. 高速排序及优化(Java版)

    高速排序(Quicksort)是对冒泡排序的一种改进. 高速排序由C. A. R. Hoare在1962年提出. 一次高速排序具体过程: 选择数组第一个值作为枢轴值. 代码实现: package Qu ...

  7. 9, java数据结构和算法: 直接插入排序, 希尔排序, 简单选择排序, 堆排序, 冒泡排序,快速排序, 归并排序, 基数排序的分析和代码实现

    内部排序: 就是使用内存空间来排序 外部排序: 就是数据量很大,需要借助外部存储(文件)来排序. 直接上代码: package com.lvcai; public class Sort { publi ...

  8. 排序基础之非比较的计数排序、桶排序、基数排序(Java实现)

    转载请注明原文地址: http://www.cnblogs.com/ygj0930/p/6639353.html  比较和非比较排序 快速排序.归并排序.堆排序.冒泡排序等比较排序,每个数都必须和其他 ...

  9. Java面试宝典系列之基础排序算法

    本文就是介绍一些常见的排序算法.排序是一个非常常见的应用场景,很多时候,我们需要根据自己需要排序的数据类型,来自定义排序算法,但是,在这里,我们只介绍这些基础排序算法,包括:插入排序.选择排序.冒泡排 ...

随机推荐

  1. 关于jboss的线程问题+java.lang.outofmemoryError

    近日来,用Jmeter做压力测试.发现,每台客户机使用800个线程组压力倍增.昨天的测试,到了今天下午都没有跑完. 仔细观察了下Jboss的错误日志,发现,jboss已经宕机了. 本身后台的环境是使用 ...

  2. 3C - Youmu

    (ans & arr[j]) == ans 保证高位已有值不失效. ((ans[j] >> (i - 1)) & 1) == 1 当前位为1,cnt++, cnt > ...

  3. AVFoundation 文本播报

    #import <Foundation/Foundation.h> #import <AVFoundation/AVFoundation.h> @interface Speak ...

  4. feign调用过程注意事项

    Feign是Netflix开发的声明式.模板化的HTTP客户端, Feign可以帮助我们更快捷.优雅地调用HTTP API. 在Spring Cloud中,使用Feign非常简单——创建一个接口,并在 ...

  5. 分布式id生成方法

    系统唯一ID是我们在设计一个系统的时候常常会遇见的问题,也常常为这个问题而纠结.生成ID的方法有很多,适应不同的场景.需求以及性能要求.所以有些比较复杂的系统会有多个ID生成的策略.下面就介绍一些常见 ...

  6. Tomcat 部署项目的几种常见方式

    转自:https://www.cnblogs.com/yuht/p/5714624.html https://www.cnblogs.com/ysocean/p/6893446.html Tomcat ...

  7. Qt 学习之路 2(38):存储容器

    Qt 学习之路 2(38):存储容器 豆子 2013年1月14日 Qt 学习之路 2 38条评论 存储容器(containers)有时候也被称为集合(collections),是能够在内存中存储其它特 ...

  8. Windows远程连接CentOS图形化界面

    1.检查是否安装VNC rpm -q tigervnc tigervnc-server 2.安装安装X-Window # yum check-update # yum groupinstall &qu ...

  9. HDU - 6183 动态开点线段树 || 令人绝望的线段树

    一看C才[0,50],肯定要开51棵线段树维护y区间的最小x值啦 是男人就上51棵..等等空间爆几倍了 动态开点!51棵线段树用全局节点变量控制,有点像主席树 清空工作很简单,把51个树根清掉然后回收 ...

  10. CDN基本原理和功能浅析

    CDN的全称是Content Delivery Network,即内容分发网络.CDN的通俗理解就是网站加速,CPU均衡负载,可以解决跨运营商,跨地区,服务器负载能力过低,带宽过少等带来的网站打开速度 ...