排序算法 --- 計(jì)數(shù)排序

前面說的那些排序算法,都是要通過比較來實(shí)現(xiàn)的晦毙。排序還能不通過比較來實(shí)現(xiàn)生巡?是的,計(jì)數(shù)排序就是這么神奇见妒。

一、排序思想

創(chuàng)建一個(gè)計(jì)數(shù)數(shù)組甸陌,利用數(shù)組下標(biāo)來表示該元素须揣,用數(shù)組下標(biāo)對應(yīng)的值來表示元素出現(xiàn)的次數(shù)。然后遍歷計(jì)數(shù)數(shù)組即可钱豁。比如下標(biāo)為5耻卡,元素值為2,表示5出現(xiàn)兩次牲尺,連續(xù)寫兩次5即可卵酪。


歡迎大家關(guān)注我的公眾號 javawebkf,目前正在慢慢地將簡書文章搬到公眾號谤碳,以后簡書和公眾號文章將同步更新溃卡,且簡書上的付費(fèi)文章在公眾號上將免費(fèi)。


1. 案例:

假如待排序列arr如下:

5   7    4    8   3    5

最大元素是8蜒简,所以創(chuàng)建一個(gè)最大下標(biāo)為8的數(shù)組:

int[] count = new int[9];

遍歷待排序列瘸羡,第一個(gè)是5,所以count[5]++]搓茬,第二個(gè)是7犹赖,所以count[7]++……
最終count數(shù)組就是:

0   0   0   1   1   2   0   1   1   // 元素值
0   1   2   3   4   5   6   7   8   // 下標(biāo)

最后根據(jù)count數(shù)組,可以知道卷仑,3出現(xiàn)一次峻村,4出現(xiàn)一次,5出現(xiàn)兩次……就可以知道排序后應(yīng)該是這樣的:

3   4   5   5   7   8

這樣看似很完美锡凝,但是會存在兩個(gè)問題粘昨。

2. 問題一:

上面的5出現(xiàn)了兩次,最后排完序的的數(shù)組中下標(biāo)為2的那個(gè)5私爷,還是原序列中下標(biāo)為0的那個(gè)5嗎雾棺?也就是說,當(dāng)值相同的情況下衬浑,無法保證排序后相同元素出現(xiàn)的順序和排序前一致捌浩,這也就是我們說的不穩(wěn)定排序。如何優(yōu)化呢工秩?

我們給之前的數(shù)組中兩個(gè)5做上標(biāo)記尸饺,便于區(qū)分:

小紅                                      小白
5       7        4        8       3       5
  • 然后和之前一樣进统,統(tǒng)計(jì)每個(gè)元素出現(xiàn)的次數(shù),得到count數(shù)組:
0   0   0   1   1   2   0   1   1   // 元素值
0   1   2   3   4   5   6   7   8   // 下標(biāo)
  • 接下來浪听,對count數(shù)組進(jìn)行變形螟碎,然后一個(gè)元素加上前一個(gè)元素,即:
count[i] = count[i] + count[i-1];

這樣一來迹栓,count數(shù)組就變成了:

0   0   0   1   2   4   4   5   6 // 元素值
0   1   2   3   4   5   6   7   8 // 下標(biāo)
  • 然后掉分,創(chuàng)建一個(gè)新數(shù)組resultArr,長度和原數(shù)組arr一樣克伊。從后往前遍歷原數(shù)組arr酥郭,第一個(gè)是5,標(biāo)記是小白愿吹,count[5]的值是4不从,表示小白排第四位,所以resultArr[4-1] = 5犁跪,同時(shí)count[5]--椿息,即把4變成3,下一個(gè)5就表示排第三位坷衍,小紅就排第三寝优,和原數(shù)組的順序一致。這樣一來惫叛,就將計(jì)數(shù)排序變成穩(wěn)定的了倡勇。

3. 問題二:

假如現(xiàn)有待排序列arr如下:

999   998   1000  995

按照之前的說法,count數(shù)組的最大下標(biāo)是arr數(shù)組最大值嘉涌,即如果要排這四個(gè)數(shù)妻熊,需要?jiǎng)?chuàng)建長度為1001的數(shù)組。而且仑最,下標(biāo)0到994的這些空間都用不到扔役,白白浪費(fèi)了。所以警医,count數(shù)組的長度應(yīng)該是max(arr) - min(arr) + 1亿胸,即用最大值減去最小值再加1即可。此案例中预皇,count的長度就是1000 - 995 + 1 = 6侈玄,那么每個(gè)元素應(yīng)該放在哪個(gè)下標(biāo)上呢?每個(gè)元素都減去最小元素吟温,得出來的值就對應(yīng)count的下標(biāo)序仙。比如999 - 995 = 4,那么999就應(yīng)該對應(yīng)count[4]鲁豪。

