zoukankan      html  css  js  c++  java
  • 算法排序2-基本排序方法1


    下一章

    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. 而且自底向上的排序比较适合链表组织的数据
  • 相关阅读:
    SQLite学习手册(开篇)
    SQLite学习手册(索引和数据分析/清理)
    SQLite学习手册(在线备份)
    SQLite学习手册(数据类型)
    SQLite学习手册(表达式)
    SQLite学习手册(C/C++接口简介)
    SQLite学习手册(命令行工具)
    (转)Graphical Execution Plans for Simple SQL Queries
    诡异的Request
    今天用windows live writer 2009写博客了
  • 原文地址:https://www.cnblogs.com/YJBlog/p/10440694.html
Copyright © 2011-2022 走看看