[每日coding]排序算法--快速排序

快速排序的基本思想:分治法。

通过一趟排序将待排记录分隔成独立的两部分,其中一部分记录的关键字均比另一部分的关键字小,则可分别对这两部分记录继续进行排序,以达到整个序列有序。

算法描述

快速排序使用分治法来把一个串(list)分为两个子串(sub-lists)。具体算法描述如下:

  • 从数列中挑出一个元素,称为 “基准”(pivot);
  • 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;
  • 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序。

动图演示

算法分析

时间复杂度: 最佳情况:T(n) = O(nlogn)   最差情况:T(n) = O(n2)   平均情况:T(n) = O(nlogn) 

空间复杂度:O(logn)

稳定性: 不稳定

基于比较的排序

代码实现

挖坑法

1. 先把作为key的抠出来单独放置,key值位置为坑。
2. 从数组尾部开始往前找,找第一个比key小的数字,放在坑里,新坑出现。
3. 从数组头部开始往后找,找第一个比key大的数字,放在坑里,更新坑。
4. 直到前后游标重叠。将key放进最后这个坑里。这就完成了第一趟快排。
5. 对子序列递归执行1~4. 完成了最终的排序。

快慢指针法

针对取最后一个元素作为枢轴的情况:
1、定义变量fast指向序列的开头,定义变量slow的前一个位置。
2、当array[fast] < key时,fast和slow同时往后走,如果array[fast]>key,fast往后走,slow留在大于key的数值前一个位置。
3、当array[fast]再次 < key时,交换array[fast]和array[slow]。

说白了就是,在没找到大于key值前,slow永远紧跟fast,遇到大于枢轴的值,两者之间就会拉开差距,中间差的肯定是连续的大于key的值,当再次遇到小于key的值时,交换两个下标对应的值就好了。

#include
#include

using namespace std;

int quick_sort2(vector& nums, int begin, int end) {
    if (begin >= end) {
        return 0;
    }
    int key = nums[begin];
    int tmp, left = begin, right = begin + 1;
    while (right != end) {
        if(nums[right] < key) {
            left++;
            cout<<"while:  left: " << left << "  nums[left]:" << nums[left] << "  right: " << right << " nums[right]:" << nums[right] << endl;
            tmp = nums[right];
            nums[right] = nums[left];
            nums[left] = tmp;
        }
        right++;
    }
    cout<<"left: " << left << "  nums[left]:" << nums[left] << "  right: " << right << " nums[right]:" << nums[right] << endl;
    tmp = nums[begin];
    nums[begin] = nums[left];
    nums[left] = tmp;

    quick_sort2(nums, begin, left);
    quick_sort2(nums, left + 1, end);

    return 0;
}

int main(int argc, char* argv[]){
    cout << "hello world\n";

//    vector nums{10, 5, 4, -10, 2, 0};
    int a[6] = {10, 5, 4, -10, 2, 0};
    vector nums(a, a+6);
    int i, length = (int)nums.size();
    for(i =0 ; i < length; i++){
        cout << nums[i] << ' ';
    }
    cout << endl;

//    quick_sort(nums, 0, length - 1);
    quick_sort2(nums, 0, length);

    for(i =0 ; i < length; i++){
        cout << nums[i] << ' ';
    }
    cout << endl;
/*    for (auto i:nums){
        cout << i << ' ';
    }
*/
    return 0;
}

左右指针法

基本思路:

1、选取一个关键字(key)作为枢轴,一般取整组记录的第一个数/最后一个为枢轴。
2、设置两个变量left = 0;right = N - 1;
3、从left一直向后走,直到找到一个大于key的值,right从后至前,直至找到一个小于key的值,然后交换这两个数。
4、重复第三步,一直往后找,直到left和right相遇,这时将key放置left的位置即可。

#include
#include

using namespace std;

int quick_sort(vector& nums, int i_begin, int i_end) {
    if(i_begin >= i_end) {
        return 0;
    }
    int key = nums[i_begin];
    int left = i_begin;
    int right = i_end;
    while(left < right) {
        while(left < right && nums[right] >= key) {
            right --;
        }
        if (left < right) {
            cout << "nums[" << left <<"] is " << nums[left] << "; nums[" << right << "] is " << nums[right]< nums{10, 5, 4, -10, 2, 0};
    int a[6] = {10, 5, 4, -10, 2, 0};
    vector nums(a, a+6);
    int i, length = (int)nums.size();
    for(i =0 ; i < length; i++){
        cout << nums[i] << ' ';
    }
    cout << endl;

    quick_sort(nums, 0, length - 1);

    for(i =0 ; i < length; i++){
        cout << nums[i] << ' ';
    }
    cout << endl;
/*    for (auto i:nums){
        cout << i << ' ';
    }
*/
    return 0;
}

 

随机快排

思想:随机选择序列中的一个数作为key值。

 

你可能感兴趣的:(每日coding)