快速排序

快速排序算法的核心思想是:

在待排序序列中选择一个分割元素,将待排序序列中所有比分割元素关键字小或相等的元素移动到分割元素左侧位置,将待排序序列中所有比分割元素大的元素移动到元素右侧位置;

然后将分割元素左侧所有元素看作一个待排序子序列,重复上述过程,直到这些元素完全有序;

最后将分割元素右侧所有元素看作一个待排序子序列,重复上述过程,直到这些元素完全有序。

这里有一个在线演示各种排序的动画http://www.atool.org/sort.php

其实用文字去说明白一个算法的思想是有一定难度的,本文呢主要讲述的是算法的具体实现

思路:

1、 快速排序的核心:就是每次递归都会确定一个元素的最终位置;即分割点的确定
2、 我们首先找到分割点
3、 递归调用分割点左边的子序列
4、 递归调用分割点右边的子序列
5、 递归终止条件:子序列只有一个元素时,直接返回

好了知道了思路我们来实现一下

/**
 *快速排序
 * @param arr 数组
 * @param left 起始下标
 * @param right 结束下标
 */
void quickSort(int arr[] , int left , int right){
    srand(time(NULL));
    //递归终止条件
    if(left >= right){
        return;
    }

    //确定分割点
    int p = _partition(arr , left , right);

    //分割点的位置已经确定,不需要再进行排序
    quickSort(arr , left , p -1);
    quickSort(arr , p + 1 , right);
}
确定分割点

思路
1、 确定分割点的核心:就是我们取arr[left]为分割点, 我们把比arr[left]小的元素移动到arr[left]左边;否则相反
2、 我们先定义两个变量l = left + 1 , r = right ;
3、 我们从 l 下标向后遍历数组,比较arr[left] 和 arr[l] ,如果arr[l] 小于arr[left] , l++;否则,记录下标,停止遍历
4、 我们从 r 下标向前遍历数组,比较arr[left] 和 arr[r] ,如果arr[r] 大于arr[left],r--;否则记录下标,停止遍历
5、 如果l > r , 说明整个数组已经遍历完,而且已经分好
6、 否则:交换arr[l] 和 arr[r] , 更新下标继续3-6
7、 当l > r 跳出循环时,我们需要交换arr[left] 和 arr[r];注:这时 r 指向的是小于arr[left]元素的下标
8、 把 r 返回即可

我们来实现一下

/**
 * 确定分割点
 * @param arr 数组
 * @param left 起始下标
 * @param right 结束下标
 * @return
 */
int _partition(int arr[] , int left , int right){
    swap(arr[left] , arr[ rand() % (right - left + 1) + left] );

    int l = left + 1;
    int r = right;

    int v = arr[left];
    while(true){

        while(arr[l] < v && l <= right){
            l++;
        }
        while(arr[r] > v && r >= (left + 1) ){
            r--;
        }

        if(l > r){
            break;
        }

        swap(arr[l] , arr[r]);
        l++;
        r--;
    }

    swap(arr[left] , arr[r]);
    return r;
}