Java basics-merge sort, non-recursive quick sort

1. Recursive quick sort optimization

  • The first optimization idea :

1. First of all, quick sorting is for a large amount of data such as ten thousand as the unit of measurement, then the time complexity and space complexity of quick sorting are the best compared to other sorts, then for a small amount of data such as 10, 100 , Quick sort is obviously not the best;
2. Then quick sort every time after looking for a benchmark, so that the data is slowly tending to order, this time when the data between low and high is less than a given value When, for example, 100, we can call between insert sort to sort;

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;
        }
    }
   
  • The second optimization :

1. For example, for the group of data {1, 2, 3, 4, 5}, each time the data with the subscript 0 on the left is taken as the reference, each time the reference position is determined, there will be extreme situations, and the data is all in the reference to the right, then to the position of benchmarking, we think that after determining each, left and right have a good baseline data, or in extreme cases appear good sort, it is clear that both sides have a good time situation;
2. so how In order to ensure that there are data on both sides of each benchmark, we take the leftmost low and the rightmost high every time, and the middle subscript mid=(high+low)/2. These three subscripts correspond to the median of the data. , That is (arr[mid] <arr[low] <arr[high]), the last low subscript is the median. No matter which position is found in these three positions, you only need to compare it with the low position Exchange, then low will always put this median;

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);
        }
    }
  • All code for both optimizations
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. Non-recursive quick sort

  • Ideas :

1. Use a stack to help achieve non-recursive fast sorting;
2. For the following set of data, after the reference position is found for the first time, there is a red square (subscript No. 5),
3. For recursion, should the left be left? Perform the same determination of the reference position with the one on the right. Then for non-recursion, we put the low (No. 0) subscript of the data on the left into the stack first, put high (No. 4) into the stack, and put the new low ( 6) Push the stack, and push the new high(9) into the stack;
4. Next, first judge whether the stack is empty. If it is not empty, assign the top of the stack to high, and the second one to low, and also find the position , And then push into the stack, pop out of the stack, until the stack is empty, then it will be arranged;

Insert picture description here

//非递归实现快速排序(需要一个栈)
    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. Merge sort

  • As shown in the figure below: split first, then merge;
    Insert picture description here
//归并排序
    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];//将临时存放好的数据给人家放回去;
        }
    }

Guess you like

Origin blog.csdn.net/qq_45665172/article/details/109678230