十大排序算法总结(三)

简介: 排序算法中涉及到了两个概念:原地排序:根据算法对内存的消耗情况,可以将算法分为原地排序和非原地排序,原地排序特指空间复杂度为 O(1) 的排序。排序算法的稳定性:例如排序一个数组 [1, 5, 3, 7, 4, 9, 5],数组中有两个 5,排序之后是 [1, 3, 4, 5, 5, 7, 9],如果排序之后的两个 5 的前后顺序没有发生变化,那么称这个排序是稳定的,反之则是不稳定的。

8. 桶排序


桶排序并不是基于数据比较的,因此比较的高效,时间复杂度接近 O(n),但是相应地,应用的条件十分苛刻。其思路非常的简单:将要排序的数据分到各个有序的桶内,数据在桶内进行排序,然后按序取出,整个数据就是有序的了。

最好情况下,数据被均匀的分到各个桶中,最坏情况是数据全都被分到一个桶中。

下面是一个桶排序的示例:

public class BucketSort {
    /**
     * 测试场景:数组中有10000个数据,范围在(0-100000)
     * 使用100个桶,每个桶存放的数据范围为:0-999, 1000-1999, 2000-2999,依次类推
     */
    public static void bucketSort(int[] data){
        //新建100个桶
        int bucketSize = 100;
        ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucketSize);
        for (int i = 0; i < bucketSize; i++) {
            buckets.add(new ArrayList<>());
        }
        //遍历数据,将数据放到桶中
        for (int i : data) {
            buckets.get(i / 1000).add(i);
        }
        //在桶内部进行排序
        int k = 0;
        for (int i = 0; i < bucketSize; i++) {
            ArrayList<Integer> list = buckets.get(i);
            Integer[] num = list.toArray(new Integer[1]);
            Arrays.sort(num);
            //拷贝到data中
            for (int n : num) {
                data[k++] = n;
            }
        }
    }
    //测试
    public static void main(String[] args) {
        Random random = new Random();
        int[] data = new int[10000];
        for (int i = 0; i < data.length; i++) {
            data[i] = random.nextInt(100000);
        }
        BucketSort.bucketSort(data);
        System.out.println(Arrays.toString(data));
    }
}


9. 计数排序


计数排序其实是一种特殊的桶排序,适用于数据的区间不是很大的情况。

例如给 10 万人按照年龄进行排序,我们知道年龄的区间并不是很大,最小的 0 岁,最大的可以假设为 120 岁,那么我们可以新建 121 个桶,扫描一遍数据,将年龄相同的放到一个桶中,然后按序从桶中将数据取出,这样数据就有序了。

计数排序的基本思路如下:

代码实现:

public class CountingSort {
    private static void countingSort(int[] data){
        int length = data.length;
        //找到数组的最大值
        int max = data[0];
        for (int i : data){
            if (max < i){
                max = i;
            }
        }
        //新建一个计数数组,大小为max+1
        //count数组的下标对应data的值,存储的值为对应data值的个数
        int[] count = new int[max + 1];
        for (int i : data){
            count[i] ++;
        }
        //根据count数组取出数据
        int k = 0;
        for (int i = 0; i < count.length; i++) {
            while (count[i] != 0){
                data[k ++] = i;
                count[i] --;
            }
        }
    }
}


10. 基数排序


基数排序适用于位数较多的数字或者字符串,思路是将排序的数据按位拆分,每一位单独按照稳定的排序算法进行比较,如下图:

图中的示例,以每个数字为下标,建了 10 个 “桶”,每个桶是一个队列(也可以是数组),然后将要排序的数据按位加入到队列中,然后出队,比较完每一位,则排序完成。

代码实现:

public class RadixSort {
    private static void radixSort(int[] data) {
        int maxDigit = maxDigit(data);
        //新建并初始化10个桶
        Queue<Integer>[] queues = new LinkedList[10];
        for (int i = 0; i < queues.length; i++) {
            queues[i] = new LinkedList<>();
        }
        for (int i = 0, mod = 1; i < maxDigit; i ++, mod *= 10) {
            for (int n : data){
                int m = (n / mod) % 10;
                queues[m].add(n);
            }
            int count = 0;
            for (Queue<Integer> queue : queues) {
                while (queue.size() > 0) {
                    data[count++] = queue.poll();
                }
            }
        }
    }
    /**
     * 获取数组最大位数
     */
    private static int maxDigit(int[] data){
        int maxDigit = data[0];
        for (int i : data){
            if (maxDigit < i){
                maxDigit = i;
            }
        }
        return String.valueOf(maxDigit).length();
    }
}
相关文章
|
6月前
|
存储 搜索推荐 算法
十大基础排序算法
十大基础排序算法
|
存储 移动开发 算法
十大排序算法
十大排序算法
132 0
|
存储 搜索推荐 算法
图解十大排序算法
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
99 2
|
存储 算法 搜索推荐
<<算法很美>>——(三)十大排序算法(上)(二)
<<算法很美>>——(三)十大排序算法(上)
<<算法很美>>——(三)十大排序算法(上)(二)
|
算法 搜索推荐 测试技术
<<算法很美>>——(三)十大排序算法(上)(一)
<<算法很美>>——(三)十大排序算法(上)
<<算法很美>>——(三)十大排序算法(上)(一)
|
算法 搜索推荐 C++
<<算法很美>>——(三)十大排序算法(下)
<<算法很美>>——(三)十大排序算法(下)
<<算法很美>>——(三)十大排序算法(下)
|
搜索推荐 算法
十大排序算法总结(一)
排序算法中涉及到了两个概念: 原地排序:根据算法对内存的消耗情况,可以将算法分为原地排序和非原地排序,原地排序特指空间复杂度为 O(1) 的排序。 排序算法的稳定性:例如排序一个数组 [1, 5, 3, 7, 4, 9, 5],数组中有两个 5,排序之后是 [1, 3, 4, 5, 5, 7, 9],如果排序之后的两个 5 的前后顺序没有发生变化,那么称这个排序是稳定的,反之则是不稳定的。
128 0
|
算法 搜索推荐
十大排序算法总结(二)
排序算法中涉及到了两个概念: 原地排序:根据算法对内存的消耗情况,可以将算法分为原地排序和非原地排序,原地排序特指空间复杂度为 O(1) 的排序。 排序算法的稳定性:例如排序一个数组 [1, 5, 3, 7, 4, 9, 5],数组中有两个 5,排序之后是 [1, 3, 4, 5, 5, 7, 9],如果排序之后的两个 5 的前后顺序没有发生变化,那么称这个排序是稳定的,反之则是不稳定的。
106 0
|
存储 搜索推荐 算法
十大经典排序算法(四)
计数排序不是基于比较的排序算法,其核心在于将输入的数据值转化为键存储在额外开辟的数组空间中。作为一种线性时间复杂度的排序,计数排序要求输入的数据必须是有确定范围的整数。 计数排序是一个稳定的排序算法。当输入的元素是 n 个 0到 k 之间的整数时,时间复杂度是O(n+k),空间复杂度也是O(n+k),其排序速度快于任何比较排序算法。当k不是很大并且序列比较集中时,计数排序是一个很有效的排序算法。
十大经典排序算法(四)
|
算法 搜索推荐 索引
十大经典排序算法(三)
堆排序(Heapsort)是指利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子结点的键值或索引总是小于(或者大于)它的父节点。堆排序可以说是一种利用堆的概念来排序的选择排序。分为两种方法: 大顶堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列; 小顶堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列; 堆排序的平均时间复杂度为 Ο(nlogn)。
十大经典排序算法(三)