IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> 算法与数据结构-桶排序、计数排序和基数排序 -> 正文阅读

[数据结构与算法]算法与数据结构-桶排序、计数排序和基数排序

桶排序、计数排序和基数排序这三种算法的时间复杂度都为 O ( n ) ,因此,它们也被叫作线性排序(Linear Sort)。之所以能做到线性,是因为这三个算法是非基于比较的排序算法,都不涉及元素之间的比较操作。

1. 桶排序(Bucket Sort)


1.1. 原理


核心思想是将要排序的数据分到几个有序的桶里,每个桶的数据再单独进行排序。桶内排完序后,再把每个桶里的数据按照顺序依次取出,组成的序列就是有序的了。


1.2. 时间复杂度分析


如果要排序的数据有 n 个,我们把它们均匀地划分到 m 个桶内,每个桶内就有 k = n/m 个元素。对每个桶内的数据进行快速排序,时间复杂度为 O ( k l o g k ) 。m 个桶排序时间复杂度就为 O ( m ? k l o g k ) = O ( n ? l o g n /m )。当桶的个数接近数据个数时,O ( l o g n /m ) 就是一个非常小的数,这个时候通排序的时间复杂度接近于 O ( n ) 。


1.3. 桶排序的适用条件


桶排序看起来很优秀,但事实上,桶排序对排序数据的要求是非常苛刻的。

首先,要排序的数据需要很容易就能划分为 m 个桶,并且桶与桶之间有着天然的大小顺序。
其次,数据在各个桶之间的分布是比较均匀的。
桶排序比较适合用在外部排序中。所谓的外部排序就是数据存储在外部磁盘中,数据比较大而内存有限,无法将数据全部加载到内存中去。


1.4. 一个桶排序的实例


假如我们有 10 GB 的订单数据需要按照金额进行排序,但内存只有几百 MB ,这时候该怎么办呢?

我们先扫描一遍文件,确定订单金额的数据范围。
如果扫描后发现订单金额处于 1 万元到 10 万元之间,我们将所有订单按照金额划分到 100 个桶内,第一个桶数据范围为[1, 1000],第二个桶数据范围为[1001, 2000]…,每个桶对应一个文件,同时将文件按照金额范围的大小顺序编号命名(如00、01、02…99)。
如果订单金额分布均匀,则每个文件包含大约 100 MB 的数据,我们可以将每个小文件读入到内存中,进行快速排序。然后,再按顺序从各个小文件读取数据,写入到另外一个文件,即是排序好的数据了。如果订单分布不均,某一范围内数据特别多无法一次读入内存,则可以继续对此区间再进行划分,直到所有的文件都可以读入内存为止。

2. 计数排序(Counting Sort)







2.1. 计数排序算法实现

public class DemoApplication {
    public static void main(String[] args) {
        int arr = new int[]{2, 5, 3, 0, 2, 3, 0, 3};

       
        //计数排序
        countingSort(arr);

       
        for(int k = 0; k < arr.length; k++){
            System.out.print(arr[k] + ",");
        }
    }
    //计数排序
    public static void countingSort(int[] arr) {
        int[] count = new int[10];
        for(int i = 0; i < arr.length; i++){
            count[arr[i]]++;
        }
        for(int i = 1; i < count.length; i++){
            count[i] += count[i - 1];
        }
        int[] t = new int[arr.length];
        for(int i = arr.length - 1; i >= 0; i--){
            t[count[arr[i]] - 1] = arr[i];
            count[arr[i]]--;
        }
        for(int i = 0; i < arr.length; i++){
            arr[i] = t[i];
        }
    }
}

2.2. 计数排序的适用范围


计数排序只适用于数据范围不大的场景中,如果数据范围 K 比排序的数据 n 大很多,就不适合用计数排序了。
计数排序能给非负整数排序,如果数据是其他类型的,需要将其在不改变相对大小的情况下,转化为非负整数。比如数据有一位小数,我们需要将数据都乘以 10;数据范围为 [-1000, 1000],我们需要对每个数据加 1000。

3. 基数排序(Radix Sort)


假设要对 10 万个手机号码进行排序,显然桶排序和计数排序都不太适合,那怎样才能做到时间复杂度为 O(n) 呢?

基数排序是一种非比较型整数排序算法,其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。由于整数也可以表达字符串(比如名字或日期)和特定格式的浮点数,所以基数排序也不是只能使用于整数。

public class DemoApplication {
    public static void main(String[] args) {
        int arr[]  = new int[]{50, 123, 543, 187, 49, 30, 0, 2, 11, 100};
        //基数排序
        arr = radixSort(arr);

        for(int k = 0; k < arr.length; k++){
            System.out.print(arr[k] + ",");
        }
    }
    /**
     * 获取数组最大位数
     * @param arr
     * @return
     */
    public static int maxBit(int[] arr){
        int max = arr[0];
        for(int i = 1; i < arr.length; i++){
            if(arr[i] > max){
                max = arr[i];
            }
        }
        int bit = 0;
        if(max == 0){
            bit = 1;
        }else{
            while(max > 0){
                bit++;
                max /= 10;
            }
        }
        return bit;
    }

    /**
     * 返回指定位数上的值
     * @param num
     * @param bit
     * @return
     */
    public static int digit(int num, int bit){
        int pow = 1;
        while(--bit > 0){
            pow *= 10;
        }
        return num / pow % 10;
    }
    /**
     * 基数排序
     */
    public static int[] radixSort(int[] arr) {
        int maxBit = maxBit(arr);
        int count[] = new int[10];
        int t[] = new int[arr.length];
        for(int i = 1; i <= maxBit; i++){
            for(int j = 0; j < count.length; j++){
                count[j] = 0;
            }
            for(int j = 0; j < arr.length; j++){
                count[digit(arr[j], i)]++;
            }
            for(int j = 1; j < count.length; j++){
                count[j] += count[j - 1];
            }
            for(int j = arr.length - 1; j >= 0; j--){
                t[--count[digit(arr[j], i)]] = arr[j];
            }
            for(int j = 0; j < arr.length; j++){
                arr[j] = t[j];
            }
        }
        return arr;
    }
}

参考地址:排序算法(8) -- 桶排序、计数排序和基数排序_Dby_freedom的博客-CSDN博客

  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-10-24 15:08:14  更:2021-10-24 15:09:16 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 8:40:04-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码