算法排序2-基本排序方法1

版权声明:Firewine 的博客,想要转载请标明出处 https://blog.csdn.net/xyjworkgame/article/details/87930195


下一章

1. 排序

下面的代码基本都是使用Comparable 接口,使用这个接口实现了主键的抽象,它给出了实现这个接口数据类型的对象的大小顺序的定义。

但是,不是每次都要使用这个接口,因为数组元素的主键很可能只是每个元素的一小部分

1. 选择排序

  1. 概念:首先找到数组中最小的元素,其次,将它和数组的第一个元素交换位置(如果第一个元素就是最小元素那么它就和自己交换)。其次,在剩下的元素中找到最小的元素,将它和数组的第二个元素交换位置。如此往复,知道将整个数组排序。

  2. 在这个算法中,最重要的就是交换和比较,,所有算法的时间效率取决于比较的次数

  3. 对于选择排序,鲜明的特点就是 运行时间输入无关

     public static void sort(Comparable[] a){
         //将a 按升序排列
         int N = a.length;
         for (int i = 0; i< N; i++){
             //将a[i] 和 a[i+1,N]中最小的元素进行交换
             int min = i;
              for (int j= i+1; j< N; j++){
                  if (less(a[j],a[min])){
                      min = j;
                  }
                  exch(a,i,min);
              }
         }
    
    

2. 插入排序

  1. 插入排序就是你将每一张牌插入到已经有序的牌中的适当位置
  2. 但是在将其余所有元素在插入之前都向右移动一位
  3. 与上面的选择排序 不同的是, 插入排序所需的时间取决于输入元素中元素的初始顺序
  4. 所以通过上述的得到:插入排序对应非随机数组的排序,效率会更好

    public static void sort(Comparable[] a){
        //将a[] 按升序排序
        int N = a.length;
        for (int i=1; i < N;i++){
            //将a[i] 插入到a[i-1],a[i-2],a[i-3] ...之中
            for (int j = i; j >0 && less(a[j],a[j-1]);j--){
                exch(a,j,j-1);
            }
        }
    }
  1. 要大幅度提高插入排序的速度 的方法: 只需要在内循环中将较大的元素都向右移动而不总是交换两个元素(这样访问数组的次数就能减少一半)
  public static void sort2(Comparable[] a){
        //将a[] 按升序排序
        int N = a.length;

        for (int i=1; i < N;i++){
            //将a[i] 插入到a[i-1],a[i-2],a[i-3] ...之中
            Comparable temp = a[i];
            int j = i;
            for (; j>0 && less(temp,a[j-i]);j--){
                a[j] = a[j-1];
            }
            a[j] = temp;
            
        }
    }

3. 希尔排序

  1. 希尔排序是==基于插入排序==的快速的排序算法
  2. 希尔排序为了加快速度简单的地改进了插入排序,交换不相邻的元素以对数组的局部进行排序,并最终用插入排序将局部有序的数组排序
  3. 相当于分组排序
 public static void sort(Comparable[] a){
        int N = a.length;
        int h= 1;

        while (h < N/3){
            h = 3* h + 1;
        }
        while (h >=3){
            for (int i=h;i < N ; i++){
                for (int j =i; j>= h && less(a[i],a[j-h]); j -= h){
                    exch(a,j,j-h);
                }
                h = h/3;
            }
        }
    }

4. 归并排序

  1. 归并排序 : 可以先将它分成两半分别排序,然后再将结果归并起来,
  2. 当然最吸引人的地方是 : 它能够保证将任意长度为N的数组排序所需时间和成正比,
  3. 主要缺点是: 它所需的额外空间和N成正比
  4. 归并排序分为自顶向下自底向上的两种方法,
  5. 在归并排序中利用了高效算法中的分治思想,,,这是其中最典型的例子
//自顶向下
class Merge {

    private static Comparable[] aux;

    public static void sort(Comparable[] a) {
        aux = new Comparable[a.length];
        sort(a, 0, a.length - 1);
    }

    private static void sort(Comparable[] a, int lo, int hi) {
        if (lo < hi) {
            return;
        }
        int mid = lo + (hi - lo) / 2;
        sort(a, lo, mid);
        sort(a, mid + 1, hi);
        merge1(a, lo, mid, hi);
    }


    public static void merge1(Comparable[] a, int lo, int mid, int hi) {
        int i = lo;
        int j = mid + 1;

        for (int k = lo; k <= hi; k++) {

            aux[k] = a[k];
        }
        for (int k = lo; k <= hi; k++) {
            if (i < mid) {
                a[k] = aux[j++];
            } else if (j > hi) {
                a[k] = aux[i++];
            } else if (less(aux[j], aux[i])) {
                a[k] = aux[i++];
            }
        }

    }
}
//自底向上
class MergeBU {

    private static Comparable[] aux;
    public static void sort(Comparable[] a){
        int N = a.length;
        aux = new Comparable[N];

        for (int sz = 1; sz < N;sz = sz+sz){
            for (int i =0; i < N-sz; i += sz+sz){
                merge2(a,i,i+sz-1,Math.min(i+sz+sz-1,N-1));
            }
        }
    }
    public static void merge2(Comparable[] a, int lo, int mid, int hi) {
        int i = lo;
        int j = mid + 1;

        for (int k = lo; k <= hi; k++) {

            aux[k] = a[k];
        }
        for (int k = lo; k <= hi; k++) {
            if (i < mid) {
                a[k] = aux[j++];
            } else if (j > hi) {
                a[k] = aux[i++];
            } else if (less(aux[j], aux[i])) {
                a[k] = aux[i++];
            }
        }

    }
}
  1. 上面这个两个方法,,的临界值是 当数组长度为2的幂时,两种归并所用的比较次数和数组访问次数正好相同,只是顺序不同,
  2. 而且自底向上的排序比较适合链表组织的数据

猜你喜欢

转载自blog.csdn.net/xyjworkgame/article/details/87930195