Array.prototype.sort()方法到底是如何排序的?

本文除了會(huì)帶大家了解一些Array.prototypr.sort()方法(后面簡(jiǎn)寫為sort()方法)的基本定義和用法之外洪己,還會(huì)探討一下sort()方法到底是使用的什么排序算法务冕。簡(jiǎn)單度娘了一下拇囊,網(wǎng)上的那些sort()方法詳解文章硅急,大多只說了sort()方法的用法覆享。還有說sort()方法是使用冒泡法做的排序,這是錯(cuò)誤的营袜。下面撒顿,我們發(fā)車!

sort()方法

先來看看sort()方法的一些基礎(chǔ)知識(shí)荚板。已經(jīng)了解sort()方法的童鞋可以直接跳過這部分凤壁。

定義

sort() 方法在適當(dāng)?shù)奈恢脤?duì)數(shù)組的元素進(jìn)行排序,并返回?cái)?shù)組跪另。 sort 排序不一定是穩(wěn)定的客扎。

語(yǔ)法

arr.sort()
arr.sort(compareFunction)

說明

1.如果沒有指明 compareFunction ,那么元素會(huì)按照轉(zhuǎn)換為的字符串的諸個(gè)字符的Unicode位點(diǎn)進(jìn)行排序罚斗。

2.如果指明了 compareFunction ,那么數(shù)組會(huì)按照調(diào)用該函數(shù)的返回值排序宅楞。即 a 和 b 是兩個(gè)將要被比較的元素:
?? a.如果 compareFunction(a, b) 小于 0 针姿,那么 a 會(huì)被排列到 b 之前;
?? b.如果 compareFunction(a, b) 等于 0 厌衙, a 和 b 的相對(duì)位置不變距淫。(ECMAScript 標(biāo)準(zhǔn)并不保證這一行為,而且也不是所有瀏覽器都會(huì)遵守,例如 Mozilla 在 2003 年之前的版本)婶希;
?? c.如果 compareFunction(a, b) 大于 0 榕暇, b 會(huì)被排列到 a 之前。
??d. compareFunction(a, b)必須總是對(duì)相同的輸入返回相同的比較結(jié)果喻杈,否則排序的結(jié)果將是不確定的彤枢。(利用這一特性,可實(shí)現(xiàn)隨機(jī)排序)

3.如果數(shù)組包含undefined元素(元素值為undefined或元素末定義)

以上90%引用自MDN

實(shí)例
//例1.字母排序
var a = new Array("banna","watermelon","orange","apple");
s.sort(); 
console.log(a) //輸出 ["apple", "banna", "orange", "watermelon"]
//沒什么好說的筒饰,比較函數(shù)缺省缴啡,按照字母順序升序排序 a<b<o<w

//例2.轉(zhuǎn)化為字母排序
var a=[11,2,44,3,5,6];
a.sort();
console.log(a) // [11, 2, 3, 44, 5, 6]
//說明第一條,數(shù)字轉(zhuǎn)為字符串瓷们,"11"<"2"<"3"<"44"<"5"<"6"

//例3.數(shù)字排序
var a=[11,2,44,3,5,6];
a.sort(function(a,b){
    return a-b; //升序——當(dāng)a<b時(shí)业栅,a-b返回一個(gè)小于0的值。根據(jù)說明2-a谬晕,a會(huì)在b的前面碘裕,則實(shí)現(xiàn)了升序排序。反之如果想實(shí)現(xiàn)降序排序攒钳,return b-a即可帮孔。
});
console.log(a) //輸出 [2, 3, 5, 6, 11, 44]

//例3.隨機(jī)排序
var a=[11,2,44,3,5,6];
a.sort(function(a,b){
    return Math.random()>.5?-1:1; //根據(jù)說明2-c特性,實(shí)現(xiàn)隨機(jī)排序
});
console.log(a) //每次運(yùn)行的輸出都不同

以上是sort()方法的一些基本用法,MDN里還有更多的用法不撑。下面我們來看看sort()方法到底是如何排序的你弦。

sort()方法如何實(shí)現(xiàn)排序

