本文根据《大话数据结构》一书,实现了Java版的冒泡排序

更多:数据结构与算法合集

基本概念

  基本思想:将相邻的元素两两比较,根据大小关系交换位置,直到完成排序。

  对n个数组成的无序数列,进行n轮排序,每轮按两两比较的方法找出最小(或最大)的一个。下图表示某数列的第一轮排序。

下面为交换元素的swap()方法代码,后面代码中将直接使用。

	public void swap(int[] a, int i, int j) {
int temp;
temp = a[j];
a[j] = a[i];
a[i] = temp;
}

  

初级版本

根据基本思想,可以写出初级版本的冒泡排序如下:

	public void bubbleSort0(int[] a) {
if(a==null) return;
// 代表第i轮排序
for (int i = 0; i < a.length; i++) {
for (int j = a.length - 1; j > i; j--) {
if (a[j] < a[j - 1]) {
swap(a, i, j);
}
}
}
}

    

第一次优化版本

  当数据基本有序时,可能前几轮循环就完成了排序,后面的循环就没有必要继续进行了,如下图所示:

  对这种情况,可以在代码中增加一个标记,用于标记每轮循环时代码是否已经有序,在每轮循环开始前,如果有序的话就没有必要继续进行比较了。具体Java代码如下:

	public void bubbleSort1(int[] a) {
if(a==null) return;
boolean isSorted = false; // false代表数据无序,需要排序
for (int i = 0; i < a.length && !isSorted; i++) { // 数据无序时还要继续循环
isSorted = true; // 假设这轮循环开始时已经有序
for (int j = a.length - 1; j > i; j--) {
if (a[j] < a[j - 1]) {
swap(a, i, j);
isSorted = false; // 有发生交换,说明这轮循环还是无序的
}
}
}
}

    

第二次优化版本

  当数列的前半部分有序而后半部分无序时,每轮循环没必要再对有序部分进行排序,例如,数列为{1,2,3,4,9,5,8,7}时,在一次循环后知道1,2,3,4已经有序,后面的循环就没必要对这些数字进行排序了。

  此时,关键点在于对有序区的界定:如果知道有序区的边界,那么每次循环就只需要比较到该边界即可。在每次循环的最后,记录下最后一次元素交换的位置,该位置就是有序区的边界了。具体Java代码如下:

	public void bubbleSort2(int[] a) {
if(a==null) return;
int lastExchangeIndex = 0; // 用于记录每轮循环最后一次交换的位置
int sortBorder = 0; // 有序数组的边界,每次比较只要比较到这里就可以
boolean isSorted = false;
for (int i = 0; i < a.length && !isSorted; i++) {
isSorted = true;
for (int j = a.length - 1; j > sortBorder; j--) {
if (a[j] < a[j - 1]) {
swap(a, i, j);
isSorted = false;
lastExchangeIndex = j; // 本轮最后一次交换位置(不断更新)
}
}
sortBorder = lastExchangeIndex; // 边界更新为最后一次交换位置
}
}

    

完整Java代码

(含测试代码)

import java.util.Arrays;

