冒泡排序之优化


冒泡排序之优化

  冒泡排序属于一种典型的交换排序。

  交换排序顾名思义就是通过元素的两两比较,判断是否符合要求,如过不符合就交换位置来达到排序的目的。冒泡排序名字的由来就是因为在交换过程中,类似水冒泡,小(大)的元素经过不断的交换由水底慢慢的浮到水的顶端。

  冒泡排序的思想就是利用的比较交换,利用循环将第 i 小或者大的元素归位,归位操作利用的是对 n 个元素中相邻的两个进行比较,如果顺序正确就不交换,如果顺序错误就进行位置的交换。通过重复的循环访问数组,直到没有可以交换的元素,那么整个排序就已经完成了。

	**常用的场景是数组排序:即遍历数组,对数组相邻元素进行对比,若想得到升序序列,则将大的元素放后边,小的放前边。若想得到降序数组则反过来**

图文讲解:

冒泡排序:从第一个数据开始,一次比较相邻元素的大小。如果前者大于后者,则进行交换操作。把大的元素往后交换。通过多轮迭代,直到没有交换操作为止。冒泡排序就像是在一个水池中处理数据一样,每次会把最大的那个数据传递到最后。

算法实现:

 @Test
    public void sortTest(){
        int[] arr = {4,1,3,2,6,7,8,9,10,11,13,15};

        int temp = -1;
        int count = 0;
		
        //需要进行arr.length-1次排序遍历
        for (int i=0; i

结果

执行了66次
----------------------------
1	2	3	4	6	7	8	9	10	11	13	15	

优化一:

通过上面的图片,我们可以发现。在第三次排序的时候,数组其实已经是一个有序数组了。但循环依然在继续,这就白白的浪费了资源。如果我们能判断出数组是有序的,然后跳出循环,那就节省了一部分空间。

 @Test
    public void sortTest1(){
        int[] arr = {4,1,3,2,6,7,8,9,10,11,13,15};

        int temp = -1;
        int count = 0;
        
        for (int i=0; i

结果:

执行了30次
----------------------------
1	2	3	4	6	7	8	9	10	11	13	15	

在以上优化的基础上,还存在一个问题,例如我们的初始数组如下:

int[] arr = {4,1,3,2,6,7,8,9,10,11,13,15};

我们发现arr在6之后的元素是有序的,根本不需要进行遍历和交换。然而,我们每次遍历是从0开始遍历到arr.length-i-1的。这就有可能包括了部分有序数组。

因此,如果我们能把无序数列和有序数组的边界标出来,每次遍历和交换的时候,只遍历到无序数组则也能省下部分空间。

  @Test
    public void sortTest2(){
        int[] arr = {4,1,3,2,6,7,8,9,10,11,13,15};

        int temp = -1;
        int count = 0;
        //定义最后一次交换位置时的索引
        int lastChangeIndex = 0;
        //初始化,第一次遍历数组时,需要遍历的长度
        int sortBorder = arr.length-1;
        for (int i=0; i
执行了14次
----------------------------
1	2	3	4	6	7	8	9	10	11	13	15	

总结:

? 冒泡排序的思想其实很简单,就是相邻元素两两对比,判断是否需要交换顺序。但经过细心的考虑,有些特殊的情况,则可以提前确实数组局部有序,则不需再进行重复遍历。优化也就是把这些重复遍历的步骤给去除,最终得到高性能的冒泡排序算法。