怎么查看sort()方法是如果實(shí)現(xiàn)排序的呢惊豺?我們可以在比較函數(shù)里把a(bǔ),b及數(shù)組輸出一下,看看是否能夠看出使用的排序算法禽作。

var arr=[1, 8, 3, 5, -1];
function compare(a,b){
    console.log(a,b,arr);
    return a-b;
}
arr.sort(compare);
/**
控制臺(tái)輸出
1 8 [1, 8, 3, 5, -1]
8 3 [1, 8, 3, 5, -1]
1 3 [1, 8, 8, 5, -1]
8 5 [1, 3, 8, 5, -1]
3 5 [1, 3, 8, 8, -1]
8 -1 [1, 3, 5, 8, -1]
5 -1 [1, 3, 5, 8, 8]
3 -1 [1, 3, 5, 5, 8]
1 -1 [1, 3, 3, 5, 8]
[-1,1, 3, 5, 8]
*/

不知道同學(xué)們有沒有看出什么端倪尸昧。反正我一開始是什么都沒有發(fā)現(xiàn),那就分析分析咯旷偿。
??第一次1和8比較烹俗,1<8,不需要調(diào)整位置萍程。
??第二次8和3比較幢妄,8>3,需要調(diào)整位置茫负。但是這里沒有交換位置蕉鸳,僅僅是8覆蓋了3位置。這里就可以推斷出不是單純的使用了冒泡算法忍法。
??第三是1和3比較潮尝,1<3,3替換了8的位置饿序。什么鬼勉失,幾個(gè)意思?原探?乱凿?看到這里我也是表示不懂呀。那就繼續(xù)往下看咯咽弦。
??第四是8和5比較徒蟆,8>5,又僅僅是覆蓋型型,沒有交換位置后专。還是不懂,繼續(xù)往下输莺!
??第五是3和5比較戚哎,3<5,5替換了8的位置嫂用,不懂型凳,繼續(xù)往下!
??第六是8和-1比較嘱函,8>-1甘畅, 還僅僅是覆蓋,繼續(xù)往下!
??第七疏唾、八蓄氧、九次,-1依次和5槐脏,3喉童,1做了比較,并且5顿天,3堂氯,1都移動(dòng)了一次位置。等等牌废,這怎么和插入排序法有點(diǎn)相似咽白。

再試試一下

var arr=[1, 8, 9, 5, 2];
arr.sort(compare);
/**
控制臺(tái)輸出
1 8 [1, 8, 9, 5, 2]
8 9 [1, 8, 9, 5, 2]
9 5 [1, 8, 9, 5, 2]
8 5 [1, 8, 9, 9, 2]
1 5 [1, 8, 8, 9, 2]
9 2 [1, 5, 8, 9, 2]
8 2 [1, 5, 8, 9, 9]
5 2 [1, 5, 8, 8, 9]
1 2 [1, 5, 5, 8, 9]
[1, 2, 5, 8, 9]
*/

沒跑了,這就是插入法鸟缕。再捋捋晶框,第一次冒泡完之后,前兩位肯是有序的懂从。第二次比較授段,如果發(fā)生位變化,a先向后移動(dòng)一位莫绣,b沒有直接前移,而是通過插入法找到正確的位置插入悠鞍,此時(shí)前三位有序对室。如果沒有發(fā)生位置變化,說明此時(shí)前三位已經(jīng)有序咖祭,繼續(xù)拿有序的最后一位和之后的一位比較掩宜。如此循環(huán),直至整個(gè)數(shù)組有序么翰。

到這里牺汤,我們得出了結(jié)論:sort()方法是使用的冒泡各插入兩種方式結(jié)合進(jìn)行排序的。 如果對(duì)排序不熟悉的同學(xué)浩嫌,可以看看——《十大經(jīng)典排序算法》

