【Java】Java 基数排序,希尔排序,桶排序,计数排序

希尔排序

希尔排序的时间复杂度十分复杂,它与分组序列有关,本这次的分组序列为 4,2,1,即 N / (2的n次方)
最坏的情况为O(n²)一般是 O(n)< t <=O(n²)
其他的分组序列对应的时间复杂度,可百度查看相关资料。

/*
希尔排序是一种分组插入排序算法。比插入排序快
首先取一个整数d1=n/2,将元素分为d1个组,每组相邻量元素之间距离为d1,在各组内进行直接插入排序
取第二个整数d2=d1/2,重复上述分组排序过程,直到di=1,即所有元素在同一组内进行直接插入排序
希尔排序每趟并不使某些元素有序,而是使整体数据趋近有序,最后一趟使所有数据有序
*/
public class Main{
    public static void main(String[] args) {
        int[] arr = {5, 1, 6, 9, 4, 8, 2, 3, 7};
        //调用希尔排序函数
        ShellSort(arr);
        //输出结果
        for (int i : arr) {
            System.out.print(i+", ");
        }
    }
    // 希尔排序(分组的插入排序)
    public static void ShellSort(int[] arr){
        int d = arr.length;
        while (d>=1){
            InsertSortGap(arr, d);
            d /= 2;
        }
    }
    // 插入排序
    public static void InsertSortGap(int[] arr, int gap){
        int tmp;
        int j;
        for (int i = gap; i < arr.length; i++) {
            tmp = arr[i];
            j = i-gap;
            while (j>=0 && arr[j]>tmp){
                arr[j+gap] = arr[j];
                j -= gap;
            }
            arr[j+gap] = tmp;
        }
    }
}
/*		  ↓           ↓	          ↓  5,4,7间距相差都为d(第一次的d为4)
元素数据 :5, 1, 6, 9, 4, 8, 2, 3, 7
分组间隔4: 4, 1, 2, 3, 5, 8, 6, 9, 7,  第一次分组
分组间隔2: 2, 1, 4, 3, 5, 8, 6, 9, 7,  第二次分组
分组间隔1: 1, 2, 3, 4, 5, 6, 7, 8, 9,  第三次分组
第一次分组:(分组依据就是每个元素之间距离为d)
5,      4,       7  //第一组  
 1,       8,		//第二组
  6,      	2,      //第三组
    9,        3,    //第四组
每组分别进行插入排序后
4,      5,       7  //第一组  
 1,       8,		//第二组
  2,      	6,      //第三组
    3,        9,    //第四组
分组间隔4排完后: 4, 1, 2, 3, 5, 8, 6, 9, 7,
然后继续分成2组
4, 2, 5, 6, 7, 第一组
  1, 3, 8, 9,   第二组
每组分别进行插入排序后
2, 4, 5, 6, 7,
 1, 3, 8, 9,   
分组间隔2排完后:2, 1, 4, 3, 5, 8, 6, 9, 7,
可以看出每次分组排序后,并不是某个元素到达正确的顺序,
而是整体在不断趋于顺序,直到最后分组间隔为1时(即一次普通的插入排序)排序后使整体彻底排好顺序
*/

计数排序

时间复杂度:O(n)

/*
对列表进行排序,已知列表中的数范围。
*/
public class Main{
    public static void main(String[] args) {
        // 随机生成一个长度25,元素在[1,10]的集合
        ArrayList<Integer> arr = GetArr();
        // 排序前集合
        System.out.print("排序前:");
        for (int i : arr) {
            System.out.print(i+", ");
        }
        System.out.println();


        // 创建一个长度等于集合中最大值的数组
        // 对集合中的数进行统计
        int[] count = new int[Collections.max(arr)+1];
        for (int i :arr){
            count[i]++;
        }

        //输出count数组
        //System.out.print("统计结果,下标代表数,元素代表该数的个数:");
        //for (int i : count) {
        //    System.out.print(i+", ");
        //}
        //System.out.println();

        //清空集合后重新写入
        arr.clear();
        //这里虽然是嵌套循环,但是写入的次数总共是n(原arr长度)次
        for (int i = 0; i < count.length; i++) {
            // 将元素i 写入count[i]次
            while (count[i]>0){
                arr.add(i);
                count[i]--;
            }
        }
        //输出排序结果
        System.out.print("排序后:");
        for (int i : arr) {
            System.out.print(i+", ");
        }
        System.out.println();
    }


