————— 次日 —————程序員
————————————數組
假定20個隨機整數的值以下:bash
9,3,5,4,9,1,2,7,8,1,3,6,5,3,4,0,10,9 ,7,9優化
如何給這些無序的隨機整數排序呢?ui
很是簡單,讓咱們遍歷這個無序的隨機數列,每個整數按照其值對號入座,對應數組下標的元素進行加1操做。spa
好比第一個整數是9,那麼數組下標爲9的元素加1:code
第二個整數是3,那麼數組下標爲3的元素加1:cdn
繼續遍歷數列並修改數組......排序
最終,數列遍歷完畢時,數組的狀態以下:it
數組每個下標位置的值,表明了數列中對應整數出現的次數。
有了這個「統計結果」,排序就很簡單了。直接遍歷數組,輸出數組元素的下標值,元素的值是幾,就輸出幾回:
0,1,1,2,3,3,3,4,4,5,5,6,7,7,8,9,9,9,9,10
顯然,這個輸出的數列已是有序的了。
public static int[] countSort(int[] array) { //1.獲得數列的最大值 int max = array[0]; for(int i=1; i<array.length; i++){ if(array[i] > max){ max = array[i]; } } //2.根據數列最大值肯定統計數組的長度 int[] countArray = new int[max+1]; //3.遍歷數列,填充統計數組 for(int i=0; i<array.length; i++){ countArray[array[i]]++; } //4.遍歷統計數組,輸出結果 int index = 0; int[] sortedArray = new int[array.length]; for(int i=0; i<countArray.length; i++){ for(int j=0; j<countArray[i]; j++){ sortedArray[index++] = i; } } return sortedArray;}
public static void main(String[] args) { int[] array = new int[] {4,4,6,5,3,2,8,1,7,5,6,0,10}; int[] sortedArray = countSort(array); System.out.println(Arrays.toString(sortedArray));}複製代碼
這段代碼在一開頭補充了一個步驟,就是求得數列的最大整數值max。後面建立的統計數組countArray,長度就是max+1,以此保證數組的最後一個下標是max。
95,94,91,98,99,90,99,93,91,92
怎麼解決這個問題呢?
很簡單,咱們再也不以(輸入數列的最大值+1)做爲統計數組的長度,而是以(數列最大值和最小值的差+1)做爲統計數組的長度。
同時,數列的最小值做爲一個偏移量,用於統計數組的對號入座。
以剛纔的數列爲例,統計數組的長度爲 99-90+1 = 10 ,偏移量等於數列的最小值 90 。
對於第一個整數95,對應的統計數組下標是 95-90 = 5,如圖所示:
什麼意思呢?讓咱們看看下面的例子:
給定一個學生的成績表,要求按成績從低到高排序,若是成績相同,則遵循原表固有順序。
那麼,當咱們填充統計數組之後,咱們只知道有兩個成績並列95分的小夥伴,殊不知道哪個是小紅,哪個是小綠:
下面的講解會有一些燒腦,請你們扶穩坐好。咱們仍然以剛纔的學生成績表爲例,把以前的統計數組變造成下面的樣子:
這是如何變形的呢?統計數組從第二個元素開始,每個元素都加上前面全部元素之和。
爲何要相加呢?初次看到的小夥伴可能會以爲莫名其妙。
這樣相加的目的,是讓統計數組存儲的元素值,等於相應整數的最終排序位置。好比下標是9的元素值爲5,表明原始數列的整數9,最終的排序是在第5位。
接下來,咱們建立輸出數組sortedArray,長度和輸入數列一致。而後從後向前遍歷輸入數列:
第一步,咱們遍歷成績表最後一行的小綠:
小綠是95分,咱們找到countArray下標是5的元素,值是4,表明小綠的成績排名位置在第4位。
同時,咱們給countArray下標是5的元素值減1,從4變成3,,表明着下次再遇到95分的成績時,最終排名是第3。
第二步,咱們遍歷成績表倒數第二行的小白:
小白是94分,咱們找到countArray下標是4的元素,值是2,表明小白的成績排名位置在第2位。
同時,咱們給countArray下標是4的元素值減1,從2變成1,,表明着下次再遇到94分的成績時(實際上已經遇不到了),最終排名是第1。
第三步,咱們遍歷成績表倒數第三行的小紅:
小紅是95分,咱們找到countArray下標是5的元素,值是3(最初是4,減1變成了3),表明小紅的成績排名位置在第3位。
同時,咱們給countArray下標是5的元素值減1,從3變成2,,表明着下次再遇到95分的成績時(實際上已經遇不到了),最終排名是第2。
這樣一來,一樣是95分的小紅和小綠就可以清楚地排出順序了,也正所以,優化版本的計數排序屬於穩定排序。
後面的遍歷過程以此類推,這裏就再也不詳細描述了。
public static int[] countSort(int[] array) { //1.獲得數列的最大值和最小值,並算出差值d int max = array[0]; int min = array[0]; for(int i=1; i<array.length; i++) { if(array[i] > max) { max = array[i]; } if(array[i] < min) { min = array[i]; } } int d = max - min; //2.建立統計數組並統計對應元素個數 int[] countArray = new int[d+1]; for(int i=0; i<array.length; i++) { countArray[array[i]-min]++; } //3.統計數組作變形,後面的元素等於前面的元素之和 int sum = 0; for(int i=0;i<countArray.length;i++) { sum += countArray[i]; countArray[i] = sum; } //4.倒序遍歷原始數列,從統計數組找到正確位置,輸出到結果數組 int[] sortedArray = new int[array.length]; for(int i=array.length-1;i>=0;i--) { sortedArray[countArray[array[i]-min]-1]=array[i]; countArray[array[i]-min]--; } return sortedArray;}public static void main(String[] args) { int[] array = new int[] {95,94,91,98,99,90,99,93,91,92}; int[] sortedArray = countSort(array); System.out.println(Arrays.toString(sortedArray));}複製代碼
1.當數列最大最小值差距過大時,並不適用計數排序。
好比給定20個隨機整數,範圍在0到1億之間,這時候若是使用計數排序,須要建立長度1億的數組。不但嚴重浪費空間,並且時間複雜度也隨之升高。
2.當數列元素不是整數,並不適用計數排序。
若是數列中的元素都是小數,好比25.213,或是0.00000001這樣子,則沒法建立對應的統計數組。這樣顯然沒法進行計數排序。
—————END—————
喜歡本文的朋友們,歡迎長按下圖關注訂閱號程序員小灰,收看更多精彩內容