美文网首页
golang 写个基数排序

golang 写个基数排序

作者: 追风骚年 | 来源:发表于2021-01-26 15:22 被阅读0次

    在编写基数排序的时候,我还找到一个规律,取一个数的个位十位百位,是经常需要用到的

    // 数字,右数第几位,从1开始
    func digit(num int, loc int) int {
        return num % int(math.Pow10(loc)) / int(math.Pow10(loc-1))
    }
    

    算法描述

    • 取得数组中的最大数,并取得位数;
    • arr为原始数组,从最低位开始取每个位组成radix数组;
    • 对radix进行计数排序(利用计数排序适用于小范围数的特点);

    算法实习

    版本一

    为了简单起见,我这里用了一个 数组,数组中是一个队列,这样可以方便取到队列头部数据。

    func radixsort(arr []int) []int {
        maxValueLen := 0 // 需要循环多少次,以最大数字为准
        for i := 0; i < len(arr); i++ {
            n := len(strconv.Itoa(arr[i])) // 方便起见,数字转字符,再取长度
            if n > maxValueLen {
                maxValueLen = n
            }
        }
    
        for loc := 1; loc <= maxValueLen; loc++ {
            arr = sort(arr, loc)
        }
        return arr
    }
    
    // 数组中每一位都需要排序
    func sort(arr []int, loc int) []int {
        bucket := make([]*list.List, 10) // 0~9 总共10个队列
        for i := 0; i <= 9; i++ {
            bucket[i] = list.New()
        }
    
        for i := 0; i < len(arr); i++ {
            ji := digit(arr[i], loc)    // 获取对应位的数字
            bucket[ji].PushBack(arr[i]) //按数字 将数据 push 进队列
        }
    
        tempArr := []int{}
        for i := 0; i <= 9; i++ {
            for bucket[i].Len() > 0 { // 队列中不为空
                fv := bucket[i].Front() // 将数据弹出
                tempArr = append(tempArr, fv.Value.(int))
                bucket[i].Remove(fv)
            }
        }
        return tempArr // 将本轮排好序的数据返回
    }
    
    // 数字,右数第几位,从1开始
    func digit(num int, loc int) int {
        return num % int(math.Pow10(loc)) / int(math.Pow10(loc-1))
    }
    
    func TestRadixsort(t *testing.T) {
        arr := []int{1, 2, 12, 4343242, 123, 4, 55, 666, 77, 102, 3249, 21210, 31312}
        t.Log(arr)
        t.Log(radixsort(arr))
    }
    
    func BenchmarkRadixsort(b *testing.B) {
        arr := rand.Perm(math.MaxInt16 * 10)
        for i := 0; i < b.N; i++ {
            radixsort(arr)
        }
    }
    

    版本二

    
    func radixsort(arr []int) []int {
        maxValueLen := 0 // 需要循环多少次,以最大数字为准
        for i := 0; i < len(arr); i++ {
            n := len(strconv.Itoa(arr[i])) // 方便起见,数字转字符,再取长度
            if n > maxValueLen {
                maxValueLen = n
            }
        }
        for loc := 1; loc <= maxValueLen; loc++ {
            sort(arr, loc)
        }
        return arr
    }
    
    func sort(arr []int, loc int) {
        bucket := make([][]int, 10) // 0~9 总共10个队列
    
        for i := 0; i < len(arr); i++ {
            ji := digit(arr[i], loc) // 获取对应位的数字
            if bucket[ji] == nil {
                bucket[ji] = make([]int, 0) // 如果 bucket 需要再去初始化
            }
    
            bucket[ji] = append(bucket[ji], arr[i]) // 将数字 push 进去
        }
    
        idx := 0
        for i := 0; i <= 9; i++ {
            for j := 0; j < len(bucket[i]); j++ {
                // 遍历二维数组
                arr[idx] = bucket[i][j] //将数字取出来 给原数组重新赋值
                idx++
            }
        }
    }
    
    // 数字,右数第几位,从1开始
    func digit(num int, loc int) int {
        return num % int(math.Pow10(loc)) / int(math.Pow10(loc-1))
    }
    
    func TestRadixsort(t *testing.T) {
        arr := []int{1, 2, 12, 4343242, 123, 4, 55, 666, 77, 102, 3249, 21210, 31312}
        t.Log(arr)
        // t.Log(radixsort(arr))
        t.Log(radixsort(arr))
    }
    
    
    func BenchmarkRadixsort(b *testing.B) {
        arr := rand.Perm(math.MaxInt16 * 10)
        for i := 0; i < b.N; i++ {
            radixsort(arr)
        }
    }
    
    
    

    版本二直接使用了一个二维数组去实现了,后面直接去掉 tempArr,给原数组赋值即可,对各种写法都Benchmark了一下,确实性能提供了很多倍。

    小结

    基数排序的逻辑可以查看B站,但是他的代码,让我很费解,这边都是自己实现的逻辑,感觉比较好理解。

    至此,8大排序均已写完,大学里用 c 和 java 都实现过,这是用 golang 重新实现了。知识这东西时间长了那真是叫似曾相识,理不清楚。

    相关文章

      网友评论

          本文标题:golang 写个基数排序

          本文链接:https://www.haomeiwen.com/subject/cwdgzktx.html