美文网首页
02 算法-初识算法-快速排序

02 算法-初识算法-快速排序

作者: 花神子 | 来源:发表于2019-05-23 11:44 被阅读0次

QuickSort

快速排序

在每一轮挑选一个基准元素,并让其他比它大的元素移动到数列一边,比它小的元素移动到数列的另一边,从而把数列拆解成了两个部分。

这种思路就叫做分治法

每次把数列分成两部分,究竟有什么好处呢?

  • 假如给定8个元素的数列,一般情况下冒泡排序需要比较8轮,每轮把一个元素移动到数列一端,时间复杂度是O(n^2)。在分治法的思想下,原数列在每一轮被拆分成两部分,每一部分在下一轮又分别被拆分成两部分,直到不可再分为止。这样一共需要多少轮呢?平均情况下需要logn轮,因此快速排序算法的平均时间复杂度是 O(nlogn)

基准元素的选择

基准元素,英文pivot,用于在分治过程中以此为中心,把其他元素移动到基准元素的左右两边。

  • 最简单的方式是选择数列的第一个元素:这种选择在绝大多数情况是没有问题的,但是对于一个已经存在顺序的数组这种效果就比较差了;

  • 随机选择一个元素作为基准元素。这样一来,即使在数列完全逆序的情况下,也可以有效地将数列分成两部分。

元素的移动

1.挖坑法

  • 首先,我们选定基准元素Pivot,并记住这个位置index,这个位置相当于一个“坑”。并且设置两个指针left和right,指向数列的最左和最右两个元素: 如下图
  • 从right指针开始,把指针所指向的元素和基准元素做比较。如果比pivot大,则right指针向左移动;如果比pivot小,则把right所指向的元素填入坑中。

第一轮开始
Pivot = 3,left = 0, right = 7

algorithm-Fast-Sort-1.png

第二轮开始
Pivot = 8,left = 3, right = 7

algorithm-Fast-Sort-2.png

第三轮开始
Pivot = 7,left = 3, right = 5

algorithm-Fast-Sort-3.png

1.挖坑法代码实现如下

/**
 *
 *
 * @description
 * @see
 * @author maozhengwei
 * @data 2019-05-23 10:49
 * @version V1.0.0
 **/
public class QuickSort1 {

    public static void quickSort(int[] arr, int startIndex, int endIndex) {
        // 递归结束条件:startIndex大等于endIndex的时候
        if(startIndex >= endIndex) {
            return;
        }
        // 得到基准元素位置
        int pivotIndex = partition(arr, startIndex, endIndex);
        // 用分治法递归数列的两部分
        quickSort(arr, startIndex, pivotIndex - 1);
        quickSort(arr, pivotIndex + 1, endIndex);
}

    private static int partition(int[] arr, int startIndex, int endIndex) {
        // 取第一个位置的元素作为基准元素
        int pivot = arr[startIndex];
        int left = startIndex;
        int right = endIndex;
        // 坑的位置,初始等于pivot的位置
        int index = startIndex;
        //大循环在左右指针重合或者交错时结束
        while ( right >= left  ){
            //right指针从右向左进行比较
            while ( right >= left ) {
                if (arr[right] < pivot) {
                    arr[left] = arr[right];
                    index = right;
                    left++;
                    break;
                }
                right--;
            }
            //left指针从左向右进行比较
            while ( right >= left ) {
                if (arr[left] > pivot) {
                    arr[right] = arr[left];
                    index = left;
                    right--;
                    break;
                }
                left++;
            }
        }
        arr[index] = pivot;
        return index;
}

    public static void main(String[] args) {
        int[] arr = new int[] {4,7,6,5,3,2,8,1};
        quickSort(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
}

2. 指针交换法
指针交换开始都填坑法是一样的,只是元素的交换方式不一样:

  • 从right指针开始,把指针所指向的元素和基准元素做比较。如果大于等于pivot,则指针向移动;如果小于pivot,则right指针停止移动,切换到left指针。

  • 轮到left指针行动,把指针所指向的元素和基准元素做比较。如果小于等于pivot,则指针向移动;如果大于pivot,则left指针停止移动:left和right指向的元素进行交换**。
    下面是图解:

第一轮:


algorithm-Fast-Sort-4.png

第二轮:


algorithm-Fast-Sort-5.png

第三轮:


algorithm-Fast-Sort-6.png

代码实现:

/**
 * 指针交换
 * @see
 * @author mzw
 * @data 2019-05-23 14:42
 * @version V1.0.0
 **/
public class QuickSort2 {

    public static void quickSort2(int[] arr, int startIndex, int endIndex) {
        // 递归结束条件:startIndex大等于endIndex的时候
        if(startIndex >= endIndex) {
            return;
        }
        // 得到基准元素位置
        int pivotIndex = partition(arr, startIndex, endIndex);
        // 根据基准元素,分成两部分递归排序
        quickSort2(arr, startIndex, pivotIndex - 1);
        quickSort2(arr, pivotIndex + 1, endIndex);
    }

    private static int partition(int[] arr, int startIndex, int endIndex) {
        // 取第一个位置的元素作为基准元素
        int pivot = arr[startIndex];
        int left = startIndex;
        int right = endIndex;

        while ( right != left  ){
            //right指针从右向左进行比较,小于则终止循环
            while ( left < right && arr[right] > pivot ) {
                right--;
            }
            //left指针从左向右进行比较,大于则准则循环
            while ( left < right && arr[left] <= pivot ) {
                left++;
            }
            if (left < right) {
                int temp = arr[left];
                arr[left] = arr[right];
                arr[right] = temp;
            }
        }
        //指针重合
        int p = arr[left];
        arr[left] = arr[startIndex];
        arr[startIndex] = p;
        return left;
    }

    public static void main(String[] args) {
        int[] arr = new int[] {4,7,6,5,3,2,8,1};
        quickSort2(arr, 0, arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
}

相关文章

网友评论

      本文标题:02 算法-初识算法-快速排序

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