快速排序

来源:互联网 发布:网络机顶盒和网络电视 编辑:程序博客网 时间:2024/06/07 08:18

快速排序

  快速排序(Quicksort)是对冒泡排序的一种改进。它由C。 A。 R。 Hoare在1962年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

原理

  首先我们观察这样的一个数组 {31425978},这是一个乱序数组,我们观察其中的元素5,发现虽然数组乱序,但是5前面的所有数都比小于等于它,而它后面的所有数都大于等于它,在不考虑数组排序后稳定性的情况下,很容易就知道,在数组排好序的情况下,元素5还是处于这个位置。
  快速排序就是基于以上理论的一个排序方法。对于一个数组,我们先取数组中的一个元素做为基准值,然后把比它小元素的都移到它前面,比它大的元素都移到它后面,这样我们就确定了这个元素在排序之后正确的位置。接下来,对这个元素左边和右边的子数组,进行相同的操作,直到所有的元素都被放在正确的位置上。(递归)

分析

设有长度为 N 的数组 A。
1。 设置两个变量i、j,排序开始的时候分别指向数组最左和最右,即 left = i = 0,right = j = N-1
2。 以最右的数组元素作为关键数据,赋值给key,即key = A[right]
3。 从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于等于key的A[i],将A[i]的值赋给a[j]
4。 从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于等于key的值A[j],将A[j]的值赋给A[i]
5。 重复第3、4步,直到i=j,此时令循环结束,将key的值赋给a[i]
6。从索引i将数组分割成索引left到i-1及索引i+1到right的两个子数组,重复上面1到5步,直到最后left = right。

图解

下图解释了快速排序的一次排序过程

这里写图片描述

代码

void quickSort(int* arr, int left, int right){    if(left < right) {        int i = left, j = right;        //取最后一位为基准值        int pivot = arr[right];        while(i < j) {            while(i < j && arr[i] < pivot) {                i++;            }            if(i < j) {                arr[j--] = arr[i];            }            while(i < j && arr[j] > pivot) {                j--;            }            if(i < j) {                arr[i++] = arr[j];            }        }        arr[i] = pivot;        quickSort(arr, left, i - 1);        quickSort(arr, i + 1, right);    }}

其它方法

上面的方法,每次要先操作左边元素,再操作右边元素,我们可以用交换法,来同时操作一个不大于基准的元素和一个不小于基准的元素,每当i指向一个不小于基准的元素并且j指向一个不大于基准的元素,我们就把a[i]与a[j]交换,这样可以更加高效,代码如下。

void swap(int* a, int* b){    if(a == b)        return;    int temp = *a;    *a = *b;    *b = temp;}void quickSort(int* arr, int left, int right){    if(left < right) {        int i = left, j = right - 1;        //取最后一位为基准值        int pivot = arr[right];        while(i <= j) {            while(i <= j && arr[i] < pivot) {                i++;            }            while(i <= j && arr[j] > pivot) {                j--;            }            if(i <= j) {                swap(arr + i, arr + j);                i++;                j--;            }        }        swap(arr + i, arr + right);        quickSort(arr, left, i - 1);        quickSort(arr, i + 1, right);    }}

还有很多种其它的快速排序方法,这里就不一一赘述了。比如以上两种方法都是ij从左右两边分别向内移动的的,还有ij都从左或者从右向另一个方向移动的方法。还有关于基准值的选择,上面两个代码也是用了最不可取的方法,取了最左或最右的值,一个比较好的方法是取最左,最右和中间数三者之间的中值。

PS

  上面两个代码中,i和j停下来的条件都是指向了不小于或者不大于基准的值,相等也是包含在里面的,这样做一个好处是防止了递归只发生在数组的一边。

  另外,之前看到有人在群里求助,说面试的时候碰到一首题给定一个数组,让选第一次快速排序之后数组的顺序…我就觉得这样的题特别没意义,快排根本没有固定的写法,你用不同的方法,第一次排序之后得到的数组顺序肯定不会是相同的,即使你选的是相同的基准值。

原创粉丝点击