日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何优化冒泡排序

發(fā)布時間:2025/6/17 编程问答 31 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何优化冒泡排序 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

一、冒泡排序(BubbleSort)

  • 基本思想:從左到右使用相鄰兩個元素進行比較,如果第一個比第二個大,則交換兩個元素。這樣會使較大數(shù)下沉到數(shù)組的尾端,即較小數(shù)像泡泡一樣冒到數(shù)組首端。
  • 排序過程:
  • 比較相鄰兩個元素,如果第一個比第二個大,則交換兩個元素;
  • 從左到右依次比較,直到最大數(shù)位于數(shù)組尾端;
  • 重復(fù)N-1次1、2步驟,(除去已經(jīng)排序的最大數(shù))依次將第二,第三。。。第N-1大的數(shù)排好位置。
  • 原序列39658274
    第1趟36582749
    第2趟35627489
    第3趟35264789
    第4趟32546789
    第5趟23456789
    第6趟23456789
    第7趟23456789

    如表格所示,每一趟都將當(dāng)前亂序序列中最大的數(shù)移到尾端?!拘』锇閭儚谋砀裰锌闯龌久芭菖判蚩梢詢?yōu)化的地方了嗎?】下面先來基本實現(xiàn)代碼。

    • java實現(xiàn)冒泡排序:

      private?static?<T?extends?Comparable<??super?T>>?void?bubbleSort(T[]?nums)?{
      ??????if?(null?==?nums?||?nums.length?==?0)?{
      ??????????throw?new?RuntimeException("數(shù)組為null或長度為0");
      ??????}
      ??????T?temp?=?null;
      ??????int?length?=?nums.length;
      ??????//外循環(huán)是趟數(shù),每一趟都會將未排序中最大的數(shù)放到尾端
      ??????for?(int?i?=?0;?i?<?length?-?1;?i++)?{
      ??????????//內(nèi)循環(huán)是從第一個元素開始,依次比較相鄰元素,
      ??????????//?比較次數(shù)隨著趟數(shù)減少,因為每一趟都排好了一個元素
      ??????????for?(int?j?=?0;?j?<?length?-?1?-?i;?j++)?{
      ??????????????if?(nums[j].compareTo(nums[j?+?1])?>?0)?{
      ??????????????????temp?=?nums[j];
      ??????????????????nums[j]?=?nums[j?+?1];
      ??????????????????nums[j?+?1]?=?temp;
      ??????????????}
      ??????????}
      ??????}
      ??}

    從表格中,相信小伙伴已經(jīng)看出,在第5趟其實已經(jīng)排好序了,但基本的冒泡排序算法還會進行第7趟比較,這其實只是進行沒必要的比較,而不會進行元素的交換。(第6趟還是必須要走的,下面會說明)

    • 時間、空間復(fù)雜度及穩(wěn)定性分析:
  • 時間復(fù)雜度:由于內(nèi)外循環(huán)都發(fā)生N次迭代,所以時間復(fù)雜度為O(n^2)。并且這個界是精確的。思考最壞的情況,輸入一個逆序的數(shù)組,則比較次數(shù)為:

    (N-1)+(N-2)+(N-3)+..+2+1 = n*(n-1)/2 = O(n^2)

  • 空間復(fù)雜度:只使用了一個臨時變量,所以為O(1)

  • 是否穩(wěn)定:穩(wěn)定排序

  • 二、優(yōu)化冒泡排序

    ? 我們換個角度看待這個問題?;久芭菟惴ㄖ赃M行了無用的多余掃描,是因為不知道已經(jīng)排好了序;所以只要我們在第 i 趟(i小于N-1)就知道序列已經(jīng)排好序,我們就不用進行之后的掃描了。

    綜上所述,我們可以增加一個boolean變量,來標(biāo)識是否已經(jīng)排好序。優(yōu)化代碼如下:

    冒泡排序優(yōu)化普通版:

    ????private?static?<T?extends?Comparable<??super?T>>?void?bubbleSort(T[]?nums)?{
    ????????if?(null?==?nums?||?nums.length?==?0)?{
    ????????????throw?new?RuntimeException("數(shù)組為null或長度為0");
    ????????}

    ????????T?temp?=?null;
    ????????int?length?=?nums.length;
    ????????//用于標(biāo)識是否已經(jīng)將序列排好序
    ????????boolean?isOrdered?=?false;
    ????????for?(int?i?=?0;?i?<?length?-?1;?i++)?{
    ????????????//每一趟開始前都假設(shè)已經(jīng)有序
    ????????????isOrdered?=?true;
    ????????????for?(int?j?=?0;?j?<?length?-?1?-?i;?j++)?{
    ????????????????if?(nums[j].compareTo(nums[j?+?1])?>?0)?{
    ????????????????????temp?=?nums[j];
    ????????????????????nums[j]?=?nums[j?+?1];
    ????????????????????nums[j?+?1]?=?temp;
    ????????????????????//如果出現(xiàn)有元素交換,則表明此躺可能沒有完成排序
    ????????????????????isOrdered?=?false;
    ????????????????}
    ????????????}
    ????????????//如果當(dāng)前趟都沒有進行元素的交換,證明前面一趟比較已經(jīng)排好序
    ????????????//直接跳出循環(huán)
    ????????????if?(isOrdered)?{
    ????????????????break;
    ????????????}
    ????????}
    ????}

    注意:雖然第5趟已經(jīng)排好序,但對于程序來說,它并不知道此趟已經(jīng)排好序,需要進行下一趟掃描來確定上一趟是否已經(jīng)將原序列排好序。所以第6趟是必須要去掃描的。

    你以為結(jié)束了嗎?還沒有,這只是第一版優(yōu)化。

    讓我們想一想這樣的情況。對于下列序列,前半部分亂序,后半部分有序。

    原序列45326789
    第一趟43256789
    第二趟32456789
    第三趟23456789

    簡述排序過程:

    第一趟:發(fā)生交換的是5和3,接著是5和2;隨后5與6比較,不需要換位置,相同地,6與7、7與8、8與9都不需要更換位置。所以第一趟結(jié)果為:[4,3,2,5,6,7,8,9]。

    第二趟:發(fā)生交換的是4與3,接著4與2;隨后4與5、5與6,6與7、7與8都不需要更換位置?!?不需要與9比較,因為第一趟已經(jīng)將最大的數(shù)下沉到尾端】。所以第二趟結(jié)果為:[3,2,4,5,6,7,8,9]。

    第三趟:發(fā)生交換的是3與2;隨后3與4,4與5,5與6,6與7都不需要更換位置。所以第三趟結(jié)果為:[2,3,4,5,6,7,8,9]。

    大家看出什么了嗎?其實進行了很多無意義的比較,因為這些都不需要更換位置,而很多趟都會重復(fù)比較。根據(jù)冒泡排序思想,我們知道,有序序列長度,其實跟排序趟數(shù)相等,每一趟就是將當(dāng)前亂序中的最大值下沉到數(shù)組尾端。但其實序列真正有序的序列長度是大于當(dāng)前排序趟數(shù)的。也就是說,只要我們找到了原序列中無序與有序的邊界,就可以避免再去比較有序序列。

    其實最后一次交換的位置,就是無序序列與有序序列的邊界。

    從例子中看:

    第一趟最后一次交換的位置是元素5與2交換的位置,即數(shù)組下標(biāo)2的位置;

    第二趟最后一次交換的位置是元素4與2交換的位置,即數(shù)組下標(biāo)1的位置;

    第三趟最后一次交換的位置是元素3與2交換的位置,即數(shù)組下標(biāo)0的位置;

    所以,只要我們記錄下當(dāng)前趟最后一次交換的位置,在下一趟只比較到這個位置即可。

    冒泡排序優(yōu)化加強版:

    ????private?static?<T?extends?Comparable<??super?T>>?void?bubbleSort(T[]?nums)?{
    ????????if?(null?==?nums?||?nums.length?==?0)?{
    ????????????throw?new?RuntimeException("數(shù)組為null或長度為0");
    ????????}

    ????????T?temp?=?null;
    ????????int?length?=?nums.length;
    ????????boolean?isOrdered?=?false;
    ????????int?lastExchangeIndex?=?0;
    ????????//當(dāng)前趟無序的邊界
    ????????int?unorderedBorder?=?length?-?1;
    ????????for?(int?i?=?0;?i?<?length?-?1;?i++)?{
    ????????????//每一趟開始前都假設(shè)已經(jīng)有序
    ????????????isOrdered?=?true;
    ????????????for?(int?j?=?0;?j?<?unorderedBorder;?j++)?{
    ????????????????if?(nums[j].compareTo(nums[j?+?1])?>?0)?{
    ????????????????????temp?=?nums[j];
    ????????????????????nums[j]?=?nums[j?+?1];
    ????????????????????nums[j?+?1]?=?temp;
    ????????????????????//如果出現(xiàn)有元素交換,則表明此躺沒有完成排序
    ????????????????????isOrdered?=?false;
    ????????????????????//記錄下最后一次交換元素的位置
    ????????????????????lastExchangeIndex?=?j;
    ????????????????}
    ????????????}
    ????????????unorderedBorder?=?lastExchangeIndex;
    ????????????if?(isOrdered)?{
    ????????????????break;
    ????????????}
    ????????}
    ????}

    其實,還可以進一步優(yōu)化, 有興趣的可以去看看雞尾酒排序,我們已經(jīng)很接近了。

    三、總結(jié)

    ? 冒泡排序可以通過增加boolean標(biāo)識是否已經(jīng)排好序來進行優(yōu)化;還可以記錄下最后一次交換元素的位置來進行優(yōu)化,防止無意義的比較。冒泡排序是穩(wěn)定排序,時間復(fù)雜度為O(n^2),空間復(fù)雜度為O(1)。

    轉(zhuǎn)載于:https://www.cnblogs.com/hhthtt/p/10707521.html

    總結(jié)

    以上是生活随笔為你收集整理的如何优化冒泡排序的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。