算法 非比较排序

一、时间复杂度为o(n)的算法

1.1 计数排序

  • 思路:设定一个范围的桶,如1~100编号的桶,将数据放到对应编号的桶中,让然后将数据从桶中倒出来。

以下是用二维数组模拟桶,二维数组第一列代表数据,第二列代表数据的个数

public static void sort(int[] array){
        int[][]  Bucket = new int[15][2];
        for (int i = 0; i < Bucket.length; i++) {
            Bucket[i][0] = 999999;
            Bucket[i][1] = 0;
        }
        for(int num : array){
            Bucket[num][0] = num;
            Bucket[num][1]  ++;
        }
        for (int i = 0; i < Bucket.length; i++) {
           while (Bucket[i][1] != 0){
               System.out.print(Bucket[i][0] + " ");
               Bucket[i][1] --;
           }
        }
    }

缺点:

  • 耗内存
  • 只适合对整数排序

补充:
int[][] arr = new int[4][];
System.out.println(arr.length);
System.out.println(arr[0].length);
第一个输出的是二维数组的行数,第二个输出的是二维数组的列数。

1.2 基数排序

  • 思路:将每个数据按照个位数的大小放到对应的桶中,倒出,再将每个数据按照十位数的大小放到对应的桶中,倒出,将每个数据按照百位数的大小放到对应的桶中,倒出…
  • 使用队列
  • 我们需要手动的调整sort()方法中,调用kind()方法的次数。
public static int[] sort(int[] array){
        array = kind(array,1);
        array = kind(array,2);
        return array;

    }
public static int[] kind(int[] array, int n){
        int flag = 0;
        Queue[] queues = new Queue[10];
        for (int i = 0; i < queues.length; i++) {
            queues[i] = new LinkedList();
        }
        //将数据入桶
        for(int num : array){
            int mid = (num / ((int)Math.pow(10,n-1)) % 10);
            queues[mid].offer(num);
        }
        //将数据倒出
        for (int i = 0; i < queues.length; i++) {
            while (!queues[i].isEmpty()) {
                int remove = (int) queues[i].poll();
                array[flag++] = remove;
            }
        }
        return array;
    }

二、对排序算法的比较

2.1 空间复杂度

  • o(1)
    插入排序,选择排序,冒泡排序,堆排序,希尔排序
  • o(logN)~o(N)
    快速排序
  • o(N)
    归并排序
  • o(M)
    计数排序,基数排序(取决于桶的数量)

2.2 排序算法的稳定性

稳定性的概念:
在待排序的记录序列中,存在多个具有相同关键字的记录,若经过排序,这些记录的相对次序保持不变,则这种算法就是稳定的,否则就是不稳定的。

  • 不稳定
    选择排序,堆排序,希尔排序,快速排序

2.2.1 选择排序不稳定

比如2,2,2,1,选择最小的数放在前面,则第一个2与1次序交换

2.2.2 堆排序不稳定

比如3,3,3,建立好堆结构后,最大值需与最后一个值交换次序

2.2.3 快排不稳定

比如1,2,2,2,4,取中间的2位key,则左右两边的2要么都在左边,要么都在右边。

2.3.4 希尔排序不稳定

比如1,3,3,1 步长为2时,后面的3与第一个1交换,则3的次序发生改变

三、补充

3.1 为什么说快速排序是最优的算法

参考:为什么说快速排序是性能最好的排序算法?

快速排序的常量系数比较小

3.2 jdk1.8的快排

Java1.8的快排是一种双轴快排

算法步骤

1.对于很小的数组(长度小于27),会使用插入排序。
2.选择两个点P1,P2作为轴心,比如我们可以使用第一个元素和最后一个元素。
3.P1必须比P2要小,否则将这两个元素交换,现在将整个数组分为四部分:
(1)第一部分:比P1小的元素。
(2)第二部分:比P1大但是比P2小的元素。
(3)第三部分:比P2大的元素。
(4)第四部分:尚未比较的部分。
在开始比较前,除了轴点,其余元素几乎都在第四部分,直到比较完之后第四部分没有元素。
4.从第四部分选出一个元素a[K],与两个轴心比较,然后放到第一二三部分中的一个。
5.移动L,K,G指向。
6.重复 4 5 步,直到第四部分没有元素。
7.将P1与第一部分的最后一个元素交换。将P2与第三部分的第一个元素交换。
8.递归的将第一二三部分排序。

参考:深入理解Arrays.sort()

3.3 排序算法的选择

元素个数较少,插入排序,冒泡排序,元素个数较大,快排,堆排,元素个数特别大,快排。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值