冒泡排序的优化

怀疑

冒泡排序的优化?
没听错把?
好吧,此前我还真不知道这玩意儿,也没想过,不过了解之后其实并不复杂。
不过一个O(n2)的算法有啥好优化的呢?快排他不香么?非要去优化一个O(n2)的玩意儿。
好吧,不管,就当脑经急转弯了、

原始冒泡

思路

冒泡冒泡,顾名思义,一杯水,最底下的泡泡,往上浮,最底下最小,越往上越大,像极了冒泡排序;

过程

乱序的N个数(假设要求从左到右从小到大排序),从左到右扫描一遍,每扫描一次,将它本身和它相邻的数进行比较并考虑是否互换位置,每次扫描完毕,你要保证当前这个数和相邻的数是有序的(左小右大),如此第一次扫描完这N个数,你就能发现第N个数是最大的;
然后你再重复这个过程:
第二次只要扫描剩下的N-1个数,你就能发现第N-1个数是最大的;

以此类推

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

思考与优化一

思路

想像以下,如果第二次扫描的时候,剩下的N-1个数都已经是有序的呢?
那么往后的扫描次数是不是都是多余的嘞?

过程

如此,你可以设置一个标记,用于假设当前剩下的N-1个数都是有序的了,如果实际在扫描过程中出现了不是有序的情况,就改变这个标记的状态,如果扫描过程中没有发生不是有序的情况,那么说明剩下的全是有序的元素,直接剩下的所有扫描过程即可。

        for (int i = arr.length - 1; i >= 0; i--) {
            boolean sorted = true;
            for (int j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    sorted = false;
                }
            }
            if (sorted) break;
        }

最坏情况分析

对于冒泡来说,最坏的情况无非是:你想要的从左到右有序递增,但是给出的序列是元素从左到右有序递减。
在这种情况下,其实当前这种优化后的冒泡比未优化前的冒泡效率要低那么一丢丢,因为体现在了标记的处理上;
此时,这个标记就相当于脱裤子放屁,多此一举了。

明确当前优化的目标

再次明确当前优化的目标:就是为了处理,剩下需要排序的目标元素已经有序的情况,节省这个时间。
那么最优情况也显而易见,对一个已经有序的序列使用原始冒泡和当前优化后的冒泡进行处理,前者是O(n2),后者是O(n)

思考与优化二

思路

通过第一种优化方式之后来看,这种剩下需要排序的一整段序列都是已经有序的情况,概率比较低;那么如果是,剩下需要排序的一整段中,有靠后的某一段是已经排好序的呢?这种情况概率显然会更大;与第一种优化有一定的相似之处;
只是第一种优化是针对,剩下的待排序段都已有序的情况,而当前这种是一整段中,后面的(未知长度)某段(末尾位置与待排序段末尾未知重合)都已有序;这种情况的概率更大;

过程

有了上面的思路,过程和优化一的过程基本一致,只是在优化一中相对原冒泡排序修改的位置从修改标记更改为记录索引,这个索引记录的是扫描剩下的待排序段中,最后一次交换相邻元素的索引,这样这个索引后面的所有元素都应当是有序的,再进行下次扫描时,这个索引就是新的待排序段的右边界。

        for (int i = arr.length - 1; i >= 0; i--) {
        	// 初始的pos,应该默认是最好的情况,即所有元素都已经从左到右有序了,则pos为0
            int pos = 0;
            for (int j = 0; j < i; j++) {
                if (arr[j] > arr[j + 1]) {
                    int temp = arr[j];
                    arr[j] = arr[j + 1];
                    arr[j + 1] = temp;
                    pos = j + 1;
                }
            }
            i = pos;
        }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值