zoukankan      html  css  js  c++  java
  • 数据结构基础(15) --基数排序

        基数排序是一种借助“多关键字排序”的思想来实现“单关键字排序”的内部排序算法。

    实现多关键字排序通常有两种作法:

       最低位优先法(LSD)

        先对K[0]{基数的最低位}进行排序,并按 K(0) 的不同值将记录序列分成若干子序列之后,分别对 K[1] 进行排序,..., K[d-1]依次类推,直至最后对最次位关键字排序完成为止。

      最高位优先法(MSD)

        先对 K[d-1]{基数的最高位}进行排序,然后对 K[d-2]进行排序,依次类推,直至对最主位关键字 K[0] 排序完成为止。

     

    百度百科对基数排序做了如下介绍:

        基数排序(radix sort)是属于“分配式排序”(distribution sort),基数排序法又称“桶子法”(bucket sort),顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,在某些时候,基数排序法的效率高于其它的稳定性排序法。

     

    链式基数排序基本步骤如下

        1.将待排序记录以数组存储[或者以指针相链,构成一个链表]

        2.”分配”时,按当前”关键字位”所取值,将记录分配到不同的”链表/链队列”(即不同的桶或堆中)中,每条链表中记录的”关键字位”相同;

        3.”收集”时,按当前关键字位取值从小到大(即将这n条链表(n的大小为基数的大小)按照编号, 依次将其中所有的元素取出)将各链表中的元素取出放入到原先的数组或链表中;

        4.对每个关键字位均重复 2) 和 3) 两步n次。

     

    如采用LSD对{179, 208, 306, 93, 859, 984, 55, 9, 271, 33}(构成一个链表或者是数组)进行基数排序:

    [第一步:按个位排]

     

    [第二步:按十位排]


    [第三步:按百位排]

     

    代码实现(LSD为例):

    //寻找数组中最大数字的位数
    template <typename Type>
    unsigned int maxBits(Type *begin, Type *end)
    {
        unsigned int bits = 1;
        //standard作为基准, 如果array中的元素
        //大于standard, 则bits+1
        int standard = 10;
    
        for (Type *current = begin; current != end; ++current)
        {
            while (*current >= standard)
            {
                standard *= 10;
                ++ bits;
            }
        }
    
        return bits;
    }
    /**说明:
      begin:数组起始
      end:数组结尾
      radix:基数
    
    */
    #define DEBUG
    template <typename Type>
    void radixSort(Type *begin, Type *end, int radix)
    {
        //找到数组中最大数字的位数
        int bits = maxBits(begin, end);
    
        //基数为radix, 则需要radix个链表
        std::list<Type> lists[radix];
    
        // 需要循环bits次
        for (int d = 0, factor = 1; d < bits; ++d, factor*=10)
        {
            //分配...
            for (Type *current = begin; current != end; ++current)
            {
                //取出相应位置上的数 (比如个位是1)
                int number = ((*current)/factor)%10;
                //则需要将之放到(分配到)标号为1的链表中
                lists[number].push_back(*current);
            }
    
            //收集...
            Type *current = begin;
            //对radix个链表中的元素进行收集
            for (int i = 0; i < radix; ++i)
            {
                while (!lists[i].empty())
                {
                    *current = lists[i].front();
    
                    ++ current;
                    lists[i].pop_front();
                }
            }
    #ifdef DEBUG
            //打印排序的中间结果
            for (current = begin; current != end; ++ current)
            {
                cout << *current << ' ';
            }
            cout << endl;
    #endif // DEBUG
        }
    }
    
    template <typename Type>
    void radixSort(Type *array, int arraySize, int radix)
    {
        return radixSort(array, array+arraySize, radix);
    }

    时间复杂度分析:

        设待排序列为n个记录,d个关键码,关键码的取值范围为radix,则进行链式基数排序的时间复杂度为O(d(n+radix)),其中,一趟分配时间复杂度为O(n),一趟收集时间复杂度为O(radix),共进行d趟分配和收集.


    -测试代码:

    int main()
    {
        int array[10];
        for (int i = 0; i < 10; ++i)
        {
            array[i] = rand()%1000;
        }
        for (int i = 0; i < 10; ++i)
        {
            cout << array[i] << ' ';
        }
        cout << endl;
    
        radixSort(array, 10, 10);
    
        for (int i = 0; i < 10; ++i)
        {
            cout << array[i] << ' ';
        }
        cout << endl;
    
        return 0;
    }

  • 相关阅读:
    [Leetcode] 221. Maximal Square
    [翻译] TensorFlow Programmer's Guide之Frequently Asked Questions(问得频率最多的几个问题)
    [Kaggle] dogs-vs-cats之模型训练
    [Kaggle] dogs-vs-cats之建立模型
    [Kaggle] dogs-vs-cats之制作数据集[1]
    Linux虚拟机Centos 设置固定的静态IP
    linux IP动态变动之后 , 需要做的杂项操作
    GitBlit (1)-- 在linux 安装 GitBlit 并运行
    Linux 安装SVN
    微信开发(3) -- 支付后接收回调信息测试
  • 原文地址:https://www.cnblogs.com/itrena/p/5926991.html
Copyright © 2011-2022 走看看