看动画学算法之:排序-count排序

简介: 看动画学算法之:排序-count排序

目录



简介


今天我们介绍一种不需要作比较就能排序的算法:count排序。


count排序是一种空间换时间的算法,我们借助一个外部的count数组来统计各个元素出现的次数,从而最终完成排序。


count排序的例子


count排序有一定的限制,因为外部的count数组长度是和原数组的元素范围是一致的,所以count排序一般只适合数组中元素范围比较小的情况。


我们举一个0-9的元素的排序的例子:3,4,2,5,6,2,4,9,1,3,5。


先看一个动画,看看是怎么排序的:


qweqwe.gif


count数组里面存放的是从0到9这些元素出现的次数。


我们遍历原始数组,遇到相应的数字就给相应的count+1。


等所有的元素都count之后,再根据count数组中的值还原排序过后的数组。


count排序的java实现


count排序很简单,我们主要掌握下面两个大的步骤:


  1. 遍历原始数组,构建count数组。


  1. 根据count数组中的count值,重新构建排序数组。


public class CountingSort {
    public void doCountingSort(int[] array){
        int n = array.length;
        // 存储排序过后的数组
        int output[] = new int[n];
        // count数组,用来存储统计各个元素出现的次数
        int count[] = new int[10];
        for (int i=0; i<10; ++i) {
            count[i] = 0;
        }
        log.info("初始化count值:{}",count);
        // 将原始数组中数据出现次数存入count数组
        for (int i=0; i<n; ++i) {
            ++count[array[i]];
        }
        log.info("count之后count值:{}",count);
        //遍历count,将相应的数据插入output
        int j=0;
        for(int i=0; i<10; i++){
            while(count[i]-- > 0){
                output[j++]=i;
            }
        }
        log.info("构建output之后的output值:{}",output);
        //将排序后的数组写回原数组
        for (int i = 0; i<n; ++i)
            array[i] = output[i];
    }
    public static void main(String[] args) {
        int[] array= {3,4,2,5,6,2,4,9,1,3,5};
        CountingSort countingSort=new CountingSort();
        log.info("countingSort之前的数组为:{}",array);
        countingSort.doCountingSort(array);
    }
}


上面的注释应该很清楚了。


运行的结果如下:


image.png

count排序的第二种方法


在我们获得count数组中每个元素的个数之后,其实我们还有另外一个生成结果数组的办法:


// 这里是一个小技巧,我们根据count中元素出现的次数计算对应元素第一次应该出现在output中的下标。
        //这里的下标是从右往左数的
        for (int i=1; i<10; i++) {
            count[i] += count[i - 1];
        }
        log.info("整理count对应的output下标:{}",count);
        // 根据count中的下标,构建排序后的数组
        //插入一个之后,相应的count下标要减一
        for (int i = n-1; i>=0; i--)
        {
            output[count[array[i]]-1] = array[i];
            --count[array[i]];
        }
        log.info("构建output之后的output值:{}",output);


主要分为两步:


第一步我们根据count中元素出现的次数计算对应元素第一次应该出现在output中的下标。这里的下标是从右往左数的。


第二步根据count中的下标,构建排序后的数组,插入一个之后,相应的count下标要减一。


image.png


可能不是很好理解,大家可以结合输出结果反复琢磨一下。


count排序的时间复杂度


从上面的代码我们可以看到,count排序实际上只做了少量次数的遍历。所以它的时间复杂度是O(n)。


本文的代码地址:


learn-algorithm

