다양한 프로그래밍 언어에서의 기수 정렬의 원리와 구현 방법
Explanation
RadixSort는 비비교 정수 정렬 알고리즘의 원리는 정수를 숫자별로 다른 숫자로 자른 다음 각 숫자를 개별적으로 비교하는 것입니다. 정수는 특정 형식의 문자열(예: 이름 또는 날짜)과 부동 소수점 숫자를 나타낼 수도 있으므로 기수 정렬은 정수에만 국한되지 않습니다. 기수 정렬의 발명은 1887년 Hermann Hollery가 Tabulation Machine에서 시작했습니다. 기수 정렬 방법은 LSD(최하위 디지털) 또는 MSD(최상위 디지털)를 사용할 수 있습니다. LSD 정렬 방법은 가장 오른쪽부터 시작됩니다. MSD는 키 값의 가장 왼쪽부터 시작합니다. LSD는 카운팅 정렬 또는 버킷 정렬을 사용하고 MSD는 버킷 정렬을 사용할 수 있습니다. 낮은 수준에서 높은 수준으로(LSD)는 비교적 간단하며, 높은 수준에서 낮은 수준으로(MSD) 재배열하면 매번 재귀를 통해 계층별로 재정렬할 수 없습니다. 자세한 내용은 다양한 버전의 소스 코드를 참조하세요.
인터넷에는 정렬 알고리즘을 구현하는 방법이 많이 있지만 다른 언어에서는 종종 오류가 포함되어 있고 비교가 부족합니다. 이 시리즈는 다양한 정렬 알고리즘을 재정렬하고 이를 다양한 언어로 구현합니다.
구현 과정
- 정렬할 숫자 순서(양의 정수)를 동일한 숫자 길이로 통일하고, 짧은 숫자는 0으로 채웁니다.
- 각 숫자는 가장 낮은 숫자에서 가장 높은 숫자로 또는 가장 높은 숫자에서 가장 낮은 숫자로 개별적으로 정렬됩니다.
- 낮은 것부터 높은 것, 높은 것부터 낮은 것 순으로 정렬하면 순서가 있는 순서가 됩니다.
- 회로도
성능 분석
시간 복잡도: O(k*N)
공간 복잡도: O(k + N)
안정성: 안정적
Code
Java
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; }
Python
""" 基数排序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
// 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,从低到高逐个数位对比排序,基于桶排序,利用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
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 } }
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); }
C++
// 基数排序,从个位到高位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
기수 정렬, 계산 정렬, 및 버킷 정렬
기수 정렬, 계산 정렬, 버킷 정렬 세 가지 개념은 매우 유사하지만 주요 차이점은 다음과 같습니다.
카운팅 정렬: 배열 값에 따라 여러 버킷을 설정하고 각 버킷은 값에 해당하며 이 값을 저장합니다. 다음 버킷에 있는 버킷을 정렬하여 사용하고 마지막으로 해당 버킷의 값을 순서대로 꺼냅니다.
버킷 정렬: 상황에 따라 여러 버킷으로 나누어집니다. 각 버킷은 특정 범위의 값을 저장하며, 각 버킷은 개별적으로 정렬되고 최종적으로 모든 데이터가 버킷 순서대로 꺼집니다.
Radix 정렬: 데이터의 자릿수에 따라 버킷을 할당합니다. 각 자릿수는 버킷에 해당합니다. 먼저 최대 자릿수에 따라 모든 데이터의 자릿수를 정렬한 다음 해당 값에 따라 정렬합니다. 숫자. 기수 정렬은 개수 정렬 또는 버킷 정렬을 기반으로 합니다.
위 내용은 다양한 프로그래밍 언어에서의 기수 정렬의 원리와 구현 방법의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

핫 AI 도구

Undresser.AI Undress
사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover
사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

AI Hentai Generator
AI Hentai를 무료로 생성하십시오.

인기 기사

뜨거운 도구

메모장++7.3.1
사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전
중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기
강력한 PHP 통합 개발 환경

드림위버 CS6
시각적 웹 개발 도구

SublimeText3 Mac 버전
신 수준의 코드 편집 소프트웨어(SublimeText3)

뜨거운 주제









모바일 XML에서 PDF의 속도는 다음 요인에 따라 다릅니다. XML 구조의 복잡성. 모바일 하드웨어 구성 변환 방법 (라이브러리, 알고리즘) 코드 품질 최적화 방법 (효율적인 라이브러리 선택, 알고리즘 최적화, 캐시 데이터 및 다중 스레딩 사용). 전반적으로 절대적인 답변은 없으며 특정 상황에 따라 최적화해야합니다.

단일 애플리케이션으로 휴대 전화에서 직접 XML에서 PDF 변환을 완료하는 것은 불가능합니다. 두 단계를 통해 달성 할 수있는 클라우드 서비스를 사용해야합니다. 1. 클라우드에서 XML을 PDF로 변환하십시오. 2. 휴대 전화에서 변환 된 PDF 파일에 액세스하거나 다운로드하십시오.

C 언어에는 내장 합계 기능이 없으므로 직접 작성해야합니다. 합계는 배열 및 축적 요소를 가로 질러 달성 할 수 있습니다. 루프 버전 : 루프 및 배열 길이를 사용하여 계산됩니다. 포인터 버전 : 포인터를 사용하여 배열 요소를 가리키며 효율적인 합계는 자체 증가 포인터를 통해 달성됩니다. 동적으로 배열 버전을 할당 : 배열을 동적으로 할당하고 메모리를 직접 관리하여 메모리 누출을 방지하기 위해 할당 된 메모리가 해제되도록합니다.

XML 구조가 유연하고 다양하기 때문에 모든 XML 파일을 PDF로 변환 할 수있는 앱은 없습니다. XML에서 PDF의 핵심은 데이터 구조를 페이지 레이아웃으로 변환하는 것입니다. XML을 구문 분석하고 PDF를 생성해야합니다. 일반적인 방법으로는 요소 트리와 같은 파이썬 라이브러리를 사용한 XML 및 ReportLab 라이브러리를 사용하여 PDF를 생성하는 XML을 구문 분석합니다. 복잡한 XML의 경우 XSLT 변환 구조를 사용해야 할 수도 있습니다. 성능을 최적화 할 때는 멀티 스레드 또는 멀티 프로세스 사용을 고려하고 적절한 라이브러리를 선택하십시오.

XML 서식 도구는 규칙에 따라 코드를 입력하여 가독성과 이해를 향상시킬 수 있습니다. 도구를 선택할 때는 사용자 정의 기능, 특수 상황 처리, 성능 및 사용 편의성에주의하십시오. 일반적으로 사용되는 도구 유형에는 온라인 도구, IDE 플러그인 및 명령 줄 도구가 포함됩니다.

휴대 전화에서 XML을 PDF로 직접 변환하는 것은 쉽지 않지만 클라우드 서비스를 통해 달성 할 수 있습니다. 가벼운 모바일 앱을 사용하여 XML 파일을 업로드하고 생성 된 PDF를 수신하고 클라우드 API로 변환하는 것이 좋습니다. Cloud API는 Serverless Computing Services를 사용하고 올바른 플랫폼을 선택하는 것이 중요합니다. XML 구문 분석 및 PDF 생성을 처리 할 때 복잡성, 오류 처리, 보안 및 최적화 전략을 고려해야합니다. 전체 프로세스에는 프론트 엔드 앱과 백엔드 API가 함께 작동해야하며 다양한 기술에 대한 이해가 필요합니다.

대부분의 텍스트 편집기를 사용하여 XML 파일을여십시오. 보다 직관적 인 트리 디스플레이가 필요한 경우 Oxygen XML 편집기 또는 XMLSPy와 같은 XML 편집기를 사용할 수 있습니다. 프로그램에서 XML 데이터를 처리하는 경우 프로그래밍 언어 (예 : Python) 및 XML 라이브러 (예 : XML.etree.elementtree)를 사용하여 구문 분석해야합니다.

XSLT 변환기 또는 이미지 라이브러리를 사용하여 XML을 이미지로 변환 할 수 있습니다. XSLT 변환기 : XSLT 프로세서 및 스타일 시트를 사용하여 XML을 이미지로 변환합니다. 이미지 라이브러리 : Pil 또는 Imagemagick와 같은 라이브러리를 사용하여 XML 데이터에서 이미지를 그리기 및 텍스트 그리기와 같은 이미지를 만듭니다.
