Java基础—归并排序,非递归快速排序

1.递归的快速排序优化

  • 第一种优化思想

1.首先快速排序对于大量数据比如以万为计量单位,那么快排的时间复杂度和空间复杂度都是相对于其他几个排序都是最好的,那么对于少量数据比如10个,100个,快速排序显然已经不是最好的了;
2.那么快速排序每次经过找基准,这样数据就在慢慢趋于有序,这个时候当low和high之间的数据小于一个给定的值的时候,比如100,我们就可以之间调用之间插入排序来进行排序;

public static void quick(int[] arr,int low,int high){
    
    
        if(low > high){
    
    
            return;
        }
        //第一个优化:当low,high之间的数据个数少于某一个范围,可以调用直接插入排序
        if(high-low+1 < 100){
    
    
            insertsort2(arr,low,high);
            return;
        }
    }
    //用来优化的的直接插入排序
    public static void insertsort2(int[] arr,int low,int high){
    
    
        for(int i = low+1;i <= high;i++) {
    
    
            int tmp = arr[i];
            int j = i-1;
            for (;j >= low;j--){
    
    
                if (arr[j] > tmp) {
    
    
                    arr[j+1] = arr[j];
                }else{
    
    
                    break;
                }
            }
            arr[j+1] = tmp;
        }
    }
   
  • 第二种优化

1.比如对于{1,2,3,4,5}这一组数据,每一次取左边0号下标的的数据作为基准,每次确定基准位置后,就会出现极端情况,数据全在基准的右边,那么对于确定基准的位置,大家认为是每次确定后,基准左边和右边都有数据好,还是出现极端情况排序好,那么显而易见,俩边都有的时候情况好;
2.那么怎样才能保证每次基准的俩边都有数据呢,我们每次都取最左边low,最右边high,中间下标mid=(high+low)/2,这三个下标对应数据的中位数,也就是(arr[mid] < arr[low] < arr[high]),最后low下标放的就是这个中位数,不管在这三个位置哪个位置找到,只需要把他和low位置进行交换,那么low就永远放的就是这个中位数;

public static void quick(int[] arr,int low,int high){
    
    
        if(low > high){
    
    
            return;
        }
        }
        //第二次优化,取三个数中位数,这样的基准就不会出现极端情况
        mid(arr,low,high);
        //par是基准
        int par = parttion(arr,low,high);
        quick(arr,low,par-1);
        quick(arr,par+1,high);
    }
    //优化的取三个数字的中位数
    public static void mid(int[] arr,int low,int high){
    
    
        /*int mid = (high+low)/2;
        if (arr[low] < arr[mid] && arr[mid] < arr[high]){
            int tmp = arr[low];
            arr[low] = arr[mid];
            arr[mid] =tmp;
            System.out.println(low);
        }else if(arr[high] > arr[low] && arr[high] < arr[mid]) {
            int tmp = arr[high];
            arr[high] = arr[low];
            arr[low] =tmp;
            System.out.println(low);
        }else{
            System.out.println(low);
            return;
        }*/
        int mid = (low+high)/2;
        //array[mid] < array[low] < array[high]
        if(arr[low] >= arr[high]) {
    
    
            swap(arr,low,high);
        }
        if(arr[low] <= arr[mid]) {
    
    
            swap(arr,low,mid);
        }
        if(arr[mid] >= arr[high]) {
    
    
            swap(arr,low,mid);
        }
    }
  • 俩种优化的全部代码
