zoukankan      html  css  js  c++  java
  • 桶排序

    桶排序是将待排序集合中处于同一个值域的元素存入同一个桶中,也就是根据元素值特性将集合拆分为多个区域,则拆分后形成的多个桶,从值域上看是处于有序状态的。对每个桶中元素进行排序,则所有桶中元素构成的集合是已排序的。

    快速排序是将集合拆分为两个值域,这里称为两个桶,再分别对两个桶进行排序,最终完成排序。桶排序则是将集合拆分为多个桶,对每个桶进行排序,则完成排序过程。两者不同之处在于,快排是在集合本身上进行排序,属于原地排序方式,且对每个桶的排序方式也是快排。桶排序则是提供了额外的操作空间,在额外空间上对桶进行排序,避免了构成桶过程的元素比较和交换操作,同时可以自主选择恰当的排序算法对桶进行排序。

    当然桶排序更是对计数排序的改进,计数排序申请的额外空间跨度从最小元素值到最大元素值,若待排序集合中元素不是依次递增的,则必然有空间浪费情况。桶排序则是弱化了这种浪费情况,将最小值到最大值之间的每一个位置申请空间,更新为最小值到最大值之间每一个固定区域申请空间,尽量减少了元素值大小不连续情况下的空间浪费情况。

    桶排序过程中存在两个关键环节:
    • 元素值域的划分,也就是元素到桶的映射规则。映射规则需要根据待排序集合的元素分布特性进行选择,若规则设计的过于模糊、宽泛,则可能导致待排序集合中所有元素全部映射到一个桶上,则桶排序向比较性质排序算法演变。若映射规则设计的过于具体、严苛,则可能导致待排序集合中每一个元素值映射到一个桶上,则桶排序向计数排序方式演化。
    • 排序算法的选择,从待排序集合中元素映射到各个桶上的过程,并不存在元素的比较和交换操作,在对各个桶中元素进行排序时,可以自主选择合适的排序算法,桶排序算法的复杂度和稳定性,都根据选择的排序算法不同而不同。

    算法过程

    1. 根据待排序集合中最大元素和最小元素的差值范围和映射规则,确定申请的桶个数;
    2. 遍历待排序集合,将每一个元素移动到对应的桶中;
    3. 对每一个桶中元素进行排序,并移动到已排序集合中。

    步骤 3 中提到的已排序集合,和步骤 1、2 中的待排序集合是同一个集合。与计数排序不同,桶排序的步骤 2 完成之后,所有元素都处于桶中,并且对桶中元素排序后,移动元素过程中不再依赖原始集合,所以可以将桶中元素移动回原始集合即可。

    利用桶排序解决的问题:

    347. Top K Frequent Elements (Medium)

    出现频率最高的k个元素

    https://leetcode.com/problems/top-k-frequent-elements/description/

    class Solution {
    public:
        // 桶排序
        vector<int> topKFrequent(vector<int>& nums, int k) {
            unordered_map<int, int> fre;
            for (auto num: nums)
            {
                fre[num]++;
            }
            vector<int> res;
            // 优先队列
            priority_queue<pair<int, int>> pq;
            for (auto f: fre)
            {
                pq.push(make_pair(f.second,f.first));
                if (pq.size() > fre.size() - k)
                {
                    res.push_back(pq.top().second);
                    pq.pop();
                }
            }
            return res;
        }
    };

    451. Sort Characters By Frequency (Medium)

    按照字符出现频率排序

    https://leetcode.com/problems/sort-characters-by-frequency/

    class Solution {
    public:
        string frequencySort(string s) {
            string res;
    
            unordered_map<int, int> fre;
            for(auto c: s)
            {
                fre[c]++;
            }
            typedef pair<int, int> pair_type;
            priority_queue<pair_type>pq;
            for(auto f:fre)
            {
                pq.push(make_pair(f.second, f.first));
            }
            while(!pq.empty())
            {
                auto p = pq.top();
                pq.pop();
                for(int i = 0;i < p.first;++i)
                {
                    res.push_back(p.second);
                }
            }
            return res;
        }
    };

     上边两个问题都用来priority_queue数据结构,也可以不用。

    定义一个vector<char> [nums.size() - 1]; 其中下标表示出现的频率,vector中存字符。


    参考链接:https://www.jianshu.com/p/204ed43aec0c

  • 相关阅读:
    Android上传文件到服务器(转)
    Android -- 利用Broadcast开启Service(转)
    【转】实践最有效的提高Android Studio运行、编译速度方案
    Android Studio3.x新的依赖方式(implementation、api、compileOnly)
    Drawable子类之——StateListDrawable (选择器)
    解决android studio引用远程仓库下载慢(JCenter下载慢)
    跳槽季,面试官:能接受加班吗?
    PHP 底层的运行机制与原理
    PHP程序员如何突破成长瓶颈
    VirtualBox启动虚拟机报错0x80004005
  • 原文地址:https://www.cnblogs.com/qiang-wei/p/12295227.html
Copyright © 2011-2022 走看看