冒泡排序
来源:互联网 发布:mac里面xp升级win7 编辑:程序博客网 时间:2024/05/22 15:54
冒泡排序的思路很简单——从头至尾遍历数组元素,若前一项大于(或小于)后一项,则交换相邻两项。单次遍历整个数组可将某一个元素排列到正确位置,因此需要遍历元素数量n次。在代码中体现也就是内外两层循环,内层循环负责遍历中两两元素的交换操作,外层负责遍历次数控制。
首先看版本1:
/** * 冒泡排序效率最低写法,没有任何优化步骤 * @param arrayToSort */public static void sortAlpha(int[] arrayToSort) { for (int i = 0; i < arrayToSort.length; i++) { for (int j = 0; j < (arrayToSort.length - 1); j++) { int tmp; if (arrayToSort[j] > arrayToSort[j + 1]) { tmp = arrayToSort[j]; arrayToSort[j] = arrayToSort[j+1]; arrayToSort[j+1] = tmp; } } }}
很明显的两层循环,这里按从小到大排序,因此弱发现后一元素比当前元素大,则交换两个元素的位置,直到比较到最后一个元素为止。因为是j
与j+1
比较,为避免数组越界,内层for循环需以arrayToSort.length - 1
做边界。
这个版本中没有做任何优化,因为遍历n次后,数组中后n个元素实际已经是排好序的了,因此不需要再进行比较了。所以内层循环还可以进一步优化,得到版本2:
/** * 冒泡排序优化版本1,减少内层循环遍历个数,已经排序好的元素无需遍历。 * @param arrayToSort */public static void sortBeta(int[] arrayToSort) { for (int i = 0; i < arrayToSort.length; i++) { for (int j = 0; j < (arrayToSort.length - 1 - i); j ++) { int tmp; if (arrayToSort[j] > arrayToSort[j + 1]) { tmp = arrayToSort[j]; arrayToSort[j] = arrayToSort[j+1]; arrayToSort[j+1] = tmp; } } }}
由于遍历n次后,后n项已经排好序了,因此内层循环上界再减去遍历次数即可,即arrayToSort.length - 1 - i
这样每次内层遍历便可减少n次比较操作,提升了效率。
虽然这时内层循环已经优化操作次数,但如果给一个部分有序的数列,如
{1, 2, 3, 4, 8, 7, 6, 5}
遍历前四次后,数组实际已经排好序了,这时就不需要再进行比较操作了,因此除了前四次排序,仅在需要一次遍历就可检验出数组有序,也就是公共遍历5次数组就可完成排序了。在当前的逻辑下,会导致出现3次无意义的遍历。
解决这个问题的方案也很简单,若数组已经有序,则不会出现交换操作。因此仅需设定一个标志变量,当有交换时置成需要排序(检验)的状态,当所有元素已经有序,检验过程没有交换操作,那么再下次遍历数组直接退出即可,便是版本3:
/** * 冒泡排序优化版2,减少内部排序遍历个数,并且添加了数据是否有序的检验, * 若数组已经有序,无需再进行遍历,直接退出。 * @param arrayToSort */public static void sortGamma(int[] arrayToSort) { boolean needSort = true; for (int i = 0; i < arrayToSort.length; i++) { if (!needSort) { break; } for (int j = 0; j < (arrayToSort.length - 1 - i); j ++) { needSort = false; int tmp; if (arrayToSort[j] > arrayToSort[j + 1]) { tmp = arrayToSort[j]; arrayToSort[j] = arrayToSort[j+1]; arrayToSort[j+1] = tmp; needSort = true; } } }}
在每次进入内部循环时重置标志变量,若进行了交换操作则相应改变,进入内层循环前进行判断,若不需要再遍历,直接退出。
接下来写一些测试代码,来验证三种方案的效率。生成两个数组:一个完全逆序,长度为9999;另一个完全正序,长度同样为9999(不用再排序了),然后分别使用三种排序,统计排序时间,以下是一种方法的调用:
public static void main(String[] args) { final int len = 9999; int test[] = new int[len]; for (int i = 0; i < test.length; i++) { test[i] = len - 1 - i; } int testNoNeedSort[] = new int[len]; for (int i = 0; i < testNoNeedSort.length; i ++) { testNoNeedSort[i] = i; } long startTimeA = System.currentTimeMillis(); BubbleSort.sortGamma(test); long endTimeA = System.currentTimeMillis(); System.out.println("Time use A:" + (endTimeA - startTimeA)); long startTimeB = System.currentTimeMillis(); BubbleSort.sortGamma(testNoNeedSort); long endTimeB = System.currentTimeMillis(); System.out.println("Time use A:" + (endTimeB - startTimeB));}
运行三种排序,统计到的时间:
最好情况下由于仅需比较,不需要交换,因此三种版本使用时间均比最差情况短,但由于第三种增加了交换情况的判断,仅需遍历一遍就可完成。
最差情况下由于版本2,版本3对内层排序进行了操作数优化,因此显著优于完全没有优化的版本1。
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 冒泡排序
- 踩水
- 【NOIP2016提高A组模拟7.17】锦标赛
- 【linux c】什么是野指针以及如何避免野指针_学习笔记_010
- 参考韩顺平老师的视频,用HTML写一个静态网页的邮箱
- IntelliJ IDEA Maven 安装配置
- 冒泡排序
- POJ1753-Flip Game
- atomic工作原理 使用CAS实现线程安全
- Java Arrays类进行数组排序
- Base64
- LeetCode 118. Pascal's Triangle
- 扩展欧几里得-逆元 浙江2012年省赛J题 Modular Inverse
- LeetCode 347. Top K Frequent Elements
- 欢迎使用CSDN-markdown编辑器