public static void quicksort(int[] arr){
    
    
        quick(arr,0,arr.length-1);

    }
    //
    public static void quick(int[] arr,int low,int high){
    
    
        if(low > high){
    
    
            return;
        }
        //第一个优化:当low,high之间的数据个数少于某一个范围,可以调用直接插入排序
        if(high-low+1 < 100){
    
    
            insertsort2(arr,low,high);
            return;
        }
        //第二次优化,取三个数中位数,这样的基准就不会出现极端情况
        mid(arr,low,high);
        //par是基准
        int par = parttion(arr,low,high);
        quick(arr,low,par-1);
        quick(arr,par+1,high);
    }
    //用来优化的的直接插入排序
    public static void insertsort2(int[] arr,int low,int high){
    
    
        for(int i = low+1;i <= high;i++) {
    
    
            int tmp = arr[i];
            int j = i-1;
            for (;j >= low;j--){
    
    
                if (arr[j] > tmp) {
    
    
                    arr[j+1] = arr[j];
                }else{
    
    
                    break;
                }
            }
            arr[j+1] = tmp;
        }
    }
    //优化的取三个数字的中位数
    public static void mid(int[] arr,int low,int high){
    
    
        /*int mid = (high+low)/2;
        if (arr[low] < arr[mid] && arr[mid] < arr[high]){
            int tmp = arr[low];
            arr[low] = arr[mid];
            arr[mid] =tmp;
            System.out.println(low);
        }else if(arr[high] > arr[low] && arr[high] < arr[mid]) {
            int tmp = arr[high];
            arr[high] = arr[low];
            arr[low] =tmp;
            System.out.println(low);
        }else{
            System.out.println(low);
            return;
        }*/
        int mid = (low+high)/2;
        //array[mid] < array[low] < array[high]
        if(arr[low] >= arr[high]) {
    
    
            swap(arr,low,high);
        }
        if(arr[low] <= arr[mid]) {
    
    
            swap(arr,low,mid);
        }
        if(arr[mid] >= arr[high]) {
    
    
            swap(arr,low,mid);
        }
    }
    public static void swap(int[] arr,int low,int high){
    
    
        int tmp = arr[low];
        arr[low] = arr[high];
        arr[high] = tmp;
    }
    //划分函数
    public static int parttion(int[] arr,int start,int end){
    
    
        //申请一个tmp空间用来放基准的值(基准一般选择的是边上的值)
        int tmp = arr[start];//这里取的是最左边的值,那么一会就先从最右边开始找[end]位置
        while(start < end){
    
    
            while(start < end && arr[end] >= tmp){
    
    
                end--;
            }
            //到了这里,从while出来有俩种情况,不满足start < end或者不满足arr[end] >= tmp
            if (start >= end){
    
    
                //arr[start] = tmp;
                break;//直接退出,因为已经遍历完毕
            }else{
    
    //else就是arr[end] < tmp
                arr[start] = arr[end];
            }
            while(start < end && arr[start] <= tmp){
    
    
                start++;
            }
            //到了这里,同样从while出来有俩种情况,不满足start < end或者不满足arr[start] <= tmp
            if (start > end){
    
    
                //arr[end] = tmp;
                break;
            }else{
    
    
                arr[end] = arr[start];
            }
        }
        arr[start] = tmp;
        return start;//返回基准移动到位置,这样基准的左边全小于它,右边全都大于它
    }


2.非递归的快速排序

  • 思路

1.用一个栈来帮助实现非递归快排;
2.对于下面这组数据,第一次找到基准位置后面,就是红色的方块(5号下标),
3.对于递归是不是就要将左边和右边的在分别进行同样的确定基准位置,那么对于非递归,我们把左边数据的low(0号)下标先入栈,在把high(4号)入栈,对于右边同样把新的low(6)入栈,新的high(9)入栈;
4.接下来先判断栈是否为空,如果非空,就将栈顶出来赋值给high,第二个出来的给low,同样进行找位置,然后进栈,出栈,直到栈为空,那么于也就排好了;

在这里插入图片描述

//非递归实现快速排序(需要一个栈)
    public static void quicksort1(int[] arr){
    
    
        Norquick(arr,0,arr.length-1);

    }
    //非递归实现快速排序
    public static void Norquick(int[] arr,int low,int high){
    
    
        Stack<Integer> stack = new Stack<>();
        int par = parttion(arr,low,high);
        if (par > low+1){
    
    
            stack.push(low);
            stack.push(par-1);
        }
        if (par < high-1){
    
    
            stack.push(par+1);
            stack.push(high);
        }
        while(!stack.empty()){
    
    
            int end = stack.pop();
            int start = stack.pop();
            par = parttion(arr,start,end);
            if (par > start+1){
    
    
                stack.push(start);
                stack.push(par-1);
            }
            if (par < end-1){
    
    
                stack.push(par+1);
                stack.push(end);
            }
        }
    }

3.归并排序

  • 如下图:先分割,在合并;
    在这里插入图片描述
//归并排序
    public static void mergesort(int[] arr){
    
    
        mergeSortInternal(arr,0,arr.length-1);
    }
    //分割
    public static void mergeSortInternal(int[] arr,int low,int high){
    
    
        if(low >= high){
    
    
            return;
        }
        int mid = (low + high)/2;
        mergeSortInternal(arr,low,mid);
        mergeSortInternal(arr,mid+1,high);
        //分割完成,就开始合并

        merge(arr,low,high,mid);
    }
    //合并方法
    public static void merge(int[] arr,int low,int high,int mid){
    
    
        int s1 = low;
        int s2 = mid+1;
        int[] tmp = new int[high-low+1];//临时存放合并后的数据
        //开始合并
        int k = 0;//tmp开始下标
        while(s1 <= mid && s2 <= high){
    
    //俩个段都有数据
            if (arr[s1] <= arr[s2]){
    
    
                tmp[k++] = arr[s1++];

            }else{
    
    
                tmp[k++] = arr[s2++];
            }
        }
        //第一个归并段还有很多数据
        while(s1 <= mid){
    
    //第一个还有若干个数据
            tmp[k++] = arr[s1++];
        }
        while(s2 <= high){
    
    //第二个还有若干个数据
            tmp[k++] = arr[s2++];
        }
        //此时就有序了
        for (int i = 0;i < tmp.length;i++){
    
    
            arr[low+i] = tmp[i];//将临时存放好的数据给人家放回去;
        }
    }

猜你喜欢

转载自blog.csdn.net/qq_45665172/article/details/109678230