99999久久久久久亚洲,欧美人与禽猛交狂配,高清日韩av在线影院,一个人在线高清免费观看,啦啦啦在线视频免费观看www

熱線電話:13121318867

登錄
首頁(yè)精彩閱讀各種排序算法的時(shí)間復(fù)雜度
各種排序算法的時(shí)間復(fù)雜度
2018-02-27
收藏

各種排序算法的時(shí)間復(fù)雜度

選擇排序、快速排序、希爾排序、堆排序不是穩(wěn)定的排序算法,冒泡排序、插入排序、歸并排序和基數(shù)排序是穩(wěn)定的排序算法。

排序算法不穩(wěn)定的含義是:

在排序之前,有兩個(gè)數(shù)相等. 
但是在排序結(jié)束之后,它們兩個(gè)有可能改變順序.
比如說(shuō):
 在一個(gè)待排序隊(duì)列中,A和B相等,且A排在B的前面,而排序之后,A排在了B的后面.這個(gè)時(shí)候,我們說(shuō)這種算法是不穩(wěn)定的.
(只要有這種可能性,我們就說(shuō)算法是不穩(wěn)定的.)
注: 算法的不穩(wěn)定性,與所用的語(yǔ)言沒(méi)有關(guān)系的.

那么,快速排序?yàn)槭裁床环€(wěn)定呢?
我們來(lái)看看快速排序的過(guò)程:(還是借用之前的那個(gè)假設(shè),假設(shè)A,B相等,并和其它一堆數(shù)據(jù)一起參加排序.)
假設(shè)此時(shí)的快排是小于等于關(guān)鍵字為排在前面的一組組,大于為另外排在后面的一組.
在選取一個(gè)數(shù)出來(lái)分組的時(shí)候,如果選到了A,那么在B<=A的情況下,B將會(huì)排在A的前面.
因?yàn)橛羞@樣的_可能性_,所以說(shuō)我們這種算法是不穩(wěn)定的.

冒泡法:  
這是最原始,也是眾所周知的最慢的算法了。他的名字的由來(lái)因?yàn)樗墓ぷ骺磥?lái)象是冒泡:  復(fù)雜度為O(n*n)。當(dāng)數(shù)據(jù)為正序,將不會(huì)有交換。復(fù)雜度為O(0)。

直接插入排序:O(n*n)

選擇排序:O(n*n)

快速排序:平均時(shí)間復(fù)雜度log2(n)*n,所有內(nèi)部排序方法中最高好的,大多數(shù)情況下總是最好的。

歸并排序:log2(n)*n

堆排序:log2(n)*n

希爾排序:算法的復(fù)雜度為n的1.2次冪

這里我沒(méi)有給出行為的分析,因?yàn)檫@個(gè)很簡(jiǎn)單,我們直接來(lái)分析算法:

首先我們考慮最理想的情況 
1.數(shù)組的大小是2的冪,這樣分下去始終可以被2整除。假設(shè)為2的k次方,即k=log2(n)。 
2.每次我們選擇的值剛好是中間值,這樣,數(shù)組才可以被等分。 
第一層遞歸,循環(huán)n次,第二層循環(huán)2*(n/2)...... 
所以共有n+2(n/2)+4(n/4)+...+n*(n/n) = n+n+n+...+n=k*n=log2(n)*n 
所以算法復(fù)雜度為O(log2(n)*n) 
其他的情況只會(huì)比這種情況差,最差的情況是每次選擇到的middle都是最小值或最大值,那么他將變成交換法(由于使用了遞歸,情況更糟)。但是你認(rèn)為這種情況發(fā)生的幾率有多大??呵呵,你完全不必?fù)?dān)心這個(gè)問(wèn)題。實(shí)踐證明,大多數(shù)的情況,快速排序總是最好的。 
如果你擔(dān)心這個(gè)問(wèn)題,你可以使用堆排序,這是一種穩(wěn)定的O(log2(n)*n)算法,但是通常情況下速度要慢 于快速排序(因?yàn)橐亟M堆)。

這幾天筆試了好幾次了,連續(xù)碰到一個(gè)關(guān)于常見(jiàn)排序算法穩(wěn)定性判別的問(wèn)題,往往還是多選,對(duì)于我以及和我一樣拿不準(zhǔn)的同學(xué)可不是一個(gè)能輕易下結(jié)論的題目,當(dāng)然如果你筆試之前已經(jīng)記住了數(shù)據(jù)結(jié)構(gòu)書(shū)上哪些是穩(wěn)定的,哪些不是穩(wěn)定的,做起來(lái)應(yīng)該可以輕松搞定。