/**
*
* @Description 冒泡排序(从小到大)
*
* @author yongh
* @date 2018年9月13日 下午3:21:38
*/
public class BubbleSort { /**
* 初级版本
*/
public void bubbleSort0(int[] a) {
if(a==null) return;
// 代表第i轮排序
for (int i = 0; i < a.length; i++) {
for (int j = a.length - 1; j > i; j--) {
if (a[j] < a[j - 1]) {
swap(a, i, j);
}
}
}
} /**
* 优化版本
* 添加一个标记isSorted
*/
public void bubbleSort1(int[] a) {
if(a==null) return;
boolean isSorted = false; // false代表数据无序,需要排序
for (int i = 0; i < a.length && !isSorted; i++) { // 数据无序时还要继续循环
isSorted = true; // 假设这轮循环开始时已经有序
for (int j = a.length - 1; j > i; j--) {
if (a[j] < a[j - 1]) {
swap(a, i, j);
isSorted = false; // 有发生交换,说明这轮循环还是无序的
}
}
}
} /**
* 进一步优化版本
*/
public void bubbleSort2(int[] a) {
if(a==null) return;
int lastExchangeIndex = 0; // 用于记录每轮循环最后一次交换的位置
int sortBorder = 0; // 有序数组的边界,每次比较只要比较到这里就可以
boolean isSorted = false;
for (int i = 0; i < a.length && !isSorted; i++) {
isSorted = true;
for (int j = a.length - 1; j > sortBorder; j--) {
if (a[j] < a[j - 1]) {
swap(a, i, j);
isSorted = false;
lastExchangeIndex = j; // 本轮最后一次交换位置(不断更新)
}
}
sortBorder = lastExchangeIndex; // 边界更新为最后一次交换位置
}
} /**
* 交换代码
*/
public void swap(int[] a, int i, int j) {
int temp;
temp = a[j];
a[j] = a[i];
a[i] = temp;
} //=========测试代码=======
public void test1() {
int[] a = null;
bubbleSort2(a);
System.out.println(Arrays.toString(a));
} public void test2() {
int[] a = {};
bubbleSort2(a);
System.out.println(Arrays.toString(a));
} public void test3() {
int[] a = { 1 };
bubbleSort2(a);
System.out.println(Arrays.toString(a));
} public void test4() {
int[] a = { 3, 3, 3, 3, 3 };
bubbleSort2(a);
System.out.println(Arrays.toString(a));
} public void test5() {
int[] a = { -3, 6, 3, 1, 3, 7, 5, 6, 2 };
bubbleSort2(a);
System.out.println(Arrays.toString(a));
} public static void main(String[] args) {;
BubbleSort demo = new BubbleSort();
demo.test1();
demo.test2();
demo.test3();
demo.test4();
demo.test5();
}
}

    

null
[]
[]
[, , , , ]
[, , -, , , , , , ]

BubbleSort

总结

  冒泡排序原理近似于气泡在水里慢慢上浮到水面上,实现容易,但也有改进的空间,

  改进1:若前几轮已经有序,则后面就没必要继续比较了,因此增加一个isSorted标记,对每轮是否有序进行标记。

  改进2:一部分有序,则没必要继续对有序区比较,增加一个sortBorder来定义有序区边界,每次比较到该边界即可。该边界由每轮循环中最后一次元素交换的位置得到。

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

更多:数据结构与算法合集

【Java】 大话数据结构(14) 排序算法(1) (冒泡排序及其优化)的更多相关文章

  1. 【Java】 大话数据结构(15) 排序算法(2) (快速排序及其优化)

    本文根据<大话数据结构>一书,实现了Java版的快速排序. 更多:数据结构与算法合集 基本概念 基本思想:在每轮排序中,选取一个基准元素,其他元素中比基准元素小的排到数列的一边,大的排到数 ...

  2. 【Java】 大话数据结构(16) 排序算法(3) (堆排序)

    本文根据<大话数据结构>一书,实现了Java版的堆排序. 更多:数据结构与算法合集 基本概念 堆排序种的堆指的是数据结构中的堆,而不是内存模型中的堆. 堆:可以看成一棵完全二叉树,每个结点 ...

  3. 【Java】 大话数据结构(17) 排序算法(4) (归并排序)

    本文根据<大话数据结构>一书,实现了Java版的归并排序. 更多:数据结构与算法合集 基本概念 归并排序:将n个记录的序列看出n个有序的子序列,每个子序列长度为1,然后不断两两排序归并,直 ...

  4. 【Java】 大话数据结构(18) 排序算法(5) (直接插入排序)

    本文根据<大话数据结构>一书,实现了Java版的直接插入排序. 更多:数据结构与算法合集 基本概念 直接插入排序思路:类似扑克牌的排序过程,从左到右依次遍历,如果遇到一个数小于前一个数,则 ...

  5. Java常用的经典排序算法:冒泡排序与选择排序

     一.冒泡排序                             冒泡排序(Bubble Sort)是一种交换排序,它的基本思想是:两两比较相邻记录的关键字,如果反序则交换,直到没有反序的记录为 ...

  6. Java常见排序算法之冒泡排序

    在学习算法的过程中,我们难免会接触很多和排序相关的算法.总而言之,对于任何编程人员来说,基本的排序算法是必须要掌握的. 从今天开始,我们将要进行基本的排序算法的讲解.Are you ready?Let ...

  7. java排序算法之冒泡排序(Bubble Sort)

    java排序算法之冒泡排序(Bubble Sort) 原理:比较两个相邻的元素,将值大的元素交换至右端. 思路:依次比较相邻的两个数,将小数放在前面,大数放在后面.即在第一趟:首先比较第1个和第2个数 ...

  8. 【Java】 大话数据结构(11) 查找算法(2)(二叉排序树/二叉搜索树)

    本文根据<大话数据结构>一书,实现了Java版的二叉排序树/二叉搜索树. 二叉排序树介绍 在上篇博客中,顺序表的插入和删除效率还可以,但查找效率很低:而有序线性表中,可以使用折半.插值.斐 ...

  9. 排序算法之冒泡排序Java实现

    排序算法之冒泡排序 舞蹈演示排序: 冒泡排序: http://t.cn/hrf58M 希尔排序:http://t.cn/hrosvb  选择排序:http://t.cn/hros6e  插入排序:ht ...

