基數排序(RadixSort)是一種非比較型整數排序演演算法,其原理是將整數按位元數切割成不同的數位,然後按每個位數分別比較。由於整數也可以表達字串(比如名字或日期)和特定格式的浮點數,所以基數排序也不是隻能使用於整數。基數排序的發明可以追溯到1887年赫爾曼·何樂禮在列表機(Tabulation Machine)上的貢獻。
基數排序的方式可以採用LSD(Least significant digital)或MSD(Most significant digital),LSD的排序方式由鍵值的最右邊開始,而MSD則相反,由鍵值的最左邊開始。LSD使用計數排序或桶排序,MSD可以使用桶排序。由低到高(LSD)比較簡單,按位元重排即可,如果是從高往低(MSD)則不能每次重排,可以通過遞回來逐層遍歷實現。詳細請看各種不同版本的原始碼。
排序演演算法網上有很多實現,但經常有錯誤,也缺乏不同語言的比較。本系列把各種排序演演算法重新整理,用不同語言分別實現。
時間複雜度:O(k*N)
空間複雜度:O(k + N)
穩定性:穩定
class RadixSort { // 基數排序,基於計數排序,按數位從低到高來排序 public static int[] countingSort(int arr[], int exponent) { // 基數exponent按10進位,range為10 int range = 10; int[] countList = new int[range]; int[] sortedList = new int[arr.length]; // 設定最小值以支援負數 int min = arr[0]; for (int i = 0; i < arr.length; i++) { if (arr[i] < min) { min = arr[i]; } } // 根據基數求得當前專案對應位置的數值,並給對應計數陣列位置加1 for (int i = 0; i < arr.length; i++) { int item = arr[i] - min; // 根據exponent獲得當前位置的數位是幾,存入對應計數陣列 int idx = (item / exponent) % range; countList[idx] += 1; } // 根據位置計數,後面的位數為前面的累加之和 for (int i = 1; i < range; i++) { countList[i] += countList[i - 1]; } System.out.println("radixSort1 countingSort countList:" + Arrays.toString(countList)); // 根據計數陣列按順序取出排序內容 for (int i = arr.length - 1; i >= 0; i--) { int item = arr[i] - min; int idx = (item / exponent) % range; // 根據計數位置得到順序 sortedList[countList[idx] - 1] = arr[i]; countList[idx] -= 1; } // 最後賦值給原資料 for (int i = 0; i < arr.length; i++) { arr[i] = sortedList[i]; } System.out.println("radixSort1 -> sortedList:" + Arrays.toString(sortedList)); return sortedList; } // 基數排序1,按數位大小,基於計數排序實現 public static int[] radixSort1(int arr[]) { int max = arr[0]; for (int i = 0; i < arr.length; i++) { if (arr[i] > max) { max = arr[i]; } } // 根據最大值,逐個按進位(基數)來應用排序,exponent即數位。 for (int exponent = 1; (max / exponent) > 0; exponent *= 10) { countingSort(arr, exponent); } return arr; } }
// 基數排序,從高到低逐位排序,遞迴方式,基於桶排序。具體步驟如下: // 1. 找出陣列中最大的數,確定其位數。 // 2. MSD是從高位開始,依次按照位數的值將數位放入到不同桶中。 // 3. 如果桶裡的長度超過1,則通過遞迴繼續按桶排序。當桶裡的資料只有1位時新增到原列表對應位置。 // 重複步驟2和3,直到按照最高位排序完成。 class RadixSortMSD { static int[] radixSort(int[] arr) { int len = arr.length; // 獲取陣列最大項 int max = arr[0]; for (int i = 0; i < len; i++) { if (max < arr[i]) { max = arr[i]; } } // 獲取陣列最小項 int min = arr[0]; for (int i = 0; i < len; i++) { if (min > arr[i]) { min = arr[i]; } } // 獲取數位一共有幾位,減去min得到最大值,以支援負數和減少最大值 int numberOfDigits = (int) (Math.log10(max - min) + 1); int exponent = (int) (Math.pow(10, numberOfDigits - 1)); // 根據陣列最大值,自後向前逐個按數位基數(exponent)比較排序。 return bucketSort(arr, len, exponent); } static int[] bucketSort(int[] arr, int len, int exponent) { System.out.println("origin arr:" + Arrays.toString(arr) + " len=" + len + " exponent:" + exponent); if (len <= 1 || exponent < 1) { return arr; } // 獲取陣列最小項 int min = arr[0]; for (int i = 0; i < len; i++) { if (min > arr[i]) { min = arr[i]; } } // 位數按10遞進 int range = 10; // 定義桶二維陣列,長度為10,放入0-9的數位 int[][] buckets = new int[range][len]; // 記錄某個桶的最新長度,以便往桶內追加資料。 int[] bucketsCount = new int[range]; for (int i = 0; i < len; i++) { int item = arr[i] - min; // 根據數位上的值,把資料追加到對應的桶裡,減去min是支援負數 int bucketIdx = (item / exponent) % range; // 把資料按下標插入到桶裡 int numberIndex = bucketsCount[bucketIdx]; buckets[bucketIdx][numberIndex] = arr[i]; bucketsCount[bucketIdx] += 1; } // 將每個桶的資料按順序逐個取出,重新賦值給原陣列 int sortedIdx = 0; for (int i = 0; i < range; i++) { int[] bucket = buckets[i]; int bucketLen = bucketsCount[i]; // 如果只有一個值,則直接更新到原陣列 if (bucketsCount[i] == 1) { arr[sortedIdx] = bucket[0]; sortedIdx += 1; } else if (bucket.length > 0 && bucketLen > 0) { // 如果是陣列且記錄大於1則繼續遞迴呼叫,位數降低1位 // 遞迴呼叫傳參時需要傳入當前子序列、子序列長度、當前分解的位數基數 int[] sortedBucket = bucketSort(bucket, bucketLen, (int) (exponent / range)); // 依照已排序的子序列實際長度,把各個桶裡的值按順序賦給原陣列 for (int j = 0; j < bucketLen; j++) { int num = sortedBucket[j]; arr[sortedIdx] = num; sortedIdx += 1; } } } System.out.println("exponent:" + exponent + " sorted arr:" + Arrays.toString(arr)); return arr; }
""" 基數排序LSD版,本基於桶排序。 1. 找出陣列中最大的數,確定其位數。 2. LSD是低位到高位,依次按照位數的值將數位放入到不同桶中。 3. 按照桶順序重新給陣列排序。 重複步驟2和3,直到排序完成。 """ def radix_sort(arr): max_value = max(arr) # 找出陣列中最大的數 min_value = min(arr) #最小值,為了支援負數 digit = 1 # 從個位開始排序 # 每次排序一個數位,從低到高直到排序完成 while (max_value - min_value) // digit > 0: # 建立10個桶,分別對應0-9的數位值 buckets = [[] for _ in range(10)] for num in arr: # 找出當前位數的值 digit_num = (num - min_value) // digit % 10 # 將數位新增到對應數位的桶中,相當於根據數位排序 buckets[digit_num].append(num) print('buckets:', buckets) # 通過exend展開陣列,相當於逐層新增 arr = [] for bucket in buckets: arr.extend(bucket) # 或逐項新增 # for item in bucket: # arr.append(item) # 數位移動到下一位 digit *= 10 return arr
""" 基數排序,從高到低逐位排序,遞迴方式,基於桶排序。具體步驟如下: 1. 找出陣列中最大的數,確定其位數。 2. MSD是從高位開始,依次按照位數的值將數位放入到不同桶中。 3. 如果桶裡的長度超過1,則通過遞迴繼續按桶排序。當桶裡的資料只有1位時新增到原列表對應位置。 重複步驟2和3,直到按照最高位排序完成。 """ # 桶排序,根據數位遞迴呼叫 def bucket_sort(arr, exponent): print('origin arr:', arr, 'exponent:', exponent) if (len(arr) <= 1 or exponent <= 0): return arr min_value = min(arr) radix = 10 amount = 10 print('prepared arr:', arr, 'exponent:', exponent) # 構建排序的桶二維列表 buckets = [None] * radix for i in range(len(arr)): item = arr[i] - min_value # 根據數位上的值,把資料追加到對應的桶裡,減去min是支援負數 bucketIdx = int(item / exponent) % radix # 填充空桶,或者提前填充為列表 if buckets[bucketIdx] is None: buckets[bucketIdx] = [] buckets[bucketIdx].append(arr[i]) print('append to buckets:', buckets) # 將每個桶的資料按順序逐個取出,重新賦值給原陣列 sortedIdx = 0 for i in range(radix): bucket = buckets[i] if bucket is None or len(bucket) < 1: continue # 如果是陣列則繼續遞迴呼叫,位數降低1位 sortedBucket = bucket_sort(bucket, exponent // amount) # 把各個桶裡的值按順序賦給原陣列 for num in sortedBucket: print ('sortedIdx::', sortedIdx) arr[sortedIdx] = num print('bucket:', bucket, 'sortedBucket:', sortedBucket, 'sortedIdx:', sortedIdx, 'set arr:', arr) sortedIdx += 1 print('exponent:', exponent, 'sorted arr:', arr) return arr # 基數排序,從高到低逐位排序MSD版,基於桶排序遞迴實現 def radix_sort_msd(arr): # 根據最大值,逐個按進位(基數)來應用排序,從高位到低位。 # 獲取數位的數位,這減去min_value是為了支援負數 # exponent是最大的數位,由高到低逐位計算 max_value = max(arr) min_value = min(arr) numberOfDigits = int(math.log10(max_value - min_value) + 1) exponent = math.pow(10, numberOfDigits - 1) return bucket_sort(arr, int(exponent))
// 2. 基數排序LSD版,計算最小值,基於計數排序實現 func radixSort2(arr []int) []int { var arrLen = len(arr) // 基數exponent按10進位,amount為10 var amount = 10 var sortedList = make([]int, arrLen) var max = arr[0] for i := 0; i < arrLen; i++ { if arr[i] > max { max = arr[i] } } var min = arr[0] for i := 0; i < arrLen; i++ { if arr[i] < min { min = arr[i] } } // 根據基數求得當前專案對應位置的數值,並給對應計數陣列位置加1 // 按最大值補齊數位,基數exponent按10進位 for exponent := 1; ((max - min) / exponent) > 0; exponent *= amount { // 計數陣列,長度為10,0-9一共10個數位 countList := make([]int, amount) // 根據基數得到當前位數,並給計數陣列對應位置加1 for i := 0; i < arrLen; i++ { var item = arr[i] - min var idx = (item / exponent) % amount countList[idx] += 1 } // 計數排序構建,自前往後,逐個將上一項的值存入當前項 for i := 1; i < amount; i++ { countList[i] += countList[i-1] } fmt.Println("radixSort2 -> countList:", countList) // 根據計數陣列按順序取出排序內容 for i := arrLen - 1; i >= 0; i-- { item := arr[i] - min var idx = (item / exponent) % amount sortedList[countList[idx]-1] = arr[i] countList[idx] -= 1 } // 將新順序賦值給原陣列 for i := 0; i < arrLen; i++ { arr[i] = sortedList[i] } } return arr }
// 基數排序,從高到低逐位排序,遞迴方式,基於桶排序。具體步驟如下: // 1. 找出陣列中最大的數,確定其位數。 // 2. MSD是從高位開始,依次按照位數的值將數位放入到不同桶中。 // 3. 如果桶裡的長度超過1,則通過遞迴繼續按桶排序。當桶裡的資料只有1位時新增到原列表對應位置。 // 重複步驟2和3,直到按照最高位排序完成。 func radixSortMSD(arr []int) []int { var amount = 10 maxValue := max(arr) exponent := pow(amount, getNumberOfDigits(maxValue)-1) bucketSort(arr, exponent) return arr } func bucketSort(arr []int, exponent int) []int { fmt.Println("origin arr:", arr, "exponent: ", exponent) if exponent < 1 || len(arr) <= 1 { return arr } var amount = 10 fmt.Println("prepared arr:", arr, "exponent: ", exponent) buckets := [][]int{} // 按數位來獲取最小值 minValue := getMinValue(arr, exponent) // 增加偏移以便支援負數 offset := 0 if minValue < 0 { offset = 0 - minValue } // 填充桶二維陣列 for i := 0; i < (amount + offset); i++ { buckets = append(buckets, []int{}) } // 獲取陣列項指定數位的值,放入到對應桶中,桶的下標即順序 for i, num := range arr { bucketIdx := getDigit(arr, i, exponent) + offset buckets[bucketIdx] = append(buckets[bucketIdx], num) } fmt.Println("append to buckets: ", buckets) sortedIdx := 0 for _, bucket := range buckets { if len(bucket) <= 0 { continue } // 遞迴遍歷所有的桶,由裡而外逐個桶進行排序 sortedBucket := bucketSort(bucket, exponent/amount) // 把各個桶裡的值按順序賦給原陣列 for _, num := range sortedBucket { arr[sortedIdx] = num fmt.Println("bucket:", bucket, "sortedBucket: ", sortedBucket, "sortedIdx:", sortedIdx, "set arr: ", arr) sortedIdx += 1 } } fmt.Println("exponent: ", exponent, "sorted arr: ", arr) return arr } // 獲取數位位數 func getNumberOfDigits(num int) int { numberOfDigits := 0 for num > 0 { numberOfDigits += 1 num /= 10 } return numberOfDigits } // 獲取絕對值 func abs(value int) int { if value < 0 { return -value } return value } // 獲取陣列最大值 func max(arr []int) int { maxValue := arr[0] for i := 1; i < len(arr); i++ { if arr[i] > maxValue { maxValue = arr[i] } } return maxValue } // 計算數位次冪 func pow(a int, power int) int { result := 1 for i := 0; i < power; i++ { result *= a } return result } // 獲取陣列項指定數位的最小值 func getMinValue(arr []int, exponent int) int { minValue := getDigit(arr, 0, exponent) for i := 1; i < len(arr); i++ { element := getDigit(arr, i, exponent) if minValue > element { minValue = element } } return minValue } // 獲取數位指定數位的值,超出數位補0,負數返回負數 // 如: 1024, 百位: 100 => 返回 0 // 如: -2048, 千位: 1000 => 返回 -2 func getDigit(arr []int, idx int, exponent int) int { element := arr[idx] digit := abs(element) / exponent % 10 if element < 0 { return -digit } return digit }
// 基數排序2,從低到高逐個數位對比排序,基於桶排序,利用JS陣列展開來還原陣列 function radixSort2(arr) { // 倒數獲取數位指定位置的數 function getDigit(num, position) { const digit = Math.floor(num / Math.pow(10, position - 1)) % 10 return digit } // 獲取陣列最大數位的位數 function getNumberLength(num) { let maxLength = 0 while (num > 0) { maxLength++ num /= 10 } return maxLength } const max = Math.max.apply(null, arr) const min = Math.min.apply(null, arr) const maxLength = getNumberLength(max - min) for (let i = 0; i < maxLength; i++) { // 每個數位準備10個空陣列,用於放數位0-9 const buckets = Array.from({ length: 10 }, () => []) // 遍歷陣列將數位上的數放入對應桶裡 for (let j = 0, l = arr.length; j < l; j++) { const item = (arr[j] - min) // 從後往前獲取第x位置的數,通過計算的方式 const num = getDigit(item, i + 1) // 當前位數如果不為空則新增到基數桶中 if (num !== isNaN) { buckets[num].push((arr[j])) } } // 將桶逐級展開取出數位,如果支援flat則直接使用陣列的flat() if (buckets.flat) { arr = buckets.flat() } else { // 定定義陣列展開函數 // arr = flat(buckets) } } return arr }
// 基數排序,從高到低逐位排序,遞迴方式,基於桶排序。具體步驟如下: // 1. 找出陣列中最大的數,確定其位數。 // 2. MSD是從高位開始,依次按照位數的值將數位放入到不同桶中。 // 3. 如果桶裡的長度超過1,則通過遞迴繼續按桶排序。當桶裡的資料只有1位時新增到原列表對應位置。 // 重複步驟2和3,直到按照最高位排序完成。 function radixSortMSD(arr) { function bucketSort(arr, exponent) { console.log('origin arr:', arr, 'exponent:', exponent) if (!arr || arr.length <= 1 || exponent < 1) { return arr } const min = Math.min.apply(null, arr) const range = 10 // 定義桶二維陣列,長度為10,放入0-9的數位 const buckets = [] for (let i = 0; i < range; i++) { buckets[i] = [] } for (let i = 0, l = arr.length; i < l; i++) { const item = arr[i] - min // 根據數位上的值,把資料追加到對應的桶裡,減去min是支援負數 const bucketIdx = Math.floor(item / exponent % range) // 提前填充空桶或使用時再填充 if (!buckets[bucketIdx]) { buckets[bucketIdx] = [] } buckets[bucketIdx].push(arr[i]) } // 將每個桶的資料按順序逐個取出,重新賦值給原陣列 let sortedIdx = 0 for (let i = 0; i < range; i++) { const bucket = buckets[i] if (bucket && bucket.length > 0) { // 如果是陣列則繼續遞迴呼叫,位數降低1位 const sortedBucket = bucketSort(bucket, Math.floor(exponent / range)) // 把各個桶裡的值按順序賦給原陣列 sortedBucket.forEach(num => { arr[sortedIdx] = num sortedIdx += 1 }) } } return arr } const max = Math.max.apply(null, arr) const min = Math.min.apply(null, arr) // 獲取數位一共有幾位,減去min得到最大值,以支援負數和減少最大值 const numberOfDigits = Math.floor(Math.log10(max - min) + 1) const exponent = Math.pow(10, numberOfDigits - 1) // 根據陣列最大值,自後向前逐個按數位基數(exponent)比較排序。 return bucketSort(arr, exponent) }
class RadixSort { // 基數排序,基於計數排序的基礎上,按數位的每個位置來排序 countingSort(arr: Array<number>, exponent: number) { const countList = Array<number>() const range = 10 countList.length = range countList.fill(0) const min = Math.min.apply(null, arr) for (let i = 0, l = arr.length; i < l; i++) { const item = arr[i] - min // 取得數位的最後一位,並給對應計數陣列加1 const idx = Math.floor((item / exponent) % range) countList[idx] += 1 } console.log('countingSort countList:', countList) // 根據位置計數,後面的位數為前面的累加之和 for (let i = 1; i < range; i++) { countList[i] += countList[i - 1] } const sortedList = Array<number>() // 根據計數陣列按順序取出排序內容 for (let i = arr.length - 1; i >= 0; i--) { const item = arr[i] - min const idx = Math.floor((item / exponent) % range) sortedList[countList[idx] - 1] = arr[i] countList[idx] -= 1 } // 最後賦值給原資料 for (let i = 0; i < arr.length; i++) { arr[i] = sortedList[i] } return sortedList } // 基數排序LSD版,基於計數排序的基礎,支援負數,按數位的每個位置來排序 radixSort(arr: Array<number>) { let sortedList = Array<number>() const max = Math.max.apply(null, arr) const min = Math.min.apply(null, arr) for ( let exponent = 1; Math.floor((max - min) / exponent) > 0; exponent *= 10 ) { sortedList = this.countingSort(arr, exponent) } return sortedList } }
// 計數排序,根據基數按位元進行計數 void counting_sort(int arr[], int len, int exponent) { int sorted_list[len]; int range = 10; int count_list[range]; // 找出最小值 int min_value = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] < min_value) min_value = arr[i]; } memset(count_list, 0, range * sizeof(int)); // 根據數位所在位置進行計數 for (int i = 0; i < len; i++) { int item = arr[i] - min_value; int idx = (item / exponent) % range; count_list[idx]++; } // 構建計數排序,當前位置加上左側位置,後面的位數為前面的累加之和 for (int i = 1; i < range; i++) { count_list[i] += count_list[i - 1]; } // 構建輸出陣列,根據計數陣列按順序取得排序內容 for (int i = len - 1; i >= 0; i--) { int item = arr[i] - min_value; int idx = (item / exponent) % range; // 根據位置重排結果,減去min值還原資料 sorted_list[count_list[idx] - 1] = arr[i]; count_list[idx]--; } // 複製到陣列重排原始陣列 for (int i = 0; i < len; i++) { arr[i] = sorted_list[i]; } } // 基數排序,從低位到高位LSD版,基於計數排序 int *radix_sort(int arr[], int len) { int max_value = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] > max_value) max_value = arr[i]; } int min_value = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] < min_value) min_value = arr[i]; } // 根據最大值,逐個按進位(基數)來應用排序,exponent即數位基數,按個十百千遞增。 for (int exponent = 1; (max_value - min_value) / exponent > 0; exponent *= 10) { counting_sort(arr, len, exponent); } return arr; }
// 根據最大長度來獲取數位第n位的值,從前往後開始,前面不足最大長度時補零 int get_digit_by_position(int num, int position, int max_length) { if (num == 0) { return 0; } int number_length = (int)log10(num) + 1; // 查詢的位置加上自身長度不足最大長度則返回0 if ((position + number_length) < max_length) { return 0; } int exponent = (int)pow(10, number_length - position); int digit = 0; if (exponent > 0) { digit = (num / exponent) % 10; } return digit; } // 基數排序,從高位到逐個對比排序,通過桶排序遞迴呼叫 // arr是陣列,len是當前陣列長度,position為自前往後的位置,max_length是最大值的數位 int *bucket_sort(int arr[], int len, int position, int max_length) { printf("\r\nlen=%d position=%d max_length=%d ", len, position, max_length); if (len <= 1 || position > max_length) { return arr; } // 找出最小值 int min_value = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] < min_value) min_value = arr[i]; } int range = 10; // 桶一共從0-9十個數位 int buckets[range][len]; for (int i = 0; i < range; i++) { // 此處未提前使用,也可以不設定預設值 memset(buckets[i], 0, len * sizeof(int)); // print_array(buckets[i], len); } // 預設填充內容為0 int bucket_count_list[range]; memset(bucket_count_list, 0, range * sizeof(int)); for (int i = 0; i < len; i++) { int item = arr[i] - min_value; // 根據數位上的值,減去最小值,分配到對應的桶裡 int bucket_idx = get_digit_by_position(item, position, max_length); // 把資料按下標插入到桶裡 int number_idx = bucket_count_list[bucket_idx]; buckets[bucket_idx][number_idx] = arr[i]; bucket_count_list[bucket_idx] += 1; } // 將每個桶的資料按順序逐個取出,重新賦值給原陣列 int sorted_idx = 0; for (int i = 0; i < range; i++) { int *bucket = buckets[i]; int bucket_len = bucket_count_list[i]; int bucket_size = sizeof(*bucket) / sizeof(bucket[0]); // 如果只有一個值,則直接更新到原陣列 if (bucket_count_list[i] == 1) { arr[sorted_idx] = bucket[0]; sorted_idx += 1; } else if (bucket_size > 0 && bucket_len > 0) { // 如果是陣列且記錄追加大於1則繼續遞迴呼叫,位置增加1位 // 遞迴呼叫傳參時需要傳入當前子序列、子序列長度、當前分解的位數基數 int *sorted_bucket = bucket_sort(bucket, bucket_len, position + 1, max_length); // 依照已排序的子序列實際長度,把各個桶裡的值按順序賦給原陣列 for (int j = 0; j < bucket_len; j++) { int num = sorted_bucket[j]; arr[sorted_idx] = num; sorted_idx += 1; } } } printf("\r\n position:%d", position); print_array(arr, len); return arr; } // 計數排序,根據數位的位置逐個對比排序,從高到低MSD,遞迴方式 int *radix_sort_msd(int arr[], int len) { // 找出最大值 int max_value = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] > max_value) max_value = arr[i]; } // 獲取最小項 int min_value = arr[0]; for (int i = 0; i < len; i++) { if (min_value > arr[i]) { min_value = arr[i]; } } // 獲取數位一共有幾位,減去min得到最大值,以支援負數和減少最大值 int max_length = (int)(log10(max_value - min_value) + 1); // 根據陣列最大值的長度,從前往後逐個對比排序。 return bucket_sort(arr, len, 1, max_length); }
// 基數排序,從個位到高位LSD版,基於計數排序實現 int *radixSort(int *arr, int len) { // 以10倍遞進 int range = 10; int sortedList[len]; int max = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] > max) { max = arr[i]; } } int min = arr[0]; for (int i = 1; i < len; i++) { if (arr[i] < min) { min = arr[i]; } } // 根據最大值,逐個按進位(基數)來應用排序,exponent即基數。 for (int exponent = 1; ((max - min) / exponent) > 0; exponent *= range) { // 計數陣列,長度為10,0-9一共10個數位 int countList[range]; memset(countList, 0, range * sizeof(int)); // 根據基數得到當前位數,並給計數陣列對應位置加1 for (int i = 0; i < len; i++) { int item = arr[i] - min; int idx = (item / exponent) % range; countList[idx] += 1; } // 計數排序構建,自前往後,逐個將上一項的值存入當前項 for (int i = 1; i < range; i++) { countList[i] += countList[i - 1]; } // 根據計數陣列按順序取出排序內容 for (int i = len - 1; i >= 0; i--) { int item = arr[i] - min; int idx = (item / exponent) % range; sortedList[countList[idx] - 1] = arr[i]; countList[idx] -= 1; } // 複製輸出陣列到原始陣列 for (int i = 0; i < len; i++) { arr[i] = sortedList[i]; } } return arr; }
基數排序與計數排序、桶排序三者概念很像,但也有不同,其主要差異如下: 計數排序:根據陣列值設定若干個桶,每個桶對應一個數值,將這些桶的值分別存入下一個桶中用於排序,最後按順序取出對應桶裡的值。 桶排序:根據情況分為若干個桶,每個桶儲存一定範圍的數值,每個桶再單獨排序,最後按桶的順序取出全部資料。 基數排序:根據資料的位數來分配桶,每一位對應一個桶,先將全部資料的位數按最大位數對齊,再根據位數上的值大小排列。基數排序基於計數排序或者桶排序。
基數排序演演算法原始碼:https://github.com/microwind/algorithms/tree/master/sorts/radixsort
其他排序演演算法原始碼:https://github.com/microwind/algorithms