zoukankan      html  css  js  c++  java
  • 冒泡排序算法以及它的优化方案

    一、什么是冒泡排序?

    冒泡排序(Bubble Sort)是一种最为基础的交换排序,相信学过C语言的,都接触过这种排序算法。

    这篇文章重点应该放在优化上面。

    二、冒泡排序的实现思想:

    将数组里面相邻的元素两两比较,根据大小来交换元素位置,举个栗子:

    这里有一个数组array[4, 6, 5, 8, 9, 3, 2, 1, 7]

    首先4和6比较,4小于6,位置不变,接下来6和5比较,6大于5,所以6和5的位置对调,数组变成[4, 5, 6, 8, 9, 3, 2,1, 7],由于6和5位置对调,接着是6和8比较,6小于8,所以位置不变,如此类推,第一轮排序后,数组变成[4,  5, 6, 8, 3, 2, 1, 7, 9],第二轮又从第一个元素4开始比较,但是最终比较的元素不是9而是7,因为第一轮比较,已经是确定将最大的元素放到了最后的位置,所以没有必要与最后的元素进行比较,这一轮最终结果为[4, 5, 6, 3, 2, 1, 7, 8, 9],

    如此类推,完成全部排序总共需要array.length x( array.length-1)/2次比较(这个是等差数列计算出来的,有兴趣的可以自己算一下)。因为每一轮都要全部比较,所以最原始的冒泡排序叫做稳定排序。

    根据这种原始思想,可以得到冒泡排序的原始版

    public void sortArray(int[] array){
        int temp;
        for(int i=0; i<array.length; i++){
            for(int j=0; j<array.length-i-1; j++){
                if(array[j] > array[j+1]){
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                }
            }
        }
    }

    我们把每一轮结果罗列出来时,

    第三轮结果:[4, 5,  3,  2, 1, 6, 7, 8, 9]

    第四轮结果:[4, 3,  2, 1, 5,  6, 7, 8, 9]

    第五轮结果:[3, 2, 1, 4,  5,  6, 7, 8, 9]

    第六轮结果:[2, 1, 3, 4,  5,  6, 7, 8, 9]

    第七轮结果[1, 2, 3, 4,  5,  6, 7, 8, 9]

    第八轮结果:[1, 2, 3, 4,  5,  6, 7, 8, 9]

    从结果可以看出,程序做了些“无用功”,为了避免程序做这些“无用功”,要对基础版本程序作出一些修改,

    优化第一版:

    public void sortArray(int[] array){
        int temp;
        for(int i=0; i<array.length; i++){
            boolean isSorted = true;
            for(int j=0; j<array.length-i-1; j++){
                if(array[j] > array[j+1]){
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                    isSorted = false;
                }
            }
            if(isSorted){
                break;
            }
        }
    }

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

    还是拿回每一轮运行结果出来:

    第三轮结果:[4, 5,  3,  2, 1, 6, 7, 8, 9]

    第四轮结果:[4, 3,  2, 1, 5,  6, 7, 8, 9]

    第五轮结果:[3, 2, 1, 4,  5,  6, 7, 8, 9]

    第六轮结果:[2, 1, 3, 4,  5,  6, 7, 8, 9]

    第七轮结果[1, 2, 3, 4,  5,  6, 7, 8, 9]

    第八轮结果:[1, 2, 3, 4,  5,  6, 7, 8, 9]

    这里讲解得详细一点,以第三轮结果,在第四轮运行操作中,4和5比较,4<5,不调换位置,5和3比较,5>3,位置对调,数组变成[4, 3, 5,  2, 1, 6, 7, 8, 9],5和2比较,5<2,位置对调,变成[4, 3, 2, 5, 1, 6, 7, 8, 9],5和1比较,5>1,位置对调,变成[4, 3, 2, 1, 5, 6, 7, 8, 9]。后面就是5和6比较,6和7比较,7和8比较,8和9比较,但是这四次比较对数组排序都没有任何“贡献”,同理,在第五轮循环操作中,没有“贡献”的操作会增加一次,这是不希望出现的。

    这里要介绍一个概念——有序区,有序区指数组有序的区域,这里只数组末尾的有序元素组成的区域,在极端的情况,如[9, 8, 7, 6, 5, 4, 3, 2, 1],按照从小到大顺序排序,每一轮排序,有序区只增加一位元素,但更多的情况有序区元素是大于循环轮次,当有序区元素等于数组长度时,可以认为这个数组已经排序完成,所以下面给出第二次优化,

    优化第二版:

    public void sortArray(int[] array){
        int border = array.length-1;
        int lastIndex = 0;
        int temp;
        for(int i=0; i<array.length; i++){
            boolean isSorted = true;
            for(int j=0; j<border; j++){
                if(array[j] > array[j+1]){
                    temp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = temp;
                    
                    lastIndex = j;
                    isSorted = false;
                }
            }
            border = lastIndex;
            if(isSorted){
                break;
            }
        }
    }

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

    以第五轮结果为栗子,[3, 2, 1, 4,  5,  6, 7, 8, 9]

    在进行第六轮循环操作时,3和2比较,3>2,位置对调,变成[2, 3, 1, 4,  5,  6, 7, 8, 9],此时lastIndex = j = 0,3和1比较,3>1,位置对调,变成[2, 1, 3, 4,  5,  6, 7, 8, 9],此时lastIndex = j = 1,3和4比较,3<4,位置不变,如此类推,本轮循环结束时,lastIndex = 1,那么此时border = 1,在第七轮循环里面,只需要进行1次比较就可以结束第七轮循环。

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

  • 相关阅读:
    easyui datagrid 编辑器绑定事件
    Java初学(八)
    Java初学(七)
    Java初学(六)
    Java初学(五)
    Java初学(四)
    GCC基本知识
    OpenCL memory object 之 Global memory (2)
    OpenCL memory object 之 Global memory (1)
    OpenCL memory object 之 传输优化
  • 原文地址:https://www.cnblogs.com/SysoCjs/p/9398491.html
Copyright © 2011-2022 走看看