算法 快速排序(随机性优化)

算法 快速排序

@author:Jingdai
@date:2020.10.28

今天刷 LeetCode,发现以前学的快排又忘记了,现记录一下,希望以后不会再忘了。

简介

快排,即快速排序。嗯,没啥说的,直接看思路吧。

思路

思路一句话概括就是确定数组中一个数 pivot ,然后将小于它的数全部放在它左边,把大于它的数全部放在它右边。然后递归对它左边的子数组和右边的子数组调用同样的算法即可完成排序,看下面的代码片段。

public static void quickSort(int[] array, int left, int right) {
     
     
    
    if (left >= right) {
     
     
        return;
    }

    int pivot = positionAndGetPivot(array, left, right);
    quickSort(array, left, pivot - 1);
    quickSort(array, pivot + 1, right);
}

看上面的代码就会发现,其实主要的问题就是选取一个 pivot ,并将小于它的数放其左边,大于其的数放其右边。那选择哪个数作为 pivot 呢?为简单起见,这里先选择数组最左边的数作为 pivot ,然后用两个指针变量 leftright 记录数组的最左边下标和最右边下标。如图,先从右边找一个比 pivot 上数小的数,将它移到左边,然后从左边找一个比 pivot 上数大的数,将它移到右边,一直循环直到 left 等于 right 。然后将 pivot 的值放入 left 的位置上即可(此时 leftright 相等)。其实整个过程有点像交换两个变量值的算法,需要利用一个中间变量,只是这里用一个变量记录 pivot 上的值,然后从右找一个数放它的位置上,右边那个位置又可以放其他数了,然后从左边找一个数放右边,一直到 leftright 相等,然后将原来中间变量即记录的 pivot 的值放在这个位置上。

在这里插入图片描述

看下面的代码片段。

public static int positionAndGetPivot(int[] array, int left, int right) {
     
     
    int pivotValue = array[left];
    while (left < right) {
     
     
        while (left < right && array[right] >= pivotValue) {
     
     
            right --;
        }
        array[left] = array[right];
        while (left < right && array[left] <= pivotValue) {
     
     
            left ++;
        }
        array[right] = array[left];
    }
    array[left] = pivotValue;
    return left;
}

但是上面代码还有一点点问题,当数组中的数的随机性不好时,快排的效率不是很理想,这里我们可以手动引入随机性。上面每次选择数组中最左边的数作为 pivot ,我们可以随机选择 pivot ,这样就可以防止因为数组随机性不足导致的效率问题。做法很简单,在 leftright 中随机选择一个下标作为 pivot ,然后将选择的数与 array[left] 交换就好了,看下面的代码片段。

public static int positionAndGetPivot(int[] array, int left, int right) {
     
     

    Random r = new Random();
    int pivotIndex = r.nextInt(right - left + 1) + left;
    int pivotValue = array[pivotIndex];
    array[pivotIndex] = array[left];

    while (left < right) {
     
     
        while (left < right && array[right] >= pivotValue) {
     
     
            right --;
        }
        array[left] = array[right];
        while (left < right && array[left] <= pivotValue) {
     
     
            left ++;
        }
        array[right] = array[left];
    }
    array[left] = pivotValue;
    return left;
}

完成 pivot 位置选取的函数后,然后递归调用这个算法就可以完成快排了。完整代码如下。

代码

public static void main(String[] args){
     
     

    int[] array = {
     
     4, 5, 9, 2, 1, 4, 1, 3, 5, 6, 7};
    quickSort(array);
    System.out.println(Arrays.toString(array));

}

public static void quickSort(int[] array) {
     
     
    quickSort(array, 0, array.length-1);
}

public static void quickSort(int[] array, int left, int right) {
     
     

    if (left >= right) {
     
     
        return;
    }

    int pivot = positionAndGetPivot(array, left, right);
    quickSort(array, left, pivot - 1);
    quickSort(array, pivot + 1, right);
}

public static int positionAndGetPivot(int[] array, int left, int right) {
     
     

    Random r = new Random();
    int pivotIndex = r.nextInt(right - left + 1) + left;
    int pivotValue = array[pivotIndex];
    array[pivotIndex] = array[left];

    while (left < right) {
     
     
        while (left < right && array[right] >= pivotValue) {
     
     
            right --;
        }
        array[left] = array[right];
        while (left < right && array[left] <= pivotValue) {
     
     
            left ++;
        }
        array[right] = array[left];
    }
    array[left] = pivotValue;
    return left;
}

猜你喜欢

转载自blog.csdn.net/qq_41512783/article/details/109326468