本文是針對(duì)老是記不住這個(gè)或者想真正明白到底為什么是穩(wěn)定或者不穩(wěn)定的人準(zhǔn)備的。

首先,排序算法的穩(wěn)定性大家應(yīng)該都知道,通俗地講就是能保證排序前2個(gè)相等的數(shù)其在序列的前后位置順序和排序后它們兩個(gè)的前后位置順序相同。在簡(jiǎn)單形式化一下,如果Ai = Aj, Ai原來(lái)在位置前,排序后Ai還是要在Aj位置前。

其次,說(shuō)一下穩(wěn)定性的好處。排序算法如果是穩(wěn)定的,那么從一個(gè)鍵上排序,然后再?gòu)牧硪粋€(gè)鍵上排序,第一個(gè)鍵排序的結(jié)果可以為第二個(gè)鍵排序所用?;鶖?shù)排序就是這樣,先按低位排序,逐次按高位排序,低位相同的元素其順序再高位也相同時(shí)是不會(huì)改變的。另外,如果排序算法穩(wěn)定,對(duì)基于比較的排序算法而言,元素交換的次數(shù)可能會(huì)少一些(個(gè)人感覺(jué),沒(méi)有證實(shí))。

回到主題,現(xiàn)在分析一下常見(jiàn)的排序算法的穩(wěn)定性,每個(gè)都給出簡(jiǎn)單的理由。

(1)冒泡排序

冒泡排序就是把小的元素往前調(diào)或者把大的元素往后調(diào)。比較是相鄰的兩個(gè)元素比較,交換也發(fā)生在這兩個(gè)元素之間。所以,如果兩個(gè)元素相等,我想你是不會(huì)再無(wú)聊地把他們倆交換一下的;如果兩個(gè)相等的元素沒(méi)有相鄰,那么即使通過(guò)前面的兩兩交換把兩個(gè)相鄰起來(lái),這時(shí)候也不會(huì)交換,所以相同元素的前后順序并沒(méi)有改變,所以冒泡排序是一種穩(wěn)定排序算法。

(2)選擇排序

選擇排序是給每個(gè)位置選擇當(dāng)前元素最小的,比如給第一個(gè)位置選擇最小的,在剩余元素里面給第二個(gè)元素選擇第二小的,依次類推,直到第n-1個(gè)元素,第n個(gè)元素不用選擇了,因?yàn)橹皇O滤粋€(gè)最大的元素了。那么,在一趟選擇,如果當(dāng)前元素比一個(gè)元素小,而該小的元素又出現(xiàn)在一個(gè)和當(dāng)前元素相等的元素后面,那么交換后穩(wěn)定性就被破壞了。比較拗口,舉個(gè)例子,序列5 8 5 2 9, 我們知道第一遍選擇第1個(gè)元素5會(huì)和2交換,那么原序列中2個(gè)5的相對(duì)前后順序就被破壞了,所以選擇排序不是一個(gè)穩(wěn)定的排序算法。

(3)插入排序
     插入排序是在一個(gè)已經(jīng)有序的小序列的基礎(chǔ)上,一次插入一個(gè)元素。當(dāng)然,剛開(kāi)始這個(gè)有序的小序列只有1個(gè)元素,就是第一個(gè)元素。比較是從有序序列的末尾開(kāi)始,也就是想要插入的元素和已經(jīng)有序的最大者開(kāi)始比起,如果比它大則直接插入在其后面,否則一直往前找直到找到它該插入的位置。如果碰見(jiàn)一個(gè)和插入元素相等的,那么插入元素把想插入的元素放在相等元素的后面。所以,相等元素的前后順序沒(méi)有改變,從原無(wú)序序列出去的順序就是排好序后的順序,所以插入排序是穩(wěn)定的。