4. 計(jì)數(shù)排序的缺點(diǎn):
從上面的分析可以知道潘悼,計(jì)數(shù)排序適合分布比較集中的數(shù)據(jù)律秃,即最大值和最小值相差不多,如果相差特別多治唤,就會很耗費(fèi)空間棒动。

二、代碼實(shí)現(xiàn)

public static void countSort(int[] arr) {
    if (arr == null || arr.length == 1) {
        return;
    }
    // 1. 找到數(shù)組中最大的數(shù)和最小的數(shù)
    int max = arr[0];
    int min = arr[0];
    for (int i=1; i<arr.length; i++) {
        max = arr[i] > max ? arr[i] : max;
        min = arr[i] < min ? arr[i] : min;
    }
    // 2. 定義count數(shù)組
    int[] count = new int[max - min + 1];
    // 3. 遍歷原數(shù)組宾添,進(jìn)行計(jì)數(shù)
    for (int i=0; i<arr.length; i++) {
        count[arr[i] - min]++;
    }
    // 4. 對count數(shù)組進(jìn)行變形船惨,讓計(jì)數(shù)排序變成穩(wěn)定的
    for (int i=1; i<count.length; i++) {
        count[i] += count[i-1];
    }
    // 5. 創(chuàng)建接收結(jié)果的數(shù)組
    int[] result = new int[arr.length];
    // 6. 倒序遍歷原數(shù)組,并且將結(jié)果存到result數(shù)組中
    for (int i=arr.length-1; i>=0; i--) {
        result[count[arr[i] - min] - 1] = arr[i];
        count[arr[i] - min] --;
    }
    // 7. 把result數(shù)組拷貝回原數(shù)組即可
    System.arraycopy(result, 0, arr, 0,  arr.length);
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末缕陕,一起剝皮案震驚了整個(gè)濱河市掷漱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌榄檬,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衔统,死亡現(xiàn)場離奇詭異鹿榜,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)锦爵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評論 2 384
  • 文/潘曉璐 我一進(jìn)店門舱殿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人险掀,你說我怎么就攤上這事沪袭。” “怎么了樟氢?”我有些...
    開封第一講書人閱讀 156,723評論 0 345
  • 文/不壞的土叔 我叫張陵冈绊,是天一觀的道長。 經(jīng)常有香客問我埠啃,道長死宣,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評論 1 283
  • 正文 為了忘掉前任碴开,我火速辦了婚禮毅该,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘潦牛。我一直安慰自己眶掌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評論 5 384
  • 文/花漫 我一把揭開白布巴碗。 她就那樣靜靜地躺著朴爬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪良价。 梳的紋絲不亂的頭發(fā)上寝殴,一...
    開封第一講書人閱讀 49,760評論 1 289
  • 那天蒿叠,我揣著相機(jī)與錄音,去河邊找鬼蚣常。 笑死市咽,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的抵蚊。 我是一名探鬼主播施绎,決...
    沈念sama閱讀 38,904評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼贞绳!你這毒婦竟也來了谷醉?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評論 0 266
  • 序言:老撾萬榮一對情侶失蹤冈闭,失蹤者是張志新(化名)和其女友劉穎俱尼,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體萎攒,經(jīng)...
    沈念sama閱讀 44,118評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡遇八,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了耍休。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片刃永。...
    茶點(diǎn)故事閱讀 38,599評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖羊精,靈堂內(nèi)的尸體忽然破棺而出斯够,到底是詐尸還是另有隱情,我是刑警寧澤喧锦,帶...
    沈念sama閱讀 34,264評論 4 328
  • 正文 年R本政府宣布读规,位于F島的核電站,受9級特大地震影響裸违,放射性物質(zhì)發(fā)生泄漏掖桦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評論 3 312
  • 文/蒙蒙 一供汛、第九天 我趴在偏房一處隱蔽的房頂上張望枪汪。 院中可真熱鬧,春花似錦怔昨、人聲如沸雀久。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽赖捌。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間越庇,已是汗流浹背罩锐。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評論 1 264
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卤唉,地道東北人涩惑。 一個(gè)月前我還...
    沈念sama閱讀 46,286評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像桑驱,于是被迫代替她去往敵國和親竭恬。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評論 2 348