다양한 프로그래밍 언어에서의 기수 정렬의 원리와 구현 방법

PHPz
풀어 주다: 2023-05-08 12:31:07
앞으로
1335명이 탐색했습니다.

    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(&#39;buckets:&#39;, 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(&#39;origin arr:&#39;, arr, &#39;exponent:&#39;, exponent)
        if (len(arr) <= 1 or exponent <= 0):
            return arr
    
        min_value = min(arr)
    
        radix = 10
        amount = 10
    
        print(&#39;prepared arr:&#39;, arr, &#39;exponent:&#39;, 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(&#39;append to buckets:&#39;, 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 (&#39;sortedIdx::&#39;, sortedIdx)
                arr[sortedIdx] = num
                print(&#39;bucket:&#39;, bucket, &#39;sortedBucket:&#39;, sortedBucket,
                      &#39;sortedIdx:&#39;, sortedIdx, &#39;set arr:&#39;, arr)
                sortedIdx += 1
    
        print(&#39;exponent:&#39;, exponent, &#39;sorted arr:&#39;, 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(&#39;origin arr:&#39;, arr, &#39;exponent:&#39;, 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(&#39;countingSort countList:&#39;, 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

    관련 라벨:
    원천:yisu.com
    본 웹사이트의 성명
    본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
    인기 튜토리얼
    더>
    최신 다운로드
    더>
    웹 효과
    웹사이트 소스 코드
    웹사이트 자료
    프론트엔드 템플릿