さまざまなプログラミング言語における基数ソートの原理と実装方法
説明
RadixSort は、非比較整数ソート アルゴリズムです。その原理は、整数を桁ごとに異なる数値に分割し、各桁を比較することです。別々に。整数は文字列 (名前や日付など) や浮動小数点数を特定の形式で表すこともできるため、基数ソートは整数に限定されません。基数ソートの発明は、ハーマン ホレリーが集計マシンに取り組んだ 1887 年に遡ります。基数ソート方法では、LSD (最下位デジタル) または MSD (最上位デジタル) を使用できます。LSD のソート方法は、最右端から開始されます。 MSD ソート方法はキー値の左端から開始されます。 LSD はカウンティング ソートまたはバケット ソートを使用し、MSD はバケット ソートを使用できます。 Low to High (LSD) は少しずつ並べ替えるだけで比較的単純ですが、High to Low (MSD) の場合は毎回並べ替えることはできず、再帰によって層ごとにたどることで実現できます。詳細については、各バージョンのソースコードを参照してください。
インターネット上には並べ替えアルゴリズムの実装が多数ありますが、多くの場合エラーが含まれており、異なる言語での比較が不足しています。このシリーズは、さまざまな並べ替えアルゴリズムを再編成し、さまざまな言語で実装します。
実装手順
- ソート対象の数値列(正の整数)を同じ桁長に統一し、短い桁をゼロで埋めます。
- 各桁は、最低から最高、または最高から最低の順に個別に並べ替えられます。
- 最低値から高値へ、または高値から低値へソートすると、シーケンスは順序付けされたシーケンスになります。
- 概略図
##パフォーマンス分析
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;
}
ログイン後にコピー
Pythonclass 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))
ログイン後にコピー
Go""" 基数排序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
}
ログイン後にコピー
JS// 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)
}
ログイン後にコピー
TS// 基数排序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
}
}
ログイン後にコピー
Cclass 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);
}
ログイン後にコピー
C // 计数排序,根据基数按位进行计数 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;
}
ログイン後にコピーLink基数ソート、カウンティング ソート、およびバケット ソートの違い基数ソート、カウンティング ソート、およびバケット ソートの概念は非常に似ていますが、相違点もあります。主な違いは次のとおりです:
カウントソート: 配列の値に従って複数のバケットを設定し、各バケットは値に対応し、これらのバケットの値を次のバケットに保存してソートし、最後に対応するバケットの値を取り出します。バケツを順番に。 バケットソート: 状況に応じていくつかのバケットに分割し、各バケットに一定範囲の値を格納し、各バケットを個別にソートし、最終的にバケットの順序ですべてのデータを取り出します。 基数ソート: データの桁数に応じてバケットを割り当てます。各ビットがバケットに対応します。まず、すべてのデータの桁を最大桁数に従って整列し、次に次のように配置します。数字の値。基数ソートは、カウントソートまたはバケットソートに基づいています。 // 基数排序,从个位到高位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; }
以上がさまざまなプログラミング言語における基数ソートの原理と実装方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









PHPとPythonには独自の利点と短所があり、選択はプロジェクトのニーズと個人的な好みに依存します。 1.PHPは、大規模なWebアプリケーションの迅速な開発とメンテナンスに適しています。 2。Pythonは、データサイエンスと機械学習の分野を支配しています。

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

Pytorch GPUアクセラレーションを有効にすることで、CentOSシステムでは、PytorchのCUDA、CUDNN、およびGPUバージョンのインストールが必要です。次の手順では、プロセスをガイドします。CUDAおよびCUDNNのインストールでは、CUDAバージョンの互換性が決定されます。NVIDIA-SMIコマンドを使用して、NVIDIAグラフィックスカードでサポートされているCUDAバージョンを表示します。たとえば、MX450グラフィックカードはCUDA11.1以上をサポートする場合があります。 cudatoolkitのダウンロードとインストール:nvidiacudatoolkitの公式Webサイトにアクセスし、グラフィックカードでサポートされている最高のCUDAバージョンに従って、対応するバージョンをダウンロードしてインストールします。 cudnnライブラリをインストールする:

DockerはLinuxカーネル機能を使用して、効率的で孤立したアプリケーションランニング環境を提供します。その作業原則は次のとおりです。1。ミラーは、アプリケーションを実行するために必要なすべてを含む読み取り専用テンプレートとして使用されます。 2。ユニオンファイルシステム(UnionFS)は、違いを保存するだけで、スペースを節約し、高速化する複数のファイルシステムをスタックします。 3.デーモンはミラーとコンテナを管理し、クライアントはそれらをインタラクションに使用します。 4。名前空間とcgroupsは、コンテナの分離とリソースの制限を実装します。 5.複数のネットワークモードは、コンテナの相互接続をサポートします。これらのコア概念を理解することによってのみ、Dockerをよりよく利用できます。

Pytorchの分散トレーニングでは、Centosシステムでトレーニングには次の手順が必要です。Pytorchのインストール:PythonとPipがCentosシステムにインストールされていることです。 CUDAバージョンに応じて、Pytorchの公式Webサイトから適切なインストールコマンドを入手してください。 CPUのみのトレーニングには、次のコマンドを使用できます。PipinstalltorchtorchtorchvisionTorchaudioGPUサポートが必要な場合は、CUDAとCUDNNの対応するバージョンがインストールされ、インストールに対応するPytorchバージョンを使用してください。分散環境構成:分散トレーニングには、通常、複数のマシンまたは単一マシンの複数GPUが必要です。場所

PytorchをCentosシステムにインストールする場合、適切なバージョンを慎重に選択し、次の重要な要因を検討する必要があります。1。システム環境互換性:オペレーティングシステム:Centos7以上を使用することをお勧めします。 Cuda and Cudnn:PytorchバージョンとCudaバージョンは密接に関連しています。たとえば、pytorch1.9.0にはcuda11.1が必要ですが、pytorch2.0.1にはcuda11.3が必要です。 CUDNNバージョンは、CUDAバージョンとも一致する必要があります。 Pytorchバージョンを選択する前に、互換性のあるCUDAおよびCUDNNバージョンがインストールされていることを確認してください。 Pythonバージョン:Pytorch公式支店

PytorchをCentosの最新バージョンに更新すると、次の手順に従うことができます。方法1:PIPでPIPを更新する:最初にPIPが最新バージョンであることを確認します。これは、PIPの古いバージョンがPytorchの最新バージョンを適切にインストールできない可能性があるためです。 pipinstall- upgradepipアンインストール古いバージョンのpytorch(インストールの場合):pipuninstorchtorchtorchvisiontorchaudioインストール最新

VSコードでは、次の手順を通じて端末でプログラムを実行できます。コードを準備し、統合端子を開き、コードディレクトリが端末作業ディレクトリと一致していることを確認します。プログラミング言語(pythonのpython your_file_name.pyなど)に従って実行コマンドを選択して、それが正常に実行されるかどうかを確認し、エラーを解決します。デバッガーを使用して、デバッグ効率を向上させます。