(4)快速排序
    快速排序有兩個(gè)方向,左邊的i下標(biāo)一直往右走,當(dāng)a[i] <= a[center_index],其中center_index是中樞元素的數(shù)組下標(biāo),一般取為數(shù)組第0個(gè)元素。而右邊的j下標(biāo)一直往左走,當(dāng)a[j] > a[center_index]。如果i和j都走不動(dòng)了,i <= j, 交換a[i]和a[j],重復(fù)上面的過(guò)程,直到i>j。 交換a[j]和a[center_index],完成一趟快速排序。在中樞元素和a[j]交換的時(shí)候,很有可能把前面的元素的穩(wěn)定性打亂,比如序列為 5 3 3 4 3 8 9 10 11, 現(xiàn)在中樞元素5和3(第5個(gè)元素,下標(biāo)從1開(kāi)始計(jì))交換就會(huì)把元素3的穩(wěn)定性打亂,所以快速排序是一個(gè)不穩(wěn)定的排序算法,不穩(wěn)定發(fā)生在中樞元素和a[j]交換的時(shí)刻。

(5)歸并排序
    歸并排序是把序列遞歸地分成短序列,遞歸出口是短序列只有1個(gè)元素(認(rèn)為直接有序)或者2個(gè)序列(1次比較和交換),然后把各個(gè)有序的段序列合并成一個(gè)有序的長(zhǎng)序列,不斷合并直到原序列全部排好序??梢园l(fā)現(xiàn),在1個(gè)或2個(gè)元素時(shí),1個(gè)元素不會(huì)交換,2個(gè)元素如果大小相等也沒(méi)有人故意交換,這不會(huì)破壞穩(wěn)定性。那么,在短的有序序列合并的過(guò)程中,穩(wěn)定是是否受到破壞?沒(méi)有,合并過(guò)程中我們可以保證如果兩個(gè)當(dāng)前元素相等時(shí),我們把處在前面的序列的元素保存在結(jié)果序列的前面,這樣就保證了穩(wěn)定性。所以,歸并排序也是穩(wěn)定的排序算法。

(6)基數(shù)排序
   基數(shù)排序是按照低位先排序,然后收集;再按照高位排序,然后再收集;依次類推,直到最高位。有時(shí)候有些屬性是有優(yōu)先級(jí)順序的,先按低優(yōu)先級(jí)排序,再按高優(yōu)先級(jí)排序,最后的次序就是高優(yōu)先級(jí)高的在前,高優(yōu)先級(jí)相同的低優(yōu)先級(jí)高的在前。基數(shù)排序基于分別排序,分別收集,所以其是穩(wěn)定的排序算法。

(7)希爾排序(shell)
    希爾排序是按照不同步長(zhǎng)對(duì)元素進(jìn)行插入排序,當(dāng)剛開(kāi)始元素很無(wú)序的時(shí)候,步長(zhǎng)最大,所以插入排序的元素個(gè)數(shù)很少,速度很快;當(dāng)元素基本有序了,步長(zhǎng)很小,插入排序?qū)τ谟行虻男蛄行屎芨?。所以,希爾排序的時(shí)間復(fù)雜度會(huì)比o(n^2)好一些。由于多次插入排序,我們知道一次插入排序是穩(wěn)定的,不會(huì)改變相同元素的相對(duì)順序,但在不同的插入排序過(guò)程中,相同的元素可能在各自的插入排序中移動(dòng),最后其穩(wěn)定性就會(huì)被打亂,所以shell排序是不穩(wěn)定的。

(8)堆排序
   我們知道堆的結(jié)構(gòu)是節(jié)點(diǎn)i的孩子為2*i和2*i+1節(jié)點(diǎn),大頂堆要求父節(jié)點(diǎn)大于等于其2個(gè)子節(jié)點(diǎn),小頂堆要求父節(jié)點(diǎn)小于等于其2個(gè)子節(jié)點(diǎn)。在一個(gè)長(zhǎng)為n的序列,堆排序的過(guò)程是從第n/2開(kāi)始和其子節(jié)點(diǎn)共3個(gè)值選擇最大(大頂堆)或者最小(小頂堆),這3個(gè)元素之間的選擇當(dāng)然不會(huì)破壞穩(wěn)定性。但當(dāng)為n/2-1, n/2-2, ...1這些個(gè)父節(jié)點(diǎn)選擇元素時(shí),就會(huì)破壞穩(wěn)定性。有可能第n/2個(gè)父節(jié)點(diǎn)交換把后面一個(gè)元素交換過(guò)去了,而第n/2-1個(gè)父節(jié)點(diǎn)把后面一個(gè)相同的元素沒(méi)有交換,那么這2個(gè)相同的元素之間的穩(wěn)定性就被破壞了。所以,堆排序不是穩(wěn)定的排序算法

1 快速排序(QuickSort)

