一、优化第一版

优化第一版是针对类似 int[] arr = {3,2,1,4,5,6,7,8,9; 这样的有很多已经排好序的数组,为了不让它做无用的循环,对于此场景进行的优化,优化代码如下:

// 优化第一版
public static void bubbleSort2(int[] arr, int len) {for (int i = 0; i < len; i++) {boolean isSorted = true;for (int j = 0; j < len - i - 1; j++) {if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;isSorted = false;}}if (isSorted) {break;}}
}

程序定义了一个boolean类型的isSorted变量,用来判断往后的循环当中,数组是否已经是有序的,每一轮循环都会设置其值为true,当有元素对调位置时,就将isSorted的值设置为false,表示该数组还不是有序数组。每一轮都要判断isSorted的值,如果判断当前一轮操作没有元素有位置调换,那么可以提前结束所有的循环。读者可以自行举例数组检验。

二、优化第二版

我们针对优化第一版再进行优化。

这一版新增了两个int类型变量,一个是border,表示无序项的边界,同时也是每一轮循环的次数设定值,另一个是lastIndex,用来记录最后元素需要交换的下标值,进行一轮循环后,将这个值赋值给border,作为下一轮循环的次数。每一轮循环,当有元素需要调换位置时,记录j的位置,当前轮次循环结束,就将lastIndex赋值给border,最为新一轮循环操作的边界。

代码如下:

// 优化第二版
public static void bubbleSort3(int[] arr, int len) {int border = len - 1, lastIndex = 0;for (int i = 0; i < len; i++) {boolean isSorted = true;for (int j = 0; j < border; j++) {if (arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;lastIndex = j;isSorted = false;}}border = lastIndex;if (isSorted) {break;}}
}

但是,优化第二版仍不是最优方案,上面的两种优化方案只是减少每轮的操作次数,还有一种可以直接减少循环的轮数,那就是鸡尾酒算法排序,请看下面的优化第三版。

三、优化第三版

鸡尾酒算法思想:冒泡排序是元素单向比较,而鸡尾酒排序却是双向。

列举一个最简单的栗子int[] arr = {2, 3, 4, 5, 6, 7, 8, 9, 1};

如果按照传统的冒泡排序进行操作,

第一轮结果:[2, 3, 4, 5, 6, 7, 8, 1, 9],只有9和1交换;

第二轮结果:[2, 3, 4, 5, 6, 7, 1, 8, 9],只有8和1交换;

第三轮结果:[2, 3, 4, 5, 6, 1, 7, 8, 9],只有7和1交换;

。。。

第八轮结果:[1, 2, 3, 4, 5, 6, 7, 8, 9],只有2和1交换;

每一轮执行过程中,前面元素的比较,很明显做了无用功,对于本次栗子中的数组,如果元素比较的顺序是从右边开始,那就省了很多功夫,加入鸡尾酒算法,可以实现这个操作。

鸡尾酒算法实现冒泡排序:

