菜单 学习猿地 - LMONKEY

VIP

开通学习猿地VIP

尊享10项VIP特权 持续新增

知识通关挑战

打卡带练!告别无效练习

接私单赚外块

VIP优先接,累计金额超百万

学习猿地私房课免费学

大厂实战课仅对VIP开放

你的一对一导师

每月可免费咨询大牛30次

领取更多软件工程师实用特权

入驻
103
0

计数排序

原创
05/13 14:22
阅读数 66718

 

 

package com.ex.cyy.demo4.alg;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class CountingSort {
    static class Node {
        int k;
        int v;

        public Node(int k, int v) {
            this.k = k;
            this.v = v;
        }
    }

    static int seed = 123;
    static Random r;

    static List<Node> randInit(int size) {
        List<Node> l = new ArrayList<>();
        r = new Random(seed);

        List<Integer> sourcePool = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            sourcePool.add(i);
        }
        for (int i = 0; i < size; i++) {
            int k = sourcePool.remove(r.nextInt(sourcePool.size()));
            l.add(new Node(k, k));
        }
        return l;
    }

    static List<Node> randInitRepit(int size, int maxk) {
        List<Node> l = new ArrayList<>();
        r = new Random(seed);

        for (int i = 0; i < size; i++) {
            int k = r.nextInt(maxk);
            l.add(new Node(k, i));
        }
        return l;
    }

    //time: O(n)
    //space: O(n)
    //stabilize: Y*   ,can modify, default: reversed position
    static Node[] countingSort(Node[] a, int maxk) {
        int[] c = new int[maxk];
        //1. scan a[] (count key's value num)
        for (int i = 0; i < a.length; i++) {
            c[a[i].k]++;
        }

        //2.add c[] (get insert index in r[])   //计算该类数值在r[]中的,属于这个数值区段的最高位索引号
        int lastV = 0;                          //先在a[]中扫到,则先插入到r[]中同数值区域中高索引号位置
        for (int i = 0; i < c.length; i++) {    //r[] 中 从右向左插入
            lastV = lastV + c[i];
            c[i] = lastV;
        }

        //3. scan a[] to r[] (sort)
        Node[] r = new Node[a.length];              //1. i=len->0 稳定
        for (int i = a.length - 1; i >= 0; i--) {   //2. i=0->len 逆稳定序(不稳定)(换成: for (int i = 0; i < a.length; i++) 的话) 
            int index = c[a[i].k] - 1;
            c[a[i].k]--;                        //插入后,将对应数值索引号-1,下一次扫到直接按此位置插入r[]
            r[index] = a[i];
        }
        return r;
    }

    public static void main(String[] args) {
        CountingSort cs = new CountingSort();
        int maxk = 5;
        int size = 9;

        long initst = System.currentTimeMillis();
        List<Node> list = cs.randInitRepit(size, maxk);
        Node[] a = new Node[list.size()];
        list.toArray(a);
        for (Node n : a) {
            System.out.print(n.k + "(" + n.v + ") ");
        }
        long initet = System.currentTimeMillis();
        System.out.println("init End , time:" + (initet - initst));

        long st = System.currentTimeMillis();
        Node[] r = countingSort(a, maxk);
        long se = System.currentTimeMillis();
        for (Node n : r) {
            System.out.print(n.k + "(" + n.v + ") ");
        }
        System.out.println("sort End , time:" + (se - st) + " size:" + size);
    }
}

 

 

 

2(0) 0(1) 1(2) 4(3) 0(4) 2(5) 4(6) 2(7) 0(8) init End , time:1
0(1) 0(4) 0(8) 1(2) 2(0) 2(5) 2(7) 4(3) 4(6) sort End , time:0 size:9

 

 

桶排序:key值区间小(key值范围小)(如年龄),key空间内数据值分布均匀的,按数据所属区间放在对应桶内(可以是区间值的桶,也可以是单值的桶(和计数排序有点相似了)),最后顺序取出,桶内可以单独用别的排序法二次排序,如快排

time:O(n)

稳定

 

计数排序:key值区间小,和单个桶值排序比较像,当数据量大,但key值范围小的时候比较有用,比如给100万个客户,按照年排序(年龄1~150);扫1次a[]得到c[],加1次c[],扫1次a[]移动到r[];

time:O(n)

稳定

 

基数排序:key值区间大(并位数大)(如手机号码),数据key值必须要位相同,位不够的补0,从低位用线性排序法,然后依次到高位(或相反顺序),要求对每位进行排序的线性排序法必须是稳定的(如桶、计数、归并、插入),否则会打乱地位排序后的结果。

time:O(n)

稳定:Y ,要求对每位排序的算法稳定

发表评论

0/200
103 点赞
0 评论
收藏
为你推荐 换一批