随机推荐

  1. luogu1351 [NOIp2014]联合权值 (dfs)

    有两种情况:一个点到它的父亲的父亲(要算两次).一个点的子节点之间互相到达 #include<bits/stdc++.h> #define pa pair<int,int> # ...

  2. 整除分块学习笔记+[CQOI2007]余数求和(洛谷P2261,BZOJ1257)

    上模板题例题: [CQOI2007]余数求和 洛谷 BZOJ 题目大意:求 $\sum^n_{i=1}k\ mod\ i$ 的值. 等等……这题就学了三天C++的都会吧? $1\leq n,k\leq ...

  3. 解题:CTSC 2008 祭祀

    题面 洛谷要求输出方案,懒得写了,但是还是放一下链接看看吧 (虽然现在二分图已经过气了=.=) 要求最长反链,最长反链=最小链覆盖,先Floyd传递闭包之后链覆盖就变成了边覆盖,然后最小边覆盖=总点数 ...

  4. 界面编程之QT窗口系统20180726

    /*******************************************************************************************/ 一.坐标系统 ...

  5. 装饰器python

    装饰器 你是一家视频网站的后端开发工程师,你们网站有以下几个版块 1 2 3 4 5 6 7 8 9 10 11 def home():     print("---首页----" ...

  6. Spark记录-Scala字符串

    Scala字符串 在Scala中的字符串和Java中的一样,字符串是一个不可变的对象,也就是一个不能修改的对象.可以修改的对象,如数组,称为可变对象.字符串是非常有用的对象,在本节的最后部分,我们将介 ...

  7. Lucene6.6.0 案例与学习路线

    之前在学习Lucene这个全文检索工具,为项目搜索引擎的开发打下基础.在这里先分享一下关于Lucene的学习心得. 核心的学习流程是:索引文件格式--索引创建过程--检索流程. 1.首先建议参看这篇精 ...

  8. Django 2.0.1 官方文档翻译: 编写你的第一个 Django app,第一部分(Page 6)

    编写你的第一个 Django app,第一部分(Page 6)转载请注明链接地址 Django 2.0.1 官方文档翻译: Django 2.0.1.dev20171223092829 documen ...

  9. 浅谈 JSON 那些被转义的字符们

    其实,之前我一直以为 JSON 会把 ASCII 可显示字符以外的统统转义为 Unicode,直到有一次我用 JSON.stringify 才发现,其实是 PHP 为我们想的太周到了. 我以前是一位 ...

  10. Linux - 用户操作

    常用命令 users # 显示所有的登录用户 groups # 列出当前用户和他所属的组 who -q # 显示所有的登录用户 groupadd # 添加组 useradd user # 建立用户 p ...