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

我们看看把大值放在后面:比如数组[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. 查看Eclipse版本号的方法及各个版本区别 Eclipse选择标准

    这篇文章主要介绍了查看Eclipse版本号的方法及各个版本区别 Eclipse选择标准,方便初学者选择适合自己的版本,需要的朋友可以参考下 Eclipse 是一个开放源代码的.基于Java的可扩展开发 ...

  2. 1. C/C++笔试面试经典题目一

    1. 不用循环和递归,实现打印数字0到999. #include <iostream> #include<stdio.h> using namespace std; #defi ...

  3. 降维之主成分分析法(PCA)

    一.主成分分析法的思想 我们在研究某些问题时,需要处理带有很多变量的数据,比如研究房价的影响因素,需要考虑的变量有物价水平.土地价格.利率.就业率.城市化率等.变量和数据很多,但是可能存在噪音和冗余, ...

  4. SLAM技术在国内的发展现状

    近年来,由于扫地机的出现使得SLAM技术名声大噪,如今,已在机器人.无人机.AVG等领域相继出现它的身影,今天就来跟大家聊一聊国内SLAM的发展现状. SLAM的多领域应用 SLAM应用领域广泛,按其 ...

  5. 2B - Amy

    数据范围是18位,把每一位加起来的和最多9*18 = 162 所以只需考虑n-162 - n的数即可,暴力解决 #include <iostream> using namespace st ...

  6. P2057 [SHOI2007]善意的投票 (最大流)

    题目 P2057 [SHOI2007]善意的投票 解析 网络流的建模都如此巧妙. 我们把同意的意见看做源点\(s\),不同意的意见看做汇点\(t\). 那我们\(s\)连向所有同意的人,\(t\)连向 ...

  7. ionic4 refresh组件位置变更:Ignored attempt to cancel a touchmove event with cancelable=false

    io3 中 refresh组件位置可不定: io4 中 须置顶,否则报错,此外complete方法的调用位置改为target属性 参考:https://github.com/ionic-team/io ...

  8. Android IntentService 的使用

    1.service 执行耗时任务的步骤 2.IntentService (1)介绍 (2)使用方法 (3)优点 (4)在AndroidManifest.xml文件中添加service设置 <se ...

  9. mysql ibdata 单独存储

    简介ibdata1 ibdata1文件是InnoDB存储引擎的共享表空间文件,存放位置my.ini 中的 datadir="D:\phpStudy\MySQL\data",目录下. ...

  10. 【算法笔记】B1020 月饼

    1020 月饼 (25 分) 月饼是中国人在中秋佳节时吃的一种传统食品,不同地区有许多不同风味的月饼.现给定所有种类月饼的库存量.总售价.以及市场的最大需求量,请你计算可以获得的最大收益是多少. 注意 ...