快速排序是一個(gè)就地排序,分而治之,大規(guī)模遞歸的算法。從本質(zhì)上來(lái)說(shuō),它是歸并排序的就地版本??焖倥判蚩梢杂上旅嫠牟浇M成。
(1) 如果不多于1個(gè)數(shù)據(jù),直接返回。
(2) 一般選擇序列最左邊的值作為支點(diǎn)數(shù)據(jù)。
(3) 將序列分成2部分,一部分都大于支點(diǎn)數(shù)據(jù),另外一部分都小于支點(diǎn)數(shù)據(jù)。
(4) 對(duì)兩邊利用遞歸排序數(shù)列。

快速排序比大部分排序算法都要快。盡管我們可以在某些特殊的情況下寫出比快速排序快的算法,但是就通常情況而言,沒(méi)有比它更快的了。快速排序是遞歸的,對(duì)于內(nèi)存非常有限的機(jī)器來(lái)說(shuō),它不是一個(gè)好的選擇。 

2 歸并排序(MergeSort)

歸并排序先分解要排序的序列,從1分成2,2分成4,依次分解,當(dāng)分解到只有1個(gè)一組的時(shí)候,就可以排序這些分組,然后依次合并回原來(lái)的序列中,這樣就可以排序所有數(shù)據(jù)。合并排序比堆排序稍微快一點(diǎn),但是需要比堆排序多一倍的內(nèi)存空間,因?yàn)樗枰粋€(gè)額外的數(shù)組。

3 堆排序(HeapSort)

堆排序適合于數(shù)據(jù)量非常大的場(chǎng)合(百萬(wàn)數(shù)據(jù))。

堆排序不需要大量的遞歸或者多維的暫存數(shù)組。這對(duì)于數(shù)據(jù)量非常巨大的序列是合適的。比如超過(guò)數(shù)百萬(wàn)條記錄,因?yàn)榭焖倥判?,歸并排序都使用遞歸來(lái)設(shè)計(jì)算法,在數(shù)據(jù)量非常大的時(shí)候,可能會(huì)發(fā)生堆棧溢出錯(cuò)誤。

堆排序會(huì)將所有的數(shù)據(jù)建成一個(gè)堆,最大的數(shù)據(jù)在堆頂,然后將堆頂數(shù)據(jù)和序列的最后一個(gè)數(shù)據(jù)交換。接下來(lái)再次重建堆,交換數(shù)據(jù),依次下去,就可以排序所有的數(shù)據(jù)。

4 Shell排序(ShellSort)

Shell排序通過(guò)將數(shù)據(jù)分成不同的組,先對(duì)每一組進(jìn)行排序,然后再對(duì)所有的元素進(jìn)行一次插入排序,以減少數(shù)據(jù)交換和移動(dòng)的次數(shù)。平均效率是O(nlogn)。其中分組的合理性會(huì)對(duì)算法產(chǎn)生重要的影響?,F(xiàn)在多用D.E.Knuth的分組方法。

Shell排序比冒泡排序快5倍,比插入排序大致快2倍。Shell排序比起QuickSort,MergeSort,HeapSort慢很多。但是它相對(duì)比較簡(jiǎn)單,它適合于數(shù)據(jù)量在5000以下并且速度并不是特別重要的場(chǎng)合。它對(duì)于數(shù)據(jù)量較小的數(shù)列重復(fù)排序是非常好的。

5 插入排序(InsertSort)

插入排序通過(guò)把序列中的值插入一個(gè)已經(jīng)排序好的序列中,直到該序列的結(jié)束。插入排序是對(duì)冒泡排序的改進(jìn)。它比冒泡排序快2倍。一般不用在數(shù)據(jù)大于1000的場(chǎng)合下使用插入排序,或者重復(fù)排序超過(guò)200數(shù)據(jù)項(xiàng)的序列。

6 冒泡排序(BubbleSort)

冒泡排序是最慢的排序算法。在實(shí)際運(yùn)用中它是效率最低的算法。它通過(guò)一趟又一趟地比較數(shù)組中的每一個(gè)元素,使較大的數(shù)據(jù)下沉,較小的數(shù)據(jù)上升。它是O(n^2)的算法。

7 交換排序(ExchangeSort)和選擇排序(SelectSort)

這兩種排序方法都是交換方法的排序算法,效率都是 O(n2)。在實(shí)際應(yīng)用中處于和冒泡排序基本相同的地位。它們只是排序算法發(fā)展的初級(jí)階段,在實(shí)際中使用較少。