經(jīng)評(píng)論區(qū)大神的提醒檐迟,EMCAScript并沒有定義sort()方法使用的排序算法,各個(gè)瀏覽器實(shí)現(xiàn)的方式并不相同码耐。以上的結(jié)論我只在chrome和fireFox中存在追迟。以上結(jié)論在chrome和fireFox也并不完全正確,當(dāng)數(shù)組長(zhǎng)度過長(zhǎng)時(shí)骚腥,就不在是使用冒泡和插入兩種方式結(jié)合進(jìn)行排序了敦间,而是使用一種我不了解方法。先修改錯(cuò)誤的結(jié)論。等我弄清楚那種我不了解的方法廓块,再來更新_srot()方法厢绝。

童鞋你似不似以為到這里就完了,文章就完美結(jié)束了带猴?當(dāng)然不似!!!接下來,閑著沒事我們模仿sort(),實(shí)現(xiàn)一個(gè)和sort()方法功能一樣的自定義方法玩玩呀昔汉。

實(shí)現(xiàn)一個(gè)和sort()方法相似的_sort()方法

這里不多說,直接上代碼浓利。然后看注釋

Array.prototype._sort.f=function(a,b){ //設(shè)置默認(rèn)按照Unicode位點(diǎn)進(jìn)行排序
    a+="",b+="";
    return a<b?-1:a===b?0:1;
}

Array.prototype._sort=function(f){

    /**
    * 如未傳入實(shí)參
    * 或傳入的實(shí)參不是函數(shù)
    * 使用默認(rèn)的排序函數(shù) (按字符順序)
    */
    var f=f&&typeof(f)=="function"?f:Array.prototype._sort.f,
        len=this.length,
        i=0,
        t;
    /**
    * 這個(gè)循環(huán)開始排序
    * Array.sort()使用的是一種冒泡各插入結(jié)合的排序方法
    * 
    */
    for(i=0,t=undefined;i<len-1;i++){
        
        if(f(this[i],this[i+1])>0){ //大于零則需要交接位置
            t=this[i+1],this[i+1]=this[i];
        }
        
        /**
        * 如果t值是unfeined挤庇,
        * 則當(dāng)前的這次騎比較沒有發(fā)生位置變化
        * 也就不需要使用插入法了
        */
        if(t){
            //使用插入法找到正確的插入位置,上面排序算法還有優(yōu)化插入法排序的方法
            for(var j=i-1;j>=0;j--){
            
                if(f(this[j],t)>0){//如果當(dāng)前元素大于t,則當(dāng)前元素后移一位
                
                    this[j+1]=this[j];
                    
                }else{//否則表示找到插入點(diǎn)了贷掖,插入t,并退出循環(huán)
                
                    this[j+1]=t;
                    t=undefined;//將t設(shè)為undefined嫡秕,防止冒泡未發(fā)生替換就進(jìn)入插入法排序
                    break;
                    
                }
            }                       
        }           
    }
    return this; //返回排序后的新數(shù)組
}

到這里就完了?苹威?昆咽?No!No!No!雖然我們實(shí)現(xiàn)了_sort()方法,但是還有一個(gè)不完美的地方牙甫。說明第三點(diǎn)說了對(duì)undefined的處理規(guī)則掷酗,我們還沒有對(duì)unfined進(jìn)行任何處理呢。還需要在上面的排序循環(huán)開始之前添加這樣一段窟哺。

//這個(gè)循環(huán)把所有數(shù)組undefined的元素和數(shù)組最后一個(gè)不是undefined的元素替換
//不同瀏覽器對(duì)undefined處理方式不同泻轰,這里模仿chrome的處理方式
for(;i<len;i++){ 

    if(this[i]===undefined){ //
    
    /**
    * while找到最后一個(gè)(len-1)不是undefined的元素的下標(biāo)
    * 同時(shí)更新需要排序的元素個(gè)數(shù)(len)
    * 那些個(gè)undefined就不鳥它了
    * 下標(biāo)小于i的元素已經(jīng)檢查替換完成了,不需要再重復(fù)一次且轨。所以添加一個(gè)len>=i的條件
    */
    while(this[len-1]===undefined&&len>=i){ 
        len--;
    }
    
    /**
    * 如果len等于i
    * 就表示下標(biāo)不小于i的元素都是undefined了
    * 可以不用繼續(xù)遍歷了
    */
    if(len===i) break; 
    
    /**
    * 使用t將最后一個(gè)不是undefined的元素保存起來
    * i in this 是判斷這個(gè)元素是不存在浮声,還是值是undefined
    * 數(shù)組中一個(gè)不存在的元素,也會(huì)返回undefined(稀疏數(shù)組)
    * 這兩者還是有區(qū)別的
    * 如果不存在i in this會(huì)返回 false
    */
    t=this[len-1];
    if(i in this)
        this[len-1]=undefined; //元素值為undefined旋奢,直接將要替換元素值設(shè)為undefined
    else
        delete this[len-1]; //元素不存在泳挥,通過刪除將要替換的元素設(shè)置為不存在,
    
    this[i]=t; //替換undefined元素
    
    //又塞了一個(gè)undefinef到后面至朗,所以要排序的元素又少了一個(gè)屉符,再減減一下
    len--; 
    
    }

}

