11-排序(上):為什么插入排序比冒泡排序更受歡迎?

排序操作相關(guān)代碼請移步 Leooel 的博客

最經(jīng)典、最常用的排序算法:冒泡排序、插入排序、選擇排序、歸并排序、快速排序、計數(shù)排序、基數(shù)排序、桶排序。

按照時間復(fù)雜度把它們分成了三類:

如何分析一個“排序算法”?

  • 一、排序算法的執(zhí)行效率

    • 最好情況、最壞情況、平均情況時間復(fù)雜度
    • 時間復(fù)雜度的系數(shù)、常數(shù) 、低階(實際開發(fā)中數(shù)據(jù)規(guī)模很小的時候不能忽略)
    • 比較次數(shù)和交換(或移動)次數(shù)
  • 二、排序算法的內(nèi)存消耗

針對排序算法的空間復(fù)雜度,引入了一個新的概念:原地排序算法,特指空間復(fù)雜度是 O(1) 的排序算法。

  • 三、排序算法的穩(wěn)定性

僅僅用執(zhí)行效率和內(nèi)存消耗來衡量排序算法的好壞是不夠的。針對排序算法,我們還有一個重要的度量指標(biāo):穩(wěn)定性。這個概念是說,如果待排序的序列中存在值相等的元素,經(jīng)過排序之后,相等元素之間原有的先后順序不變。

冒泡排序(Bubble Sort)

冒泡排序只會操作相鄰的兩個數(shù)據(jù)。每次冒泡操作都會對相鄰的兩個元素進行比較,看是否滿足大小關(guān)系要求。如果不滿足就讓它倆互換。一次冒泡會讓至少一個元素移動到它應(yīng)該在的位置,重復(fù) n 次,就完成了 n 個數(shù)據(jù)的排序工作。

冒泡過程還可以優(yōu)化。當(dāng)某次冒泡操作已經(jīng)沒有數(shù)據(jù)交換時,說明已經(jīng)達到完全有序,不用再繼續(xù)執(zhí)行后續(xù)的冒泡操作。

三個問題:

  • 第一,冒泡排序是原地排序算法嗎?

冒泡的過程只涉及相鄰數(shù)據(jù)的交換操作,只需要常量級的臨時空間,所以它的空間復(fù)雜度為 O(1),是一個原地排序算法。

  • 第二,冒泡排序是穩(wěn)定的排序算法嗎?

冒泡排序中當(dāng)有相鄰的兩個元素大小相等的時候,我們不做交換,相同大小的數(shù)據(jù)在排序前后不會改變順序,所以冒泡排序是穩(wěn)定的排序算法。

  • 第三,冒泡排序的時間復(fù)雜度是多少?

最好情況時間復(fù)雜度是 O(n);最壞情況時間復(fù)雜度為 O(n^2)

那平均時間復(fù)雜是多少呢?平均時間復(fù)雜度就是加權(quán)平均期望時間復(fù)雜度,分析的時候要結(jié)合概率論的知識。

在這里如果用概率論方法定量分析平均時間復(fù)雜度,涉及的數(shù)學(xué)推理和計算就會很復(fù)雜。我這里還有一種思路,通過“有序度”和“逆序度”這兩個概念來進行分析。如下圖:

例如對于一個完全有序的數(shù)組,比如 1,2,3,4,5,6,有序度就是 n * (n - 1) / 2,也就是 15,我們把這種完全有序的數(shù)組的有序度叫作 滿有序度。

逆序度的定義正好跟有序度相反(默認從小到大為有序)。

關(guān)于這三個概念,我們還可以得到一個公式:逆序度 = 滿有序度 - 有序度

我們排序的過程就是一種增加有序度,減少逆序度的過程,最后達到滿有序度,就說明排序完成了。

對于包含 n 個數(shù)據(jù)的數(shù)組進行冒泡排序,平均交換次數(shù)是多少呢?最壞情況下,初始狀態(tài)的有序度是 0,所以要進行 n*(n-1)/2 次交換。最好情況下,初始狀態(tài)的有序度是 n*(n-1)/2,就不需要進行交換。我們可以取個中間值 n*(n-1)/4,來表示初始有序度既不是很高也不是很低的平均情況。

換句話說,平均情況下,需要 n * (n - 1) / 4 次交換操作,比較操作肯定要比交換操作多,而復(fù)雜度的上限是 O(n^2),所以平均情況下的時間復(fù)雜度就是 O(n^2)。

插入排序(Insertion Sort)

插入排序是如何來實現(xiàn)排序的呢?

首先,我們將數(shù)組中的數(shù)據(jù)分為兩個區(qū)間,已排序區(qū)間未排序區(qū)間。初始已排序區(qū)間只有一個元素,就是數(shù)組的第一個元素。插入算法的核心思想是取未排序區(qū)間中的元素,在已排序區(qū)間中找到合適的插入位置將其插入,并保證已排序區(qū)間數(shù)據(jù)一直有序。重復(fù)這個過程,直到未排序區(qū)間中元素為空,算法結(jié)束。

