算法-12-排序算法应用

目录

1、排序比较

2、算法稳定性

3、指针排序

4、Arrays.sort()

5、找出重复元素

6、找出中位数(第k小的数)


1、排序比较

                        

2、算法稳定性

如果一个排序算法能够保留数组中重复元素的相对位置则可以被称为是稳定的。

应用场景:对于记录有大量位置和时间的一个列表库,每条数据的插入都是按照时间顺序插入的,我们现在要对该数组按照地点给来进行排序,拥有稳定性的排序算法在排序之后,时间还具有一定的有序性。上面的各个排序算法比较,记录各自的稳定性。

                                     

3、指针排序

在 Java 中,指针操作是隐式的。除了原始数字类型之外,我们操作的总是数据的引用(指针), 而非数据本身。指针排序增加了一层间接性,因为数组保存的是待排序的对象的引用,而非对象本身。

使用引用的另一个好处是我们不必移动整个元素。对于元素大而键小的数组来说这带来的节 约是巨大的,因为比较只需要访问元素的一小部分,而排序过程中元素的大部分都不会被访问到。

对于几乎任意大小的元素,使用引用使得在一般情况下交换的成本和比较的成本几乎相同(代价 是需要额外的空间存储这些引用)。如果键值很长,那么交换的成本甚至会低于比较的成本。研 究将数字排序的算法性能的一种方法就是观察其所需的比较和交换总数,因为这里隐式地假设了 比较和交换的成本是相同的。由此得出的结论则适用于 Java 中的许多应用,因为我们都是在将引 用排序。  

4、Arrays.sort()

 Java 系统库中的主要排序方法 java.util. Arrays.sort()。根据不同的参数类型,它实际上代表了一系列排序方法:

  1.  每种原始数据类型都有一个不同的排序方法;
  2.  一个适用于所有实现了 Comparable 接口的数据类型的排序方法;
  3.  一个适用于实现了比较器 Comparator 的数据类型的排序方法。

Java 的系统程序员选择对原始数据类型使用(三向切分的)快速排序,对引用类型使用归并排 序。这些选择实际上也暗示着用速度和空间(对于原始数据类型)来换取稳定性(对于引用类型)。 

5、找出重复元素

普通方法:用平方级别O(n2)的算法,将所有元素比较

进阶方法:用线性对数级别O(N*lgN)的算法,先将元素比较,然后再遍历所有元素,记录重复元素即可。

                         

6、找出中位数(第k小的数)

普通方法一:将前50%排序,找到中位数------优先队列(最小堆)----插入NlgN级别,取出k*lgN级别。总(N+k)*lgN

普通方法二:将所有元素排序---------------------快速排序------------------排序NlgN级别,取出是1。总(NlgN+1

进阶方法:利用快速排序中切分,快速排序中根据数组的第一个元素key的大小,将数组切分大于key,和小于key两部分,然后根据key所在的下标 k(a[k]=key),继续递归切分前后两部分数组,直到每个子数组都是依次排序的。

寻找中位数的方法就是按照上面的切分方法,根据第一个元素key切分数组,返回key的下标k,如果k==mid,那么key就是我们要找的中位数,如果mid<k,我们继续切分比key小的那一部分数组,如果mid>k,我们切分比key大的那一部分数组,如此循环,直到找到正确的mid。

进阶方法的时间复杂度在线性级别,为什么呢?假设下面的切分每次正好将数组二分,那么比较的总次数为(N+N/2+N/4+N/8.....)h,直到找到k元素,这个和显然小于2N。平均需要~(2+2In2)N次比较,最坏情况下还是平方级别的时间复杂度。不管怎么说,它相对于普通方法二来说,都是要快的。

public class MidSelect {
    public static double select(double[] a ,int k){
        int lo=0;
        int hi=a.length-1;
        while (hi>lo){
            int j=partition(a,lo,hi);
            if (k==j) return a[k];
            if (k<j) hi=j-1;
            if (k>j) lo=j+1;
        }
        return a[k];
    }
    private static int partition(double[] a, int lo, int hi) {
        double key=a[lo];
        int left=lo;
        int right=hi+1;

        while (true){
            while (key > a[++left])  if (left == hi) break;
            while (key < a[--right]) if (right == lo) break;
            if (left>=right)break;
            exch(a,left,right);

        }
        exch(a,lo,right);
        return right;
    }
    private static void exch(double[] a, int left, int right) {

        double temp=a[left];
        a[left]=a[right];
        a[right]=temp;
    }
    private static void show(double[] a) {
        System.out.println("\n");
        for (double item : a) {
            System.out.print((int) item + ",");
        }
    }
    public static void main(String[] args) {
        double[] a = { 55, 43, 23, 12, 13, 11, 7, 8, 88, 6, 3, 2, 4, 1, 9, 8, 7, 11, 56, 45, 22, 23,
                45, 66 };
        double mid=select(a,a.length/2);
        show(a);
        System.out.println("mid="+mid);
    }
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值