高级排序

一、希尔排序(对插入排序进行优化)

     原理:1.选定一个增长量h,按h作为分组依据,对数据进行分组

                2.对分好组的每一组进行插入排序

                3.减少增长量,最少减为一,重复第二步操作

   增长量的确定:

     

int h=1;
while(h<数组长度/2){
h=2h+1;
}
//循环结束后就是最大的h
//h的减小规则
h=h/2;

  

    public static void sort(Comparable[] a){
        //增长量h
        int h=1;
        //根据数组长度来确定增长量h的值
       while (h<a.length/2){
            h=2*h+1;
        }
       //写入排序
        while(h>=1){
            //排序
            //找到待插入元素
             for(int i=h;i<a.length;i++){
                 //把待插入元素插入到有序数列中
                 for(int j=i;j>=h;j-=h){
                     //待插元素为a[j],与a[j-h]比较
                     if(greater(a[j-h],a[j])){
                         exch(a,j-h,j);
                     }else{
                         break;
                     }
                 }
             }
            //h减少
            h=h/2;
        }
    }

二、归并排序

         原理:1. 尽可能的一组数据拆分为相等的两份,并对每一个自组继续进行拆分,直到拆分后每个自组的元素个数为1;

                    2. 将两个自组合并成一个有序的大组

                    3.不断重复步骤2,直到成为一个大组

                  

public class Merge {
    public static void main(String[] args) {
        //原数组
      int[] a={9,8,6,5,2,1};
        //归并所需要的复制数组
      int[] tem=new int[a.length];
      int lo=0;
      int hi=a.length-1;
      sort(a,lo,hi,tem);
      System.out.println(Arrays.toString(a));
    }
    /**
     *对数组a从lo到hi进行排序
     * @param a
     */
    public static void sort(int[] a,int lo,int hi,int[] tem){
        if(lo<hi){
            //将数组进行分组
            int mid=(lo+hi)/2;
            //分组之后对每一组进行排序
            sort(a,lo,mid,tem);
            sort(a,mid+1,hi,tem);
            //再把两个数组进行归并
             merge(a,lo,hi,mid,tem);
        }


    }
    /**
     * 对数组,从lo到mid,mid+1到hi两个数组合并排序
     */
    public static void merge(int[] a,int lo,int hi,int mid,int[] tem){
        //此指针指向辅助数组
        int i=lo;
        //此指针指向前数组
        int p1=lo;
        //此指针指向后面的数组
        int p2=mid+1;
        //遍历,移动p1和p2,如果p1指针超过mid或者p2超过mid结束
          while(p1<=mid && p2<=hi){
              if(a[p1]<a[p2]){
                  tem[i++]=a[p1++];//把a[p1]给辅助数组,并且指针后移
              }else{
                  tem[i++]=a[p2++];
              }
          }
        //如果p1指针指向的数组没遍历完,那么直接赋给tem
          while (p1<=mid){
              tem[i++]=a[p1++];
          }
        //如果p2指针指向的数组没遍历完,那么直接赋给tem
        while (p2<=hi){
            tem[i++]=a[p2++];
        }
        //把assist数组拷贝到a数组中
        for (int index=lo;index<=hi;index++){
                a[index]=tem[index];
        }
    }
}

三、快速排序

      原理:快速排序是对冒泡排序的改进;

                1. 首先选定一个分界值,将数组分为两部分

                2. 将大于等于分界值的数据放到右边,小于的放到左边

                3. 对左边和右边分别进行2步骤

                4. 重复上述步骤,通过递归对左右两部分进行排序,最后完成

                   

    把一个数组切分为两个数组的原理:

            1.找一个基准值(一般为第一个元素,6),用两个指针分别指向数组的头部和尾部+1的位置

              

             2.先从尾部向头部开始搜索一个比基准值小的元素,并停止,记录元素。

             3.再从头部向尾部开始搜索一个比基准值小的元素,并停止,记录元素。

             4.交换左右指针所指的值。

             5.重复上述操作

public class Partition{
    public static void main(String[] args) {
        //原数组
      int[] a={1,6,2,12,9,10};
      int lo=0;
      int hi=a.length-1;
      sort(a,lo,hi);
      System.out.println(Arrays.toString(a));
    }
    /**
     *对数组a从lo到hi进行排序
     * @param a
     */
    public static void sort(int[] a,int lo,int hi){
        if (lo<hi){
            //对数组a从lo到hi进行分组(左和右子组),返回分界索引
            int partition = partition(a, lo, hi);
            //对左子组进行排序
            sort(a,lo,partition-1);
            //对右子组进行排序
            sort(a,partition+1,hi);
        }

    }
    /**
     * 对数组,从lo到hi两个数组进行分组并返回分界索引
     */
    public static int partition(int[] a,int lo,int hi) {
        //分界值
        int key=a[lo];
        //头指针
        int left=lo;
        //尾指针的下一个位置
        int right=hi+1;
        while (true)
        {
            //先从右往左扫描,移动right,如果right所指的值小于key则停止
            while (a[--right]>key){
                if(right==lo){
                    break;
                }
            }
            //从左往右扫描,移动left,如果left所指的值大于key则停止
            while (a[++left]<key){
                if (left==hi){
                    break;
                }
            }
            //判断left>=right,则扫描完毕,结束循环,如果不是则交换元素
            if (left>=right){
                break;
            }else {
                exch(a,left,right);
            }
        }
        exch(a,lo,right);
        return right;
    }

    private static void exch(int[] a, int hi, int lo) {
        int temp = 0;
        temp =a[lo];
        a[lo]=a[hi];
        a[hi]=temp;
    }
}

 四、排序的稳定性

      1.定义:假设数组a中右若干元素,其中A和B相等,在A在B的前面,在排完序之后任能保证A在B的前面,则稳定

       2.常见排序算法的稳定性

           稳定的:排序、插入、归并

           不稳定的:选择、希尔、快速

       

原文地址:https://www.cnblogs.com/cqyp/p/12547247.html