    // 获取随机集合
    public static ArrayList<Integer> GetArr(){
        ArrayList<Integer> arr = new ArrayList<>();
        for (int i = 1; i <= 25; i++) {
            int a = (int)(Math.random()*10+1);
            arr.add(a);
        }
        return arr;
    }
}
/*
排序前:5, 8, 8, 7, 2, 2, 1, 6, 3, 6, 2, 5, 3, 1, 6, 5, 5, 9, 7, 7, 7, 3, 7, 5, 1, 
排序后:1, 1, 1, 2, 2, 2, 3, 3, 3, 5, 5, 5, 5, 5, 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 9, 

计数排序虽然时间复杂度为O(n)但是要使用它本身就有很多限制
1.必须知道要排序的数组元素范围
2.消耗空间大,假设只有10个数但是是0到1亿,那么在统计时就要开长度为1亿的数组。
*/

桶排序

桶排序的时间复杂度与桶的分配有关
平均情况时间复杂度:O(n+k)
最坏情况时间复杂度:O(n²k)
空间复杂度:O(nk)

public class Main{
    public static void main(String[] args) {
        // 随机生成一个长度150,元素在[1,100]的集合
        ArrayList<Integer> arr = GetArr();
        int max_num = Collections.max(arr);
        // 排序前集合
        System.out.print("排序前:");
        for (int i : arr) {
            System.out.print(i+", ");
        }
        System.out.println();
        //调用桶排序函数这里分了10个桶
        // 也可以写成 bucket_num = (Collections.max(arr) - Collections.min(arr)) / arr.size() + 1
        BucketSort(arr, 10, max_num);
    }

	// 桶排序
    public static void BucketSort(ArrayList<Integer> arr, int bucket_num, int max_num){
        // 创建桶
        ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(bucket_num);
        for(int i = 0; i < bucket_num; i++){
            buckets.add(new ArrayList<>());
        }

        int i; // 桶号
        for (int val : arr){
            i = Math.min(val /(max_num/bucket_num), bucket_num-1);
            buckets.get(i).add(val);
            // 维持桶中数据的顺序,这一步也可以分开写,先将元素全部装入桶,再对每个桶进行排序
            // 这里用自带的排序函数,也可以用之前写的冒泡排序等
            Collections.sort(buckets.get(i));
        }
        System.out.print("排序后:");
        System.out.println(buckets);
    }


