github.com/benz9527/toy-box/algo@v0.0.0-20240221120937-66c0c6bd5abd/sort/radix.go (about)

     1  package sort
     2  
     3  /*
     4  Sorts the elements by first grouping the individual digits of the same place value.
     5  Then, sort the elements according to their increasing / decreasing order.
     6  
     7  1. Find the largest element in the array, i.e. max. Let X be the number of digits in max. X is calculated because
     8  we have to go through all the significant places of all elements.
     9  In this array [121, 1, 788], we have the largest number 788. It has 3 digits. Therefore, the loop should go up to hundreds
    10  place (3 times).
    11  2.Go through each significant place one by one.
    12  */
    13  
    14  func getMax(arr []int, n int) (max int) {
    15  	max = arr[0]
    16  	for i := 1; i < n; i++ {
    17  		if arr[i] > max {
    18  			max = arr[i]
    19  		}
    20  	}
    21  	return max
    22  }
    23  
    24  func countingSort(arr []int, size int, place int) {
    25  	output := make([]int, size+1)
    26  	// 基数桶
    27  	count := make([]int, 10)
    28  
    29  	// calculate count of elements 计算数字的位数并存储
    30  	// 0-9 的索引代表了所有数字拆分后的各个位的具体数值, 由于默认使得 0-9 的 count array 是有序的,而且是稳定有序的
    31  	// count array 每在一个地方 + 1 表示就多一个元素
    32  	for i := 0; i < size; i++ {
    33  		// count[(arr[i] / place) % 10] = count[(arr[i] / place) % 10] + 1
    34  		count[(arr[i]/place)%10]++
    35  	}
    36  
    37  	// calculate cumulative cont
    38  	// 计算基数桶的边界索引,count[i] 的值为第 i 个桶的右边界索引 +1
    39  	// 这里不断累加也就是为了确定 count[i] 中元素的索引分布范围(可能包含多个相同的元素)
    40  	// count[i] 包括左侧元素的范围和本身元素的范围
    41  	for i := 1; i < 10; i++ {
    42  		count[i] += count[i-1]
    43  	}
    44  
    45  	// place the elements in sorted order
    46  	// 从右往左扫描,保证排序的稳定性
    47  	for i := size - 1; i >= 0; i-- {
    48  		// 元素个数转为索引必然要 - 1
    49  		output[count[(arr[i]/place)%10]-1] = arr[i]
    50  		// 每当一个元素找到直接的位置后 count[i] 就会减一
    51  		count[(arr[i]/place)%10]--
    52  	}
    53  
    54  	for i := 0; i < size; i++ {
    55  		arr[i] = output[i]
    56  	}
    57  }
    58  
    59  func RadixSort(arr []int) {
    60  	n := len(arr)
    61  	if n <= 1 {
    62  		return
    63  	}
    64  	max := getMax(arr, n)
    65  
    66  	for place := 1; max/place > 0; place *= 10 {
    67  		countingSort(arr, n, place)
    68  	}
    69  }