8 基數(shù)排序(RadixSort)

基數(shù)排序和通常的排序算法并不走同樣的路線。它是一種比較新穎的算法,但是它只能用于整數(shù)的排序,如果我們要把同樣的辦法運(yùn)用到浮點(diǎn)數(shù)上,我們必須了解浮點(diǎn)數(shù)的存儲(chǔ)格式,并通過(guò)特殊的方式將浮點(diǎn)數(shù)映射到整數(shù)上,然后再映射回去,這是非常麻煩的事情,因此,它的使用同樣也不多。而且,最重要的是,這樣算法也需要較多的存儲(chǔ)空間。

9 總結(jié)

下面是一個(gè)總的表格,大致總結(jié)了我們常見(jiàn)的所有的排序算法的特點(diǎn)。


數(shù)據(jù)分析咨詢請(qǐng)掃描二維碼

若不方便掃碼,搜微信號(hào):CDAshujufenxi

數(shù)據(jù)分析師資訊
更多

OK
客服在線
立即咨詢
客服在線
立即咨詢
') } function initGt() { var handler = function (captchaObj) { captchaObj.appendTo('#captcha'); captchaObj.onReady(function () { $("#wait").hide(); }).onSuccess(function(){ $('.getcheckcode').removeClass('dis'); $('.getcheckcode').trigger('click'); }); window.captchaObj = captchaObj; }; $('#captcha').show(); $.ajax({ url: "/login/gtstart?t=" + (new Date()).getTime(), // 加隨機(jī)數(shù)防止緩存 type: "get", dataType: "json", success: function (data) { $('#text').hide(); $('#wait').show(); // 調(diào)用 initGeetest 進(jìn)行初始化 // 參數(shù)1:配置參數(shù) // 參數(shù)2:回調(diào),回調(diào)的第一個(gè)參數(shù)驗(yàn)證碼對(duì)象,之后可以使用它調(diào)用相應(yīng)的接口 initGeetest({ // 以下 4 個(gè)配置參數(shù)為必須,不能缺少 gt: data.gt, challenge: data.challenge, offline: !data.success, // 表示用戶后臺(tái)檢測(cè)極驗(yàn)服務(wù)器是否宕機(jī) new_captcha: data.new_captcha, // 用于宕機(jī)時(shí)表示是新驗(yàn)證碼的宕機(jī) product: "float", // 產(chǎn)品形式,包括:float,popup width: "280px", https: true // 更多配置參數(shù)說(shuō)明請(qǐng)參見(jiàn):http://docs.geetest.com/install/client/web-front/ }, handler); } }); } function codeCutdown() { if(_wait == 0){ //倒計(jì)時(shí)完成 $(".getcheckcode").removeClass('dis').html("重新獲取"); }else{ $(".getcheckcode").addClass('dis').html("重新獲取("+_wait+"s)"); _wait--; setTimeout(function () { codeCutdown(); },1000); } } function inputValidate(ele,telInput) { var oInput = ele; var inputVal = oInput.val(); var oType = ele.attr('data-type'); var oEtag = $('#etag').val(); var oErr = oInput.closest('.form_box').next('.err_txt'); var empTxt = '請(qǐng)輸入'+oInput.attr('placeholder')+'!'; var errTxt = '請(qǐng)輸入正確的'+oInput.attr('placeholder')+'!'; var pattern; if(inputVal==""){ if(!telInput){ errFun(oErr,empTxt); } return false; }else { switch (oType){ case 'login_mobile': pattern = /^1[3456789]\d{9}$/; if(inputVal.length==11) { $.ajax({ url: '/login/checkmobile', type: "post", dataType: "json", data: { mobile: inputVal, etag: oEtag, page_ur: window.location.href, page_referer: document.referrer }, success: function (data) { } }); } break; case 'login_yzm': pattern = /^\d{6}$/; break; } if(oType=='login_mobile'){ } if(!!validateFun(pattern,inputVal)){ errFun(oErr,'') if(telInput){ $('.getcheckcode').removeClass('dis'); } }else { if(!telInput) { errFun(oErr, errTxt); }else { $('.getcheckcode').addClass('dis'); } return false; } } return true; } function errFun(obj,msg) { obj.html(msg); if(msg==''){ $('.login_submit').removeClass('dis'); }else { $('.login_submit').addClass('dis'); } } function validateFun(pat,val) { return pat.test(val); }