zoukankan      html  css  js  c++  java
  • 不止数据结构——快速排序(Java)

     

    快速排序

      众所周知,快速排序是一个非常常用并且效率很高的排序算法,也是面试中经常问到的算法。本文介绍了快速排序的详细过程,内容比较紧凑,同时也很直观,相信看过之后会有收获。

    算法思想

      在数组内部进行排序,每次确定一个数的位置。以递增次序为例,每次移动一个数,使得它前面的数都比他小,后面的数都比它大(为了方便理解,假设数组没有相等的元素),而前半部分和后半部分内部的次序是不确定的。该过程如图所示:

      将x移动后要保证B部分都比x小,C部分都比x大,这样就确定了x最后的位置。要完成整个数组的排序只要将B部分和C部分做同样的操作。

      一直进行下去,直到某一次B部分和C部分都只有一个元素为止,这样就完成了整个数组的排序。这是一个典型的分治思想,将整个数组的排序分解成部分排序的子问题,每次只需要找到一个元素的确定位置,再将其他的部分做同样的操作。

      那么算法的重点实际上是如何确定x的位置,使得B部分都小于x,C部分都大于x。实现的方法如下所示。

    每次将待排序数组的第一个元素设定为基准元素x。
    1. 初始化两个指针i和j,i指向第二个元素,j指向最后一个元素。i遍历过的数最后都比x小,j遍历过的数最后都比x大
    2. i向右移动直到找到一个大于x的数
    3. j向左移动直到找到一个小于x的数
    4. 交换i和j所指元素的位置(这样就保证了i遍历过的都比x小,j遍历过的都比x大)
    重复2,3,4步,直到j<i,跳出循环。
    循环结束之后将x元素和j指向的元素交换位置,这样就确定了x的位置。
    复制代码
    1. 初始化指针。
    1. i向右移动找到一个大于x的数。
    2. j向左移动找到一个小于x的数。
    1. 交换i和j指向元素的位置。交换过后的状态就还是i经过的元素都比x小,j经过的元素都比x大。
    1. 重复2,3,4步骤,直到i<j,这是后必定会停下来,因为j一旦在i的左边,j指向的元素肯定小于x,符合j停止的条件,i同理。
    1. 交换j指向元素和x的位置,这样就保证了x左边的元素都比x小,x右边的元素都比j大。

      至此,就确定了一个元素的位置。我们这里忽略掉了数组内有重复元素的情况,在编写代码时还有很多的边界情况需要考虑。

    Java实现

      这里的实现只放出了找到x位置并返回的代码,这也是快速排序最关键的部分,有了这部分代码,实现完整的排序就很简单了。这里考虑了众多边界情况,请仔细看注释。该部分建议大家可以背下来,这部分代码可以适用于很多编程题。

    // 该方法用于找到x的位置并返回
    // low,high参数表示要操作的区域(直接在待排序数组内部操作);nums参数就是整个待排序数组。
    // 返回值是x的下标,方法执行之后[low,x)部分都比x小,(x,high]部分都比x大。
    public static int partion(int low, int high, int[] nums) {
        // 如果low不比high小,则该部分不需要排序
        if (low >= high) return -1;
        // if (low > high) return -1;
        // if (low == high) return low;
        int pivot = nums[low]; // 记录x的值,这里用pivot变量表示
        int i = low; // 因为下面的循环体内是以++i开始的,所以这里i=low而不是i=low+1
        int j = high + 1; // 同理,j=high+1而不是high
        while (true) {
            // i不超过上界的前提下一直往右移动,直到找到一个数大于或者等于x,这里表示等于的情况也要交换位置。
            while (++i < high && nums[i] < pivot);
            // 与i同理
            while (--j > low && nums[j] > pivot);
            /*
            有两种情况会出现i==j,第一种是所有的元素都小于x,这样i会移动到最后,j一开始便跳出循环,这时已经可以确定x的位置就在最右边了。另一种情况是当i和j相遇在一个等于x的元素位置时,这时也确定了x的位置。所以这里设定当i>=j时就确定了x的位置应该在j处。这样的话实际上是保证了x左边的元素小于等于x,右边的大于等于x。
            */
            if (i >= j) break;
            // ij还没有相遇时交换ij所指元素的位置
           	int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
        // 确定了x的位置为j后交换元素位置
        nums[low] = nums[j];
        nums[j] = pivot;
        // 将x的位置返回
        return j;
    }
    复制代码

    完整代码

    public static int partion(int low, int high, int[] nums) {
        if (low >= high) return -1;
        int i = low;
        int j = high + 1;
        int pivot = nums[low];
        while (true) {
            while(++i < high && nums[i] < pivot);
            while(--j > low && nums[j] > pivot);
            if (j <= i) break;
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
        nums[low] = nums[j];
        nums[j] = pivot;
        return j;
    }
    // 实际的排序方法
    public static void sort(int low, int high, int[] nums) {
        int index = partion(low, high, nums);
        if (index == -1) return;
        sort(low, index - 1, nums);
        sort(index + 1, high, nums);
    }
  • 相关阅读:
    Hard Rock
    Codeforces Round #416 (Div. 2) B. Vladik and Complicated Book
    codeforces 793B. Igor and his way to work
    codeforces 1B Spreadsheets
    HDU 1069 Monkey and Banana
    codeforces 2B The least round way
    【机器学习】 通俗说拟合
    python-八皇后问题
    python-核心知识思维导图
    python-@property 属性
  • 原文地址:https://www.cnblogs.com/mczhou2/p/13023451.html
Copyright © 2011-2022 走看看