排序演算法(六)非比較排序----計數排序和基數排序
阿新 • • 發佈:2019-02-09
前邊的幾篇文章介紹的幾種排序演算法都是比較排序,接下來的文章將會介紹兩種非比較排序。
計數排序:
根據上圖的分析,需要按照最大的數的每個位都進行排序之後,整個陣列才會有序。 基數排序的缺陷:適用於資料比較集中的情況,不能對負數進行排序。 如果對以上的 求最大數的位數 的那種辦法不能理解,你可以採用一種理解起來比較簡單但是稍微麻煩的辦法:找出最大的數,然後求出他的位數。
計數排序通過雜湊的方法將一組資料對映到一個數組裡,最後將陣列中的數依次讀取,並寫進原來的陣列,讀出的資料就是有序的。
綜合以上圖片的分析,我們知道,儲存資料資訊的陣列(即就是計數的count陣列)的大小應該是最大數與最小數之差再加1. 下邊請看程式碼實現:計數排序,是比較快的排序,但是它卻有一定的缺陷。如果資料過於分散,計數排序的空間複雜度是比較高的(count陣列比較大)。如果資料很集中,計數排序就是比較快的。 基數排序 : 對一組資料進行排序,先按照其個位進行排序,然後按照十位進行排序,依次類推。//計數排序 void CountSort(int a[],int n) { assert(a); //找到陣列中的最大元素和最小元素 int min = a[0]; int max = a[0]; for(int i = 1; i < n; ++i) { if(a[i] > max) max = a[i]; if(a[i] < min) min = a[i]; } int range = max - min + 1; //開闢range大的count陣列 int* count = new int[range]; memset(count,0,sizeof(int) * range); //寫count陣列 for(int i = 0; i < n; ++i) { count[a[i] - min]++; } //讀count陣列,並寫a陣列 int index = 0; for(int i = 0; i < range; ++i) { while(count[i]--) { a[index++] = i + min; } } }
下邊給出程式碼實現:
//求最大數的位數 int GetMaxDigit(int a[],int n) { int base = 10; int digit = 1; int i = 0; for(int i = 0; i< n ; ++i) { while(a[i] >= base) { digit ++; base *= 10; } } return digit; } //基數排序 void LSDSort(int a[],int n) { assert(a); int digit = GetMaxDigit(a,n); int base = 1; //定義一個count陣列 int count[10] = {0}; int start[10] = {0}; int* tmp = new int[n]; while(digit--) { memset(count,0,sizeof(int) * 10); start[0] = 0; //寫count陣列 for(int i = 0; i < n; ++i) { count[(a[i]/base) % 10]++; } //寫start陣列 for(int i = 1; i < 10; ++i) { start[i] = start[i - 1] + count[i - 1]; } //讀a陣列,寫tmp數 int num = 0; for(int i = 0; i < n; ++i) { num = (a[i]/base) % 10; tmp[start[num]] = a[i]; start[num]++; } //將tmp陣列寫回a陣列 for(int i = 0; i < n; ++i) { a[i] = tmp[i]; } base *= 10; } delete[] tmp; }
根據上圖的分析,需要按照最大的數的每個位都進行排序之後,整個陣列才會有序。 基數排序的缺陷:適用於資料比較集中的情況,不能對負數進行排序。 如果對以上的 求最大數的位數 的那種辦法不能理解,你可以採用一種理解起來比較簡單但是稍微麻煩的辦法:找出最大的數,然後求出他的位數。