插入排序也包含兩種操作,一種是元素的比較,一種是元素的移動。

對于不同的查找插入點方法(從頭到尾、從尾到頭),元素的比較次數(shù)是有區(qū)別的。但對于一個給定的初始序列,移動操作的次數(shù)總是固定的,就等于逆序度。

同樣三個問題:

  • 第一,插入排序是原地排序算法嗎?

空間復(fù)雜度是 O(1),也就是說,這是一個原地排序算法。

  • 第二,插入排序是穩(wěn)定的排序算法嗎?

在插入排序中,對于值相同的元素,我們可以選擇將后面出現(xiàn)的元素,插入到前面出現(xiàn)元素的后面,這樣就可以保持原有的前后順序不變,所以插入排序是穩(wěn)定的排序算法。

  • 第三,插入排序的時間復(fù)雜度是多少?

最好是時間復(fù)雜度為 O(n);最壞情況時間復(fù)雜度為 O(n^2);平均時間復(fù)雜度為 O(n^2)。

選擇排序(Selection Sort)

選擇排序算法的實現(xiàn)思路有點類似插入排序,也分已排序區(qū)間和未排序區(qū)間。但是選擇排序每次會從未排序區(qū)間中找到最小的元素,將其放到已排序區(qū)間的末尾。

選擇排序空間復(fù)雜度為 O(1),是一種原地排序算法。選擇排序的最好情況時間復(fù)雜度、最壞情況和平均情況時間復(fù)雜度都為 O(n^2)。選擇排序是一種不穩(wěn)定的排序算法。

開篇解答

冒泡排序和插入排序的時間復(fù)雜度都是 O(n^2),都是原地排序算法,為什么插入排序要比冒泡排序更受歡迎呢?

不論冒泡排序還是插入排序,對于同一組數(shù)據(jù),需要的元素交換的次數(shù)是一個固定值,即原始數(shù)據(jù)的逆序度。

但是從代碼實現(xiàn)上來看,冒泡排序的每次數(shù)據(jù)交換需要三個賦值操作,而插入排序只需要一個賦值操作,見下圖:

我們把執(zhí)行一個賦值語句的時間粗略地計為單位時間 (unit_time),然后分別用冒泡排序和插入排序?qū)ν粋€逆序度是 K 的數(shù)組進行排序。用冒泡排序,需要 K 次交換操作,每次需要 3 個賦值語句,所以交換操作總耗時就是 3*K 單位時間。而插入排序中數(shù)據(jù)移動操作只需要 K 個單位時間。

所以,雖然冒泡排序和插入排序在時間復(fù)雜度上是一樣的,都是 O(n^2),但是如果我們希望把性能優(yōu)化做到極致,那肯定首選插入排序。

插入排序的算法思路也有很大的優(yōu)化空間,上面只是最基礎(chǔ)的一種,詳細請看希爾排序。

內(nèi)容小結(jié)

要想分析、評價一個排序算法,需要從執(zhí)行效率、內(nèi)存消耗和穩(wěn)定性三個方面來看。

這一節(jié),分析了三種時間復(fù)雜度是 O(n^2) 的排序算法,冒泡排序、插入排序、選擇排序。需要重點掌握的是它們的分析方法。

這三種時間復(fù)雜度為 O(n^2) 的排序算法中,冒泡排序、選擇排序,可能就純粹停留在理論的層面了,學(xué)習(xí)的目的也只是為了開拓思維,實際開發(fā)中應(yīng)用并不多,但是插入排序還是挺有用的。后面講排序優(yōu)化的時候,我會講到,有些編程語言中的排序函數(shù)的實現(xiàn)原理會用到插入排序算法。

這三種排序算法,實現(xiàn)代碼都非常簡單,對于小規(guī)模數(shù)據(jù)的排序,用起來非常高效。但是在大規(guī)模數(shù)據(jù)排序的時候,這個時間復(fù)雜度還是稍微有點高,接下來學(xué)習(xí)時間復(fù)雜度為 O(nlogn) 的排序算法。

課后思考

我們講過,特定算法是依賴特定的數(shù)據(jù)結(jié)構(gòu)的。我們今天講的幾種排序算法,都是基于數(shù)組實現(xiàn)的。如果數(shù)據(jù)存儲在鏈表中,這三種排序算法還能工作嗎?如果能,那相應(yīng)的時間、空間復(fù)雜度又是多少呢?


考慮只能改變節(jié)點位置。冒泡排序相比于數(shù)組實現(xiàn),比較次數(shù)一致,但交換時操作更復(fù)雜;

插入排序,比較次數(shù)一致,不需要再有后移操作,找到位置后可以直接插入,但排序完畢后可能需要倒置鏈表;

選擇排序比較次數(shù)一致,交換操作同樣比較麻煩。

綜上,時間復(fù)雜度和空間復(fù)雜度并無明顯變化,若追求極致性能,冒泡排序的時間復(fù)雜度系數(shù)會變大,插入排序系數(shù)會減小,選擇排序無明顯變化。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容