相关文章
|
6天前
|
算法
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
【算法】二分查找——在排序数组中查找元素的第一个和最后一个位置
|
7天前
|
搜索推荐 算法 Java
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
该博客文章通过UML类图和Java源码示例,展示了如何使用适配器模式将QuickSort类和BinarySearch类的排序和查找功能适配到DataOperation接口中,实现算法的解耦和复用。
现有一个接口DataOperation定义了排序方法sort(int[])和查找方法search(int[],int),已知类QuickSort的quickSort(int[])方法实现了快速排序算法
|
12天前
|
算法 关系型数据库 MySQL
揭秘MySQL中的版本号排序:这个超级算法将颠覆你的排序世界!
【8月更文挑战第8天】在软件开发与数据管理中,正确排序版本号对软件更新及数据分析至关重要。因MySQL默认按字符串排序版本号,可能出现&#39;1.20.0&#39;在&#39;1.10.0&#39;之前的不合理情况。解决办法是将版本号各部分转换为整数后排序。例如,使用`SUBSTRING_INDEX`和`CAST`函数从`software`表的`version`字段提取并转换版本号,再按这些整数排序。这种方法可确保版本号按逻辑正确排序,适用于&#39;major.minor.patch&#39;格式的版本号。对于更复杂格式,需调整处理逻辑。掌握此技巧可有效应对版本号排序需求。
39 3
|
5天前
|
算法 搜索推荐
算法设计 (分治法应用实验报告)基于分治法的合并排序、快速排序、最近对问题
这篇文章是关于分治法应用的实验报告,详细介绍了如何利用分治法实现合并排序和快速排序算法,并探讨了使用分治法解决二维平面上的最近对问题的方法,包括伪代码、源代码实现及时间效率分析,并附有运行结果和小结。
|
11天前
|
存储 算法 Java
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
LeetCode初级算法题:反转链表+统计N以内的素数+删除排序数组中的重复项Java详解
10 0
|
1月前
|
存储 算法 搜索推荐
算法进阶之路:Python 归并排序深度剖析,让数据排序变得艺术起来!
【7月更文挑战第12天】归并排序是高效稳定的排序算法,采用分治策略。Python 实现包括递归地分割数组及合并已排序部分。示例代码展示了如何将 `[12, 11, 13, 5, 6]` 分割并归并成有序数组 `[5, 6, 11, 12, 13]`。虽然 $O(n log n)$ 时间复杂度优秀,但需额外空间,适合大规模数据排序。对于小规模数据,可考虑其他算法。**
57 4
|
2月前
|
算法 Java 调度
Java数据结构与算法:拓扑排序
Java数据结构与算法:拓扑排序
|
2月前
|
算法 搜索推荐 C++
C++之STL常用算法(遍历、查找、排序、拷贝、替换、算数生成、集合)
C++之STL常用算法(遍历、查找、排序、拷贝、替换、算数生成、集合)
24 0
|
2月前
|
人工智能 算法 搜索推荐
蓝桥杯宝藏排序题目算法(冒泡、选择、插入)
以下是内容的摘要: 本文介绍了三种排序算法:冒泡排序、选择排序和插入排序。冒泡排序通过不断交换相邻的逆序元素逐步排序,最坏情况下需要 O(n^2) 次比较。选择排序在每轮中找到剩余部分的最小元素并放到已排序序列的末尾,同样具有 O(n^2) 时间复杂度。插入排序则是将每个元素插入到已排序序列的正确位置,时间复杂度也是 O(n^2),但空间复杂度为 O(1)。
|
2月前
|
人工智能 算法 BI
【洛谷 P1803】凌乱的yyy _ 线段覆盖 题解(贪心算法+结构体排序)
**线段覆盖问题**: YYY 想在 NOIP 前参加最多比赛。给定 $n$ 场比赛的开始和结束时间,每场比赛必须连续且不能冲突。输入包含每场比赛的时间段,输出最多可参加的比赛数。$20\%$ 数据 $n\leq10$,$50\%$ 数据 $n\leq10^3$,$100\%$ 数据 $n\leq10^6$。解决方案:按结束时间排序比赛,若当前比赛开始时间晚于上一个结束时间,则计数加一。样例输入:3 场比赛,输出:2。AC C++ 代码实现了此算法。
25 0

热门文章

最新文章