靈光一閃的排序算法與靠譜的計數(shù)排序

自己閑來沒事亂寫的排序算法

假設(shè)我們有正要待排序的數(shù)組A,它的區(qū)間是[0,k],0~k均是有限大小的整數(shù)撑螺。接下來我們初始化一個k+1長度的數(shù)據(jù)B吏砂,并把它所有的值都初始化為-1(只因為它是負數(shù)蝇恶,可以用來區(qū)別將要進行排序的數(shù)據(jù)拳魁,因為要排序的數(shù)據(jù)都>=0)。
那我們現(xiàn)在就有兩個數(shù)組了撮弧。假設(shè)A數(shù)組的值是{5,0,2,3,1}:

1.最開始初始化

原諒我自己手畫的潘懊,工作時間擠出來,見諒見諒贿衍。

因為A數(shù)組中最大的為5授舟,那B數(shù)組中數(shù)組長度為(5+1),為6贸辈,初始化之后B數(shù)組的初始值為-1释树。
接下來就是給B數(shù)組賦值了。我們把A數(shù)組中的值對應(yīng)B數(shù)組的下標擎淤,把A數(shù)組中的下標對應(yīng)B數(shù)組的值奢啥,比如:A[0]=5->B[5]=0,A[1]=0->B[0]=1;這樣我們就可根據(jù)B數(shù)組知道:A中的5存儲在下標為0,也就是第一個位置上嘴拢,A中的0保存在下標為1也就是第二個位置上桩盲。這樣操作了之后如下圖:

經(jīng)過上訴操作之后B數(shù)組的值

從B數(shù)組我們也就知道了A數(shù)組中的信息。第三步席吴,我們需要一個新的數(shù)組C赌结,用來保存A數(shù)組中的信息。
如下:

C數(shù)組與A數(shù)組保存數(shù)據(jù)一致

這個C數(shù)組會在接下來說明抢腐。接下來我們我們將一個一個的從B數(shù)組中取出數(shù)據(jù)用來當(dāng)C數(shù)組的下標取出重新賦值給A數(shù)組姑曙。按前面的我們知道襟交,從B數(shù)組我們知道迈倍,A數(shù)組中最小的是下標為1的位置。接下來是下標為4的位置捣域,最大的數(shù)據(jù)在下標為0 的位置啼染。處理之后,A數(shù)組就變成了:

最終結(jié)果

java實現(xiàn)代碼:

public void sort(int[] aDatas) { 
   //根據(jù)A數(shù)組中的最大值得到B數(shù)組中長度 
 int bDataLength = getMaxNum(aDatas)+1; 
   //得到A與C數(shù)組的長度   
 int cLength = aDatas.length;   
 //接下來初始化C數(shù)組  
 int[] cDatas = new int[cLength];  
 for (int i = 0; i < cLength; i++) {   
     cDatas[i] = aDatas[i];   
 }  
  //接下來處理B數(shù)組中的值  
 int[] bDatas = new int[bDataLength];   
 for (int i = 0; i < bDataLength; i++) {     
   bDatas[i] = -1;   
 }  
  //根據(jù)A數(shù)組賦值給B數(shù)組  
 for (int i = 0; i < cLength; i++) {    
    bDatas[aDatas[i]] = i;    }    
//用于記錄A數(shù)組中的有效位置   
 int numberLeng = 0;   
 //進行大小位置正確放置  
  for (int i = 0; i < bDataLength; i++) {  
  if (bDatas[i] != -1) {     
  int index = bDatas[i];    
  int temp = cDatas[index];   
 aDatas[numberLeng] = temp;        
 numberLeng++;  
     }   
 }
}


public int getMaxNum(int[] datas) { 
   int max = 0;   
 int length = datas.length;  
  for (int i = 0; i < length; i++) {   
     if (datas[i] > max) {     
       max = datas[i];    
    } 
   }    
return max ;
}
public static void main(String[] args) {  
  int[] datas = new int[]{5,0,2,3,1};  
  new BucketSort().sort(datas);  
  for (int i = 0; i < datas.length; i++) {  
      System.out.println(datas[i]); 
   }}

來看看結(jié)果

0
1
2
3
5

然后覺得不對宴合,我這樣寫如果有重復(fù)的元素,肯定排序就不正確迹鹅。當(dāng)然可以再用一個數(shù)組D來記錄下重復(fù)的元素卦洽。可是這樣就太麻煩了斜棚,太復(fù)雜了阀蒂,并且要排序的數(shù)據(jù)不要太大,要不然B數(shù)組太大弟蚀,效率也不高蚤霞。后來回家翻了下算法導(dǎo)論發(fā)現(xiàn)計數(shù)排序和我這個非常相似。書是好東西义钉,得經(jīng)常翻翻昧绣。


計數(shù)排序

現(xiàn)在可以進入正題了。
應(yīng)該都知道冒泡排序捶闸,快速排序夜畴,選擇排序等等都是通過比較兩個數(shù)據(jù)大小來進行排序的。而它們的時間復(fù)雜度以及穩(wěn)定性如下 :


