美文网首页
入门算法:三路快速排序

入门算法:三路快速排序

作者: 半理想主义 | 来源:发表于2020-08-26 17:26 被阅读0次

    上手难度:★★★★

    算法复杂度:O(nlogn)

    排序思想:

    预先设定三个空间
    l为最左边的索引
    初始值lt=l, gt=r+1, i = l + 1
    arr[l+1~lt) 存放的是小于v的值
    arr[l+1 ~ i)存放的是等于v的值
    arr[gt~r]存放的是大于v的值
    初始的时候这三个区间都为空
    进入while(i < gt)的循环
    当arr[i]<v时,将i和lt+1的值交换位置,同时i和lt向右移动,i移动是为了比较下一个值,lt移动是因为左边的区间多了一个值
    当arr[i]>v时,将i和gt-1的值交换位置,gt向左移动,i不变,因为交换来的值还未判断,所以i不动
    当arr[i]=v时,不做交换操作,i继续向右移动
    循环完成后,lt到gt之间的值就不需要再排序了,然后将继续切分小于v的区间和大于v的区间即可

    代码实现:

    public class QuickSort3 {
    
        private static Random random = new Random();
    
        private static int rand(int l, int r){
            return random.nextInt(r - l + 1);
        }
    
        /**
         * 交换数组中两个元素的位置
         */
        private static void swap(int[] arr, int x, int y){
            if(x < 0 || y < 0 || x > arr.length || y > arr.length){
                return;
            }
            int temp = arr[x];
            arr[x] = arr[y];
            arr[y] = temp;
        }
    
        /**
         * 对ar[l...r]部分进行快速排序
         */
        public static void quickSort(int[] arr, int l, int r){
            if(l >= r){
                return;
            }
    
            swap(arr,  l, l + rand(l, r));
    
            int v = arr[l];
    
            int lt = l;
            // 索引对应arr[l+1...lt) < v
            int gt = r + 1;
            // 索引对应arr[gt...r] > v
            int i = l + 1;
            // 索引对应arr[lt+1...i) = v 在初始情况下,这些区间都是空的,符合逻辑,首先假设有这样的数组空间了,
            //随着lt、gt、i的变动以及交换位置,就可以把这三个区间确定下来
    
            //当i移动到从右往左数 最后一个大于v的值的位置时,就不用循环了
            while(i < gt){
                if(arr[i] < v){
                    //当i索引的值小于v,就将其与lt+1的值调换位置,同时i继续往右移动,lt因为多了一个值,也要往右移动
                    //lt+1的值之前已经判断过了,因此不需要再处理,直接将i移动
                    swap(arr, i, lt + 1);
                    i++;
                    lt++;
                }else if(arr[i] > v){
                    //当i索引的值大于v,就将其与gt-1的值调换位置,将大于v的值放到gt区间
                    //然后继续判断调换过来的值,因此i不用移动,gt因为多了一个值,所以要往左移动
                    swap(arr, i, gt - 1);
                    gt--;
                }else{
                    i++;
                }
            }
            //l对应的值就是v,lt对应的是最后一个小于v的值,交换后,v就放在了合适的位置,即v的左边小于v,右边大于等于v
            swap(arr, l, lt);
    
            //注意:这里返回p,之后,只是说满足arr[l+1...j] < v; arr[j+1...i) > v
            //并不是说p的左边一定有数组,或者p的右边一定有数组,也可能是空
            quickSort(arr, l, lt - 1);
            //以p为中间点,再进行快速排序
            quickSort(arr, gt, r);
        }
    
        public static void main(String[] args) {
    
            int[] arr = {3, 44, 38, 5, 47, 15, 36, 26, 27, 2, 46, 4, 19, 50, 48};
    
            quickSort(arr, 0, arr.length - 1);
    
            for( int i = 0 ; i < arr.length ; i ++ ){
                System.out.print(arr[i]);
                System.out.print(' ');
            }
    
        }
    }
    

    优点:

    不需要对大量等于v的元素重复操作,在包含大量相同元素时,三路排序最有效率
    另外快速排序在 取出数组中第n大的元素这类问题效率很高,算法复杂度为O(n),因为快速排序的过程每一次都是找到一个标定点,然后将标定点挪到数组中合适的位置,这个合适的位置就是数组排好序后最终所处的位置,所以第n大元素,就是第n个位置的元素

    相关文章

      网友评论

          本文标题:入门算法:三路快速排序

          本文链接:https://www.haomeiwen.com/subject/yvlfsktx.html