到這里是真結(jié)束了,謝謝大家锹引!如何有什么我說錯(cuò)了或者沒說明白的地方矗钟,歡迎大家留言一起討論,大家一起學(xué)習(xí)嫌变,共同進(jìn)步么真仲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市初澎,隨后出現(xiàn)的幾起案子秸应,更是在濱河造成了極大的恐慌虑凛,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件软啼,死亡現(xiàn)場(chǎng)離奇詭異桑谍,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)祸挪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門锣披,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人贿条,你說我怎么就攤上這事雹仿。” “怎么了整以?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵胧辽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我公黑,道長(zhǎng)邑商,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任凡蚜,我火速辦了婚禮人断,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘朝蜘。我一直安慰自己恶迈,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布谱醇。 她就那樣靜靜地躺著暇仲,像睡著了一般。 火紅的嫁衣襯著肌膚如雪枣抱。 梳的紋絲不亂的頭發(fā)上熔吗,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天辆床,我揣著相機(jī)與錄音佳晶,去河邊找鬼。 笑死讼载,一個(gè)胖子當(dāng)著我的面吹牛轿秧,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播咨堤,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼菇篡,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了一喘?” 一聲冷哼從身側(cè)響起驱还,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬榮一對(duì)情侶失蹤嗜暴,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后议蟆,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體闷沥,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年咐容,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了舆逃。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡戳粒,死狀恐怖路狮,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蔚约,我是刑警寧澤奄妨,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站炊琉,受9級(jí)特大地震影響展蒂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜苔咪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一锰悼、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧团赏,春花似錦箕般、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至体谒,卻和暖如春杯聚,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背抒痒。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來泰國(guó)打工幌绍, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人故响。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓傀广,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親彩届。 傳聞我的和親對(duì)象是個(gè)殘疾皇子伪冰,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • 概述 排序有內(nèi)部排序和外部排序,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序樟蠕,而外部排序是因排序的數(shù)據(jù)很大贮聂,一次不能容納全部...
    蟻前閱讀 5,167評(píng)論 0 52
  • 總結(jié)一下常見的排序算法靠柑。 排序分內(nèi)排序和外排序。內(nèi)排序:指在排序期間數(shù)據(jù)對(duì)象全部存放在內(nèi)存的排序吓懈。外排序:指在排序...
    jiangliang閱讀 1,326評(píng)論 0 1
  • 概述:排序有內(nèi)部排序和外部排序病往,內(nèi)部排序是數(shù)據(jù)記錄在內(nèi)存中進(jìn)行排序,而外部排序是因排序的數(shù)據(jù)很大骄瓣,一次不能容納全部...
    每天刷兩次牙閱讀 3,727評(píng)論 0 15
  • 1.插入排序—直接插入排序(Straight Insertion Sort) 基本思想: 將一個(gè)記錄插入到已排序好...
    依依玖玥閱讀 1,239評(píng)論 0 2
  • 1. 前段時(shí)間因?yàn)橐恍┕ぷ魃系氖虑殚爬福慌笥呀辛顺鋈ヅ锨冢谝粋€(gè)環(huán)境幽暗的咖啡廳。這種環(huán)境下最適合這幫文藝工作者們討論一...
    crius閱讀 3,791評(píng)論 68 102