    // 获取随机集合
    public static ArrayList<Integer> GetArr(){
        ArrayList<Integer> arr = new ArrayList<>();
        for (int i = 1; i <= 150; i++) {
            int a = (int)(Math.random()*100+1);
            arr.add(a);
        }
        return arr;
    }
}
/*
排序前:81, 17, 12, 77, 15, 55, 78, 76, 26, 27, 22, 84, 75, 60, 79, 90, 46, 72, 15, 1, 62, 68, 97, 47, 65, 23, 64, 35, 3, 78, 49, 24, 20, 32, 69, 61, 97, 49, 11, 6, 94, 37, 49, 54, 74, 9, 80, 55, 21, 72, 47, 94, 66, 67, 26, 25, 35, 8, 80, 15, 61, 59, 56, 60, 75, 8, 89, 57, 84, 24, 79, 77, 62, 72, 90, 35, 19, 13, 57, 43, 14, 18, 13, 34, 54, 63, 74, 89, 70, 12, 79, 97, 34, 90, 65, 11, 26, 46, 79, 76, 44, 84, 78, 63, 19, 32, 21, 35, 50, 21, 71, 40, 100, 51, 69, 50, 83, 5, 50, 1, 94, 93, 13, 45, 39, 17, 24, 79, 24, 48, 10, 32, 19, 36, 21, 91, 55, 68, 3, 75, 57, 54, 75, 29, 88, 86, 14, 88, 85, 100, 
排序后:[
1号桶:[1, 1, 3, 3, 5, 6, 8, 8, 9], 
2号桶:[10, 11, 11, 12, 12, 13, 13, 13, 14, 14, 15, 15, 15, 17, 17, 18, 19, 19, 19], 
3号桶:[20, 21, 21, 21, 21, 22, 23, 24, 24, 24, 24, 25, 26, 26, 26, 27, 29], 
4号桶:[32, 32, 32, 34, 34, 35, 35, 35, 35, 36, 37, 39],
5号桶:[40, 43, 44, 45, 46, 46, 47, 47, 48, 49, 49, 49],
6号桶:[50, 50, 50, 51, 54, 54, 54, 55, 55, 55, 56, 57, 57, 57, 59], 
7号桶:[60, 60, 61, 61, 62, 62, 63, 63, 64, 65, 65, 66, 67, 68, 68, 69, 69], 
8号桶:[70, 71, 72, 72, 72, 74, 74, 75, 75, 75, 75, 76, 76, 77, 77, 78, 78, 78, 79, 79, 79, 79, 79], 
9号桶:[80, 80, 81, 83, 84, 84, 84, 85, 86, 88, 88, 89, 89],
10号桶:[90, 90, 90, 91, 93, 94, 94, 94, 97, 97, 97, 100, 100]
]

桶排序的时间复杂度与桶的分配有关
假设有100个数据,其中90个数据都是在90~100那么几乎所有的数都将分到最后一个桶中,就失去了分桶的意义。
所以桶排序适用于数据分布比较均匀的情况,当然在知道数据分布的情况时我们可以人为的设置桶的分配情况
假设有100个数据,还是分10个桶,其中90个数据都是在90~100
那么可以针对这90个数进行分桶,例如第一个桶的范围是[0,89],剩下的9个桶都分到这90个数上去,每个桶装10个数。
*/

基数排序

时间复杂度:O(kn)
空间复杂度:O(k+n)
k: 数字位数

public class Main{
    public static void main(String[] args) {
        ArrayList<Integer> arr = GetArr();
        RadixSort(arr);
    }
    // 基数排序
    public static void RadixSort(ArrayList<Integer> arr){
        int max_num = Collections.max(arr); // 确定循环次数
        int it = 0, digit;
        //从个位开始,每循环一次就上升一位,当超过最大数值的位数时退出循环
        // 10**0 = 1, 10**1 = 10, 10**2 = 100 (python中**代表次方)
        while (Math.pow(10,it) <= max_num){
            //分桶 0,1,2,3,4,5,6,7,8,9
            //分10个桶,因为每一位数字的范围是[0,9]
            ArrayList<ArrayList<Integer>> buckets = new ArrayList<>(10);
            for (int i = 0; i < 10; i++){
                buckets.add(new ArrayList<>());
            }

            //排序
            for (Integer val : arr){
                digit = (val / (int)Math.pow(10,it)) % 10; // 获取当前位的数字
                buckets.get(digit).add(val);
            }
            // 更新原集合顺序
            arr.clear();
            for(ArrayList<Integer> bucket : buckets){
                arr.addAll(bucket);
            }
            it++;
        }
        System.out.println("排序后:"+arr);
    }

