冒泡排序

原理:每次比较两个相邻的元素,将较大的元素交换至右端。

思路:每次冒泡排序操作都会将相邻的两个元素进行比较,看是否满足大小关系要求,如果不满足,就交换这两个相邻元素的次序,一次冒泡至少让一个元素移动到它应该排列的位置,重复N次,就完成了冒泡排序。

具体如何移动呢?举一个栗子:

有8个数组成一个无序数列:5,8,6,3,9,2,1,7,希望从小到大排序。

首先让\color{red}{5}\color{red}{8}比较,发现\color{red}{5}\color{red}{8}要小,因此元素位置不变。
\color{red}{5}\color{red}{8},6,3,9,2,1,7

接下来让\color{red}{8}\color{red}{6}比较,发现\color{red}{8}\color{red}{6}要大,所以\color{red}{8}\color{red}{6}交换位置。
5,\color{red}{6}\color{red}{8},3,9,2,1,7

继续让\color{red}{8}\color{red}{3}比较,发现\color{red}{8}\color{red}{3}要大,所以\color{red}{8}\color{red}{3}交换位置。
5,6,\color{red}{3}\color{red}{8},9,2,1,7

继续让\color{red}{8}\color{red}{9}比较,发现\color{red}{8}\color{red}{9}要小,所以元素位置不变。
5,6,3,\color{red}{8}\color{red}{9},2,1,7

接下来让\color{red}{9}\color{red}{2}比较,发现\color{red}{9}\color{red}{2}要大,所以\color{red}{9}\color{red}{2}交换位置。
5,6,3,8,\color{red}{2}\color{red}{9},1,7

接下来让\color{red}{9}\color{red}{1}比较,发现\color{red}{9}\color{red}{1}要大,所以\color{red}{9}\color{red}{1}交换位置。
5,6,3,8,2,\color{red}{1}\color{red}{9},7

这样第一轮比较,就找到了元素\color{red}{9}作为最大元素,排序在最右侧。
5,6,3,8,2,1,7,\color{red}{9}

下面进行第二轮排序

首先让\color{red}{5}\color{red}{6}比较,发现\color{red}{5}\color{red}{6}要小,因此元素位置不变。
\color{red}{5}\color{red}{6},3,8,2,1,7,9

接下来让\color{red}{6}\color{red}{3}比较,发现\color{red}{6}\color{red}{3}要大,所以\color{red}{6}\color{red}{3}交换位置。
5,\color{red}{3}\color{red}{6},8,2,1,7,9

继续让\color{red}{6}\color{red}{8}比较,发现\color{red}{6}\color{red}{8}要小,因此元素位置不变。
5,3,\color{red}{6}\color{red}{8},2,1,7,9

接下来让\color{red}{8}\color{red}{2}比较,发现\color{red}{8}\color{red}{2}要大,所以\color{red}{8}\color{red}{2}交换位置。
5,3,6,2,\color{red}{8},1,7,9

接下来让\color{red}{8}\color{red}{1}比较,发现\color{red}{8}\color{red}{1}要大,所以\color{red}{8}\color{red}{1}交换位置。
5,3,6,2,\color{red}{1}\color{red}{8},7,9

继续让\color{red}{8}\color{red}{7}比较,发现\color{red}{8}\color{red}{7}要大,所以\color{red}{8}\color{red}{7}交换位置。
5,3,6,2,1,\color{red}{7}\color{red}{8},9

接下来如同上进行八轮比较得到;
1,2,3,5,6,7,\color{red}{8}\color{red}{9}

第二轮比较结束后,得到了两个有序的最大元素 \color{red}{8},\color{red}{9}

原始的冒泡排序是稳定排序。由于该排序算法的每一轮要遍历所有元素,轮转的次数和元素数量相当,所以时间复杂度是O(N^2) 。

下面呈上代码:

private static void sort1(int array[]) {
        int tmp = 0;
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = tmp;
                }
            }
        }
    }

原始的冒泡排序有哪些优化点呢?

让我们回顾一下刚才描述的排序细节,仍然以5,8,6,3,9,2,1,7这个数列为例,当排序算法分别执行到第六、第七、第八轮的时候,数列状态如下:

第六轮比较
1,2,3,5,6,7,8,9

第七轮比较
1,2,3,5,6,7,8,9

第八轮比较
1,2,3,5,6,7,8,9

很明显可以看出,自从经过第六轮排序,整个数列已然是有序的了。可是我们的排序算法仍然“兢兢业业”地继续执行第七轮、第八轮。

这种情况下,如果我们能判断出数列已经有序,并且做出标记,剩下的几轮排序就可以不必执行,提早结束工作。

冒泡排序优化版

 /**
     * 这一版代码做了小小的改动,利用布尔变量isSorted作为标记。如果在本轮排序中,元素有交换,则说明数列无序;如果没有元素交换,说明数列已然有序,直接跳出大循环。
     * @param array
     */
    private static void sort2(int array[]) {
        int tmp = 0;
        for (int i = 0; i < array.length; i++) {
            boolean isSorted = true;                  //有序标记,每一轮的初始是true
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = tmp;
                    isSorted = false;                //有元素交换,所以不是有序,标记变为false
                }
            }
            if (isSorted) {
                break;
            }
        }
    }

这只是冒泡排序优化的第一步,下面还可以进一步优化提升性能!

为了说明问题,咱们这次找一个新的数列:
3,4,2,1,5,6,7,8

这个数列的特点是前半部分(3,4,2,1)无序,后半部分(5,6,7,8)升序,并且后半部分的元素已经是数列最大值。

这个问题的关键点在哪里呢?关键在于对数列有序区的界定。

按照现有的逻辑,有序区的长度和排序的轮数是相等的。比如第一轮排序过后的有序区长度是1,第二轮排序过后的有序区长度是2 ......

实际上,数列真正的有序区可能会大于这个长度,比如例子中仅仅第二轮,后面5个元素实际都已经属于有序区。因此后面的许多次元素比较是没有意义的。

如何避免这种情况呢?我们可以在每一轮排序的最后,记录下最后一次元素交换的位置,那个位置也就是无序数列的边界,再往后就是有序区了。

冒泡排序再次优化

 /**
     * 这一版代码中,sortBorder就是无序数列的边界。每一轮排序过程中,sortBorder之后的元素就完全不需要比较了,肯定是有序的。
     * @param array
     */
    private static void sort3(int array[]) {
        int tmp = 0;
        int lastExchangeIndex = 0;                        //记录最后一次交换的位置
        int sortBorder = array.length - 1;                //无序数列的边界,每次比较只需要比到这里为止
        for (int i = 0; i < array.length; i++) {
            boolean isSorted = true;                      //有序标记,每一轮的初始是true
            for (int j = 0; j < sortBorder; j++) {
                if (array[j] > array[j + 1]) {
                    tmp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = tmp;
                    isSorted = false;                     //有元素交换,所以不是有序,标记变为false
                    lastExchangeIndex = j;                //把无序数列的边界更新为最后一次交换元素的位置
                }
            }
            sortBorder = lastExchangeIndex;
            if (isSorted) {
                break;
            }
        }
    }

原文地址

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容