// 优化第三版 (鸡尾酒算法)
public static void bubbleSort4(int[] arr, int len) {int temp = 0;boolean isSorted = true;for (int i = 0; i < len / 2 - 1; i++) {// 奇数轮比较for (int j = 0; j < len - i - 1; j++) {if (arr[j] > arr[j + 1]) {temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;isSorted = false;}}if (isSorted) {break;}// 偶数轮比较for (int j = len - i - 1; j > i; j--) {if (arr[j] < arr[j - 1]) {temp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = temp;isSorted = false;}}if (isSorted) {break;}}
}

大循环中我们将循环轮次优化为len/2次,奇数轮比较顺序从左到右,每一轮 j 的开始项也从冒泡算法的0变成了 i ,因为下面还有偶数轮比较排序,偶数轮排序会将最左边的元素变成有序区。

鸡尾酒算法还可以再优化下,于是有了鸡尾酒算法的优化,如下第四版。

四、优化第四版

// 优化第四版 (鸡尾酒算法优化)
public static void bubbleSort5(int[] arr, int len) {int temp = 0;boolean isSorted = true;int lastLeftIndex = 0, lastRightIndex = 0;//左边界int leftBorder = 0;//右边界int rightBorder = arr.length - 1;for (int i = 0; i < len / 2 - 1; i++) {// 奇数轮比较for (int j = leftBorder; j < rightBorder; j++) {if (arr[j] > arr[j + 1]) {temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;lastRightIndex = j;isSorted = false;}}rightBorder = lastRightIndex;if (isSorted) {break;}// 偶数轮比较for (int j = rightBorder; j > leftBorder; j--) {if (arr[j] < arr[j - 1]) {temp = arr[j];arr[j] = arr[j - 1];arr[j - 1] = temp;lastLeftIndex = j;isSorted = false;}}leftBorder = lastLeftIndex;if (isSorted) {break;}}
}

与传统冒泡法的第三版优化一样,设置了每一轮的循环边界,由于鸡尾酒算法是双向排序的,所以这里的边界也分别定义了左、右边界 leftBorder 和 rightBorder ,即每一轮循环都是以这两个边界为循环次数计算,相对于鸡尾酒第一版,第二版比较容易理解。

鸡尾酒算法实现冒泡排序的优化确实可以很大程度上减少了比较的无用功,同时也要注意它的代码量也是之前的两倍。


2020.5.7 更新。。。

对于冒泡排序优化,又想到了一种算法。

// 优化第五版 (引入标志位,只循环一次)
public static void bubbleSort6(int[] arr, int len) {boolean flag = true;while (flag) {flag = false;for (int i = 0; i < len - 1; i++) {if (arr[i] > arr[i + 1]) {int temp = arr[i];arr[i] = arr[i + 1];arr[i + 1] = temp;flag = true;}}len--;}
}

我自己测试了以下这几个版本的性能,10万随机数排序性能对比如下:

优化版本 性能耗时
第一版 18993 ms
第二版 19701 ms
第三版 15289 ms
第四版 11322 ms
第五版 19370 ms

这个数据各位小伙伴们看着选择,第二班比第一版还多,有点尴尬。第三版相对好点,第四版最好。第五版其实性能没有提升太多,如果注重代码简洁的可以选择第五版。


十大排序算法总结

【十大排序算法】(一)冒泡排序算法
【十大排序算法】(一)冒泡排序算法(优化)
【十大排序算法】(二)快速排序算法
【十大排序算法】(三)选择排序算法
【十大排序算法】(四)堆排序算法
【十大排序算法】(五)插入排序算法
【十大排序算法】(六)希尔排序算法
【十大排序算法】(七)归并排序算法
【十大排序算法】(八)计数排序算法
【十大排序算法】(九)桶排序算法
【十大排序算法】(十)基数排序算法

【十大排序算法】(一)冒泡排序算法(优化)相关推荐

  1. JS 实现十大排序算法

    文章目录 前言 零.十大排序 一.冒泡排序(bubbleSort) 二.选择排序(selectionSort) 三.插入排序(insertSort) 四.希尔排序(shellSort) 五.归并排序( ...

  2. 十大经典排序算法之冒泡排序及其优化

    一.冒泡排序 1.冒泡排序算法的原理如下: 1.比较相邻的元素.如果第一个比第二个大,就交换他们两个. 2.对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对.在这一点,最后的元素应该会是最大 ...

  3. 算法基础-十大排序算法及其优化(文末有抽奖福利哦)

    算法基础-十大排序算法及其优化 算法基础-十大排序算法及其优化 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Kw1LA5Q4-1607527572080)(/uplo ...

  4. 数据结构与算法:十大排序算法之冒泡排序

    数据结构与算法:十大排序算法之冒泡排序 package array;import java.util.Arrays;//冒泡排序 //1.比较数组中两个相邻的元素,如果第一个数比第二个数大,我们就交换 ...

  5. 这或许是东半球分析十大排序算法最好的一篇文章

    作者 | 不该相遇在秋天 转载自五分钟学算法(ID:CXYxiaowu) 前言 本文全长 14237 字,配有 70 张图片和动画,和你一起一步步看懂排序算法的运行过程. 预计阅读时间 47 分钟,强 ...

  6. 「干货总结」程序员必知必会的十大排序算法

    点击上方 好好学java ,选择 星标 公众号 重磅资讯.干货,第一时间送达 今日推荐:硬刚一周,3W字总结,一年的经验告诉你如何准备校招! 个人原创100W+访问量博客:点击前往,查看更多 绪论 身 ...

  7. 「归纳|总结」程序员必知必会的十大排序算法

    微信搜一搜「bigsai」关注这个有趣的程序员 新人原创公众号,求支持一下!你的点赞三连肯定对我至关重要! 文章已收录在 我的Github bigsai-algorithm 欢迎star 本文目录 绪 ...

  8. 归并排序执行次数_十大排序算法,看这篇就够了

    排序算法分类[1][2] 比较类排序:通过比较来决定元素间的相对次序,由于其时间复杂度不能突破O(nlogn),因此也称为非线性时间比较类排序. 非比较类排序:不通过比较来决定元素间的相对次序,它可以 ...

  9. 经典十大排序算法(含升序降序,基数排序含负数排序)【Java版完整代码】【建议收藏系列】

    经典十大排序算法[Java版完整代码] 写在前面的话 十大排序算法对比 冒泡排序 快速排序 直接选择排序 堆排序 归并排序 插入排序 希尔排序 计数排序 桶排序 基数排序 完整测试类 写在前面的话   ...

最新文章

  1. 云原生平台的建设怎么搞?监控系统又该如何演进?这里有答案!
  2. ssh_config sshd_config 详解
  3. spring batch (四) Job的配置及配置文件说明介绍
  4. 【译】A Practical Introduction to Blockchain with Python
  5. 颠覆传统4S店,特斯拉发布智能售后服务体系
  6. tomcat启动java项目_Java web项目启动Tomcat报错解决方案
  7. 关于使用cadence建pad
  8. linux怎么用网络yum源,Linux配置本地网络YUM源
  9. Paddle实现NLP-文本分类
  10. 【Prison Break】第六天(4.2)
  11. python面向对象设计角色攻击_Python技能:面向对象基础实战之英雄联盟
  12. python语言mooc作业_计算机基础(Ⅱ)Python语言-中国大学mooc-试题题目及答案
  13. 研发管理05:项目管理经验总结
  14. html勾选标签,html怎么勾选框
  15. SymPy学习之Plotting Module
  16. 2021ccpc网络预选赛部分题解
  17. 拓嘉辰丰:影响拼多多直通车推广效果的因素有哪些?
  18. 願いをドラッグの若返り薬)作者紫猫刘程
  19. 【在线研讨会-倒计时】12月12日Softing工业物联网解决方案 助力工业4.0
  20. 拼多多商家和快递公司谈合作的技巧

热门文章

  1. 深度学习的Attention模型
  2. Transformer中的注意力机制
  3. js中简单的使用webSocket
  4. 译| 自定义一个Vue路由器
  5. 树莓派 (为学生计算机编程教育设计的一种卡片式电脑)
  6. 标准模板库STL经典书籍(必读)
  7. 全球顶尖大学,获单笔捐赠20.65亿!
  8. 【Struts2】〖500错误〗解决“找不到URI:[/struts-tags]的taglib[s]”问题
  9. HDU 2069 母函数模版题
  10. GXT 2.x 中设置Grid内容可复制