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

我们看看把大值放在后面:比如数组[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. 【bzoj3576】[Hnoi2014]江南乐 数论分块+博弈论

    Description 小A是一个名副其实的狂热的回合制游戏玩家.在获得了许多回合制游戏的世界级奖项之后,小A有一天突然想起了他小时候在江南玩过的一个回合制游戏. 游戏的规则是这样的,首先给定一个数F ...

  2. bzoj2440完全平方数

    题目链接 上来先吐槽题面!!!!!! 你跟我说$1$不是完全平方数昂? 看了半天样例啊. 活生生的半天$……$ 莫比乌斯 反演    函数容斥一下,每次二分就好 反正本宝宝不知道反演是啥. 每次判断应 ...

  3. JDBC_事务概念_ACID特点_隔离级别_提交commit_回滚rollback

    事务的概念 一组要么同时执行成功,要么同时执行失败的SQL语句,是数据库操作的一个执行单元! 事务开始于: 连接到数据库上,并执行一条DML语句(insert,update或delete),前一个事务 ...

  4. 将utc时间格式化的代码

    /** * 对Date的扩展,将 Date 转化为指定格式的String * 月(M).日(d).12小时(h).24小时(H).分(m).秒(s).周(E).季度(q) 可以用 1-2 个占位符 * ...

  5. 23.3Sum(三数和为零)

    Level:   Medium 题目描述: Given an array nums of n integers, are there elements a, b, c in nums such tha ...

  6. Android GPS应用(获取定位信息)

    1.介绍 2.使用方法 3.在AndroidManifest.xml文件中添加 <uses-permission android:name="android.permission.AC ...

  7. Angular 2: 404 error occur when I refresh through the browser [duplicate]

    https://stackoverflow.com/questions/35284988/angular-2-404-error-occur-when-i-refresh-through-the-br ...

  8. 洛谷 P3267 [JLOI2016/SHOI2016]侦察守卫(树形dp)

    题面 luogu 题解 树形\(dp\) \(f[x][y]表示x的y层以下的所有点都已经覆盖完,还需要覆盖上面的y层的最小代价.\) \(g[x][y]表示x子树中所有点都已经覆盖完,并且x还能向上 ...

  9. 蓝桥-青蛙跳杯子(bfs)

    问题描述 X星球的流行宠物是青蛙,一般有两种颜色:白色和黑色. X星球的居民喜欢把它们放在一排茶杯里,这样可以观察它们跳来跳去. 如下图,有一排杯子,左边的一个是空着的,右边的杯子,每个里边有一只青蛙 ...

  10. P2056 [ZJOI2007]捉迷藏

    传送门 如果没有修改显然就直接点分治 有修改那就动态点分治 动态点分治就是在点分树上维护一些东西,查询时也在点分树上查 因为点分树深度是$log$的所以可以保证时间复杂度 此题我们需要在点分树上维护 ...