zoukankan      html  css  js  c++  java
  • 排序——快速排序

    1.选取枢纽元:三数中值分割法,得到的中间值即作为mid,将数组分为arrays[mid]左边的比它小,右边的比它大

    2.进行划分partition:首先将arrays[mid]放在arrays[high]处,然后对数组范围内的数值进行比较,

    (左右两边分别有一个指针来进行寻找,arrays[left] <= arrays[high],arrays[right] >= arrays[high])找到不符合要求的值,在左右交换位置。

    在left>=right时,终止查找,然后将swap(arrays, left, high);即可将枢纽元放入合适的位置

    3.循环进行左右两侧的选择枢纽元,划分

    注意:在partition之后,传回来的是划分好之后arrays[mid]应该在的位置,而不再是mid处了

    排序中的划分部分可以衍生出很多的问题:

    数据结构--荷兰国旗问题

    利用荷兰国旗问题的解法衍生出的随机快排解法

    注意在生成随机数时,是 (int)(Math.random() * (right - left + 1)) + left  

    快排优化:
    * 1.使用荷兰国旗法进行划分
    * 2.使用随机快排:将一直选取最后一个数进行比较的经典快排,改为随机选取一个数进行比较
    * 生成随机数的方法 int num = (int)(Math.Random()*(high - low + 1) + low);
    * 使用空间复杂度O(logN),用来记录各个递归中的断点,用来进行另外一半的递归
    * 工程上快排是非递归的

    public void quickSort(Integer[] arrays){
            if(arrays.length == 0) return;
            randomQuickSort( arrays, 0, arrays.length - 1 );
        }
    
        //随机快排
        public void randomQuickSort(Integer[] arrays, int left, int right){
            if(left >= right) return;
            swap(arrays, left + (int)(Math.random() * (right - left + 1)), right);
            int[] p = partitionRandom(arrays, left, right);
            randomQuickSort( arrays, left, p[0] - 1 );
            randomQuickSort(arrays, p[1] + 1, right);
        }
    
        public int[] partitionRandom(Integer[] arrays, int left, int right){
            int low = left - 1;
            int high = right;
    
            while(left < high){
                if(arrays[left] < arrays[right]){
                    swap(arrays, ++low, left++);
                } else if(arrays[left] > arrays[right]){
                    swap(arrays, --high, left);
                } else {
                    left++;
                }
            }
            swap(arrays, right, high);
    
            return new int[]{low + 1, high};
        }
    

      

    一般的解法

    package sort;
    import static sort.PrintRes.swap;
    /**
     * Created by Skye on 2018/3/27.
     */
    public class QuickSort {
        public void quickSort(Integer[] arrays){
            if(arrays.length == 0) return;
            quickSort( arrays, 0, arrays.length - 1 );
        }
    
        public void quickSort(Integer[] arrays, int low, int high){
            if(low >= high) return;
            int mid = threeMid(arrays, low, high);
            swap(arrays, mid, high);
            int num = partition(arrays, low, high);
            quickSort( arrays, low, num - 1 );
            quickSort(arrays, num + 1, high);
    
        }
    
        public int threeMid(Integer[] arrays, int low, int high){
            int mid = (low + high) / 2;
            if(arrays[low] > arrays[mid]) swap(arrays, low, mid);
            if(arrays[low] > arrays[high]) swap( arrays, low, high );
            if(arrays[mid] > arrays[high]) swap( arrays, mid, high );
            return mid;
        }
    
        public int partition(Integer[] arrays, int low, int high){
            int left = low;
            int right = high - 1;
    
            //把arrays[mid]放到合适的位置
            while(left < right){
                while(left < right && arrays[left] <= arrays[high]) {
                    left++;
                }
                while(right > left && arrays[right] >= arrays[high]) {
                    right--;
                }
                swap(arrays, left, right);
            }
            swap(arrays, left, high);
            return left;
        }
    }
    

      

    注意:可以将交换改成覆盖,来减少交换次数  将partition方法修改

    对于小数组,可以将排序改为插入排序   quickSort(Integer[] arrays, int low, int high)修改

      还可以将递归改成尾迭代:(不太懂)

    最终版

    package sort;
    import static sort.PrintRes.swap;
    public class QuickSort {
        public void quickSort(Integer[] arrays){
            if(arrays.length == 0) return;
            quickSort( arrays, 0, arrays.length - 1 );
        }
        public void quickSort(Integer[] arrays, int left, int right){
            if(left >= right) return;
            if(right - left > 10){
                int mid = threeMid(arrays, left, right);
                swap(arrays, mid, right);
                int num = partition(arrays, left, right);
                quickSort( arrays, left, num - 1 );
                quickSort(arrays, num + 1, right);
            } else{
                for(int i = left + 1; i <= right; i++){
                    int j = i - 1;
                    int temp = arrays[i];
                    for(; j >= left; j--){
                        if(arrays[j] < temp) break;
                        arrays[j + 1] = arrays[j];
                    }
                    arrays[j + 1] = temp;
                }
            }
        }
        public int threeMid(Integer[] arrays, int left, int right){
            int mid = (left + right) / 2;
            if(arrays[left] > arrays[mid]) swap(arrays, left, mid);
            if(arrays[left] > arrays[right]) swap( arrays, left, right );
            if(arrays[mid] > arrays[right]) swap( arrays, mid, right );
            return mid;
        }
        public int partition(Integer[] arrays, int left, int right){
            int low = left;
            int high = right;
            //把arrays[mid]放到合适的位置
            //枢纽元放在最右边,记录枢纽元的值
            int temp = arrays[right];
            while(low < high){
                while(low < high && arrays[low] <= temp) {
                    low++;
                }
                //相当于交换arrays[left] arrays[right],交换后,right-1(开始时,right处放置的是枢纽元的值,就是将枢纽元覆盖掉)
                arrays[high--] = arrays[low];
                while(high > low && arrays[high] >= temp) {
                    high--;
                }
                //相当于交换arrays[left] arrays[right],交换后,left+1(此时,arrays[left]的值已经存放在arrays[right]中了)
                arrays[low++] = arrays[high];
            }
            //最后再将枢纽元放回到数组中
            arrays[low] = temp;
            return low;
        }
    }
    
  • 相关阅读:
    Linux Centos7(Mac) 安装Docker教程
    SpringBoot应用操作Rabbitmq(fanout广播高级操作)
    SpringBoot应用操作Rabbitmq(topic交换器高级操作)
    SpringBoot应用操作Rabbitmq(direct高级操作)
    CCF 字符串匹配(find()函数的使用)
    PKU 1204 Word Puzzles(AC自动机)
    PKU 1932 XYZZY(Floyd+Bellman||Spfa+Floyd)
    PKU 1201 Intervals(差分约束系统+Spfa)
    PKU 2352 Stars(裸一维树状数组)
    PKU 3169 Layout(差分约束系统+Bellman Ford)
  • 原文地址:https://www.cnblogs.com/SkyeAngel/p/8660466.html
Copyright © 2011-2022 走看看