計數(shù)排序是時間效率為O(n)的計數(shù)排序删壮。所謂排序算法贪绘,無非就是把正確的元素放到正確的位置,計數(shù)排序就是計算相同key的元素各有多少個央碟,然后根據(jù)出現(xiàn)的次數(shù)累加而獲得最終的位置信息兔簇。但是計數(shù)排序有兩個限制條件,那就是存在一個正整數(shù)K硬耍,使得數(shù)組里面的所有元素的key值都不大于N垄琐,且key值都是非負整數(shù)。
計數(shù)排序算法步驟大概有三個步驟:

  • 建一個長度為K+1的的數(shù)組B经柴,里面的每一個元素初始都置為0(Java里面默認就是0)狸窘。我自己寫的是將B數(shù)組初始化為一個固定負數(shù),如-1
  • 遍歷待排序的數(shù)組坯认,計算其中的每一個元素出現(xiàn)的次數(shù)翻擒,比如一個key為i的元素出現(xiàn)了3次,那么C[i]=3牛哺。這里是記錄元素出現(xiàn)的次數(shù)陋气,我只是記錄下標,所以我不能處理重復(fù)數(shù)據(jù)引润,而計數(shù)法可以
  • 累加B數(shù)組巩趁,獲得元素的排位,從0開始遍歷B, B[i+1]=B[i]+B[i-1]
  • 建一個臨時數(shù)組C淳附,長度與待排序數(shù)組一樣议慰。從數(shù)組末尾遍歷待排序數(shù)組蠢古,把元素都安排到C里面,直接從B里面就可以得到元素的具體位置别凹, 不過記得每處理過一個元素之后都要把B里面對應(yīng)位置的計數(shù)減1草讶。為什么要從末尾開始遍歷呢,是為保證排序算法的穩(wěn)定性炉菲。
    現(xiàn)在又用的我手工圖給大家講解一下:

1.假設(shè)A數(shù)組內(nèi)容為{5,0,2,3,2}這里我故意加了個重復(fù)元素

A與B初始化

2.在A的值對應(yīng)B的下標加1

對B進行賦值

上圖B數(shù)組中表示A中0有一個堕战,1有0個,2有兩個拍霜,3有一個践啄,4有零個,5有一個。

  1. B[i]=B[i]+B[i-1]
B數(shù)組最終的樣子

4.新建一個數(shù)組C與A有相同的值,從數(shù)組末尾遍歷A數(shù)組沉御,直接從B里面就可以得到元素的具體位置屿讽, 不過記得每處理過一個元素之后都要把B里面對應(yīng)位置的計數(shù)減1。
這里圖顯示一下前兩次循環(huán)的結(jié)果:

前兩次循環(huán)排序結(jié)果

下面是java的實現(xiàn)代碼:

public static void countSort(int[] aDatas) throws Exception { 
   if (aDatas.length <= 1) { 
       return; 
   }   
 int range = getMaxNum(aDatas);
int[] bDatas = new int[range + 1];  
  for (int i = 0; i < aDatas.length; i++) {   
   int value = aDatas[i];     
   bDatas[value] += 1;  
  }   
 for (int i = 1; i < bDatas.length; i++) {     
  bDatas[i] += bDatas[i - 1];  
  }   
 int[] cDatas = new int[aDatas.length];   
 for (int i = aDatas.length - 1; i >= 0; i--) {    
 int value = aDatas[i];    
  int position = bDatas[value] - 1;      
  cDatas[position] = value;      
  bDatas[value] -= 1; 
   }    
for (int i = 0; i < aDatas.length; i++) {  
      aDatas[i] = cDatas[i]; 
   }
}
public static int getMaxNum(int[] datas) { 
   int max = 0; 
   int length = datas.length; 
   for (int i = 0; i < length; i++) {   
     if (datas[i] > max) {    
        max = datas[i];   
     }   
 }   
 return max;}
public static void main(String[] args) throws Exception {
 int[] array = {5, 0, 2, 3, 2};   
countSort(array);   
 for (int i = 0; i < array.length; i++) {     
   System.out.println(array[i]); 
   }}
0
2
2
3
5

有種在以前上學(xué)時打草稿的感覺吠裆。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末伐谈,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子试疙,更是在濱河造成了極大的恐慌诵棵,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件祝旷,死亡現(xiàn)場離奇詭異履澳,居然都是意外死亡,警方通過查閱死者的電腦和手機怀跛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門距贷,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人吻谋,你說我怎么就攤上這事忠蝗。” “怎么了漓拾?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵阁最,是天一觀的道長。 經(jīng)常有香客問我骇两,道長速种,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任低千,我火速辦了婚禮配阵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己闸餐,他們只是感情好饱亮,可當(dāng)我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布矾芙。 她就那樣靜靜地躺著舍沙,像睡著了一般。 火紅的嫁衣襯著肌膚如雪剔宪。 梳的紋絲不亂的頭發(fā)上拂铡,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天,我揣著相機與錄音葱绒,去河邊找鬼感帅。 笑死,一個胖子當(dāng)著我的面吹牛地淀,可吹牛的內(nèi)容都是我干的失球。 我是一名探鬼主播,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼帮毁,長吁一口氣:“原來是場噩夢啊……” “哼实苞!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起烈疚,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤黔牵,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后爷肝,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體猾浦,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年灯抛,在試婚紗的時候發(fā)現(xiàn)自己被綠了金赦。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡对嚼,死狀恐怖素邪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情猪半,我是刑警寧澤兔朦,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站磨确,受9級特大地震影響沽甥,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜乏奥,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一摆舟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦恨诱、人聲如沸媳瞪。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛇受。三九已至,卻和暖如春厕鹃,著一層夾襖步出監(jiān)牢的瞬間兢仰,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工剂碴, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留把将,地道東北人。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓忆矛,卻偏偏與公主長得像察蹲,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子催训,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,979評論 2 355

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