    // 获取随机集合
    public static ArrayList<Integer> GetArr(){
        ArrayList<Integer> arr = new ArrayList<>();
        for (int i = 1; i <= 100; i++) {
            int a = (int)(Math.random()*100+1);
            arr.add(a);
        }
        System.out.println("排序前:"+arr);
        return arr;
    }
}
/*
排序前:[31, 21, 90, 61, 46, 95, 49, 39, 21, 37, 81, 80, 4, 2, 25, 42, 20, 44, 69, 24, 26, 17, 80, 29, 62, 27, 47, 83, 100, 22, 3, 60, 89, 74, 17, 29, 40, 67, 52, 82, 85, 84, 38, 70, 19, 47, 79, 17, 65, 34, 16, 78, 71, 95, 10, 20, 18, 46, 53, 44, 27, 18, 16, 65, 5, 23, 43, 19, 24, 82, 67, 56, 33, 59, 73, 69, 14, 46, 43, 72, 63, 26, 56, 49, 39, 68, 43, 82, 36, 90, 25, 47, 80, 50, 27, 94, 6, 30, 45, 85]

每次排序桶内的情况:

按个位排:[
0桶:[90, 80, 20, 80, 100, 60, 40, 70, 10, 20, 90, 80, 50, 30], 
1桶:[31, 21, 61, 21, 81, 71], 
2桶:[2, 42, 62, 22, 52, 82, 82, 72, 82], 
3:[83, 3, 53, 23, 43, 33, 73, 43, 63, 43], 
4:[4, 44, 24, 74, 84, 34, 44, 24, 14, 94], 
5:[95, 25, 85, 65, 95, 65, 5, 25, 45, 85], 
6:[46, 26, 16, 46, 16, 56, 46, 26, 56, 36, 6], 
7:[37, 17, 27, 47, 17, 67, 47, 17, 27, 67, 47, 27], 
8:[38, 78, 18, 18, 68], 
9:[49, 39, 69, 29, 89, 29, 19, 79, 19, 59, 69, 49, 39]
]
按十位排:[
0 [100, 2, 3, 4, 5, 6], 
1 [10, 14, 16, 16, 17, 17, 17, 18, 18, 19, 19], 
2 [20, 20, 21, 21, 22, 23, 24, 24, 25, 25, 26, 26, 27, 27, 27, 29, 29], 
3 [30, 31, 33, 34, 36, 37, 38, 39, 39], 
4 [40, 42, 43, 43, 43, 44, 44, 45, 46, 46, 46, 47, 47, 47, 49, 49], 
5 [50, 52, 53, 56, 56, 59], 
6 [60, 61, 62, 63, 65, 65, 67, 67, 68, 69, 69], 
7 [70, 71, 72, 73, 74, 78, 79], 
8 [80, 80, 80, 81, 82, 82, 82, 83, 84, 85, 85, 89], 
9 [90, 90, 94, 95, 95]
]
按百位排:[
0 [2, 3, 4, 5, 6, 10, 14, 16, 16, 17, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 23, 24, 24, 25, 25, 26, 26, 27, 27, 27, 29, 29, 30, 31, 33, 34, 36, 37, 38, 39, 39, 40, 42, 43, 43, 43, 44, 44, 45, 46, 46, 46, 47, 47, 47, 49, 49, 50, 52, 53, 56, 56, 59, 60, 61, 62, 63, 65, 65, 67, 67, 68, 69, 69, 70, 71, 72, 73, 74, 78, 79, 80, 80, 80, 81, 82, 82, 82, 83, 84, 85, 85, 89, 90, 90, 94, 95, 95], 
1 [100], [], [], [], [], [], [], [], [] (最大数是100,所有只有0,1号桶有数)
]
排序后:[2, 3, 4, 5, 6, 10, 14, 16, 16, 17, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 23, 24, 24, 25, 25, 26, 26, 27, 27, 27, 29, 29, 30, 31, 33, 34, 36, 37, 38, 39, 39, 40, 42, 43, 43, 43, 44, 44, 45, 46, 46, 46, 47, 47, 47, 49, 49, 50, 52, 53, 56, 56, 59, 60, 61, 62, 63, 65, 65, 67, 67, 68, 69, 69, 70, 71, 72, 73, 74, 78, 79, 80, 80, 80, 81, 82, 82, 82, 83, 84, 85, 85, 89, 90, 90, 94, 95, 95, 100]


*/

桶排序与基数排序的区别:
桶排序:

装一次桶,在桶中排序

基数排序:

装多次桶,不在桶中排序,只是装桶,输出,装桶,输出。。。 
排序是因为桶是有序的(0,1,2······)0桶总是先输出,然后1桶,2桶·····

冒泡排序,选择排序,插入排序

https://blog.csdn.net/m0_60370702/article/details/123360290?spm=1001.2014.3001.5502

快速排序,归并排序,堆排序

https://blog.csdn.net/m0_60370702/article/details/123417783?spm=1001.2014.3001.5502

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值