排序算法-快速排序

        快速排序运用了递归的思想,通过选取一个点pivot,将比它小的数放在左边,比它大的数放在右边;这样就将原来的数组切分成比pivot小的左子树和比pivot大的右子树组;再对两个子数组进行一样的操作。

        常见的算法会直接选择左值来作为pivot点。当数组本身为有序数组时,每一个元素都会与左值比较,但都不会交换,比较次数达到N^{2}/2,这是最坏的情况。这里用三数中值分隔解决这个问题:取三个元素,将大小居中的元素作为pivot点。

cpp:

#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;

#define cutoff 3

void swap(vector<int> &nums, int i, int j)
{
    
    int temp = nums[i];
    nums[i] = nums[j];
    nums[j] = temp;
}

int median3(vector<int> &nums, int left, int right)
{
    // 三数中值分隔
    int center = (left + right) / 2;

    if (nums[left] > nums[center])
    {
        swap(nums, left, center);
    }
    if (nums[left] > nums[right])
    {
        swap(nums, left, right);
    }
    if (nums[center] > nums[right])
    {
        swap(nums, center, right);
    }
    // nums[left] <= nums[center] <= nums[right]
    swap(nums, center, right - 1);
    // nums[right - 1] <= nums[right],隐藏 pivot
    return nums[right - 1];
}

void quick_median(vector<int> &nums, int left, int right)
{
    int i, j, pivot;
    if ((left + cutoff) < right)
    {
        pivot = median3(nums, left, right);
        i = left;
        j = right - 1;
        for (;;)
        {
            // left 和 right - 1都不用和pivot比较
            while (nums[--j] > pivot)
            {
            }
            while (nums[++i] < pivot)
            {
            }
            if (i < j)
            {
                swap(nums, i, j);
            }
            else
            {
                break;
            }
        }
        // left~right-1 都已经排序好 left~i-1小于等于pivot  其余大于pivot 将
        swap(nums, i, right - 1);
        quick_median(nums, left, i - 1);
        quick_median(nums, i + 1, right);
    }
    else
    {
        for (int i = left; i <= right; i++)
        {
            int temp = nums[i];
            int j = i - 1;
            for (j; j >= 0 && nums[j] > temp; j--)
            {
                nums[j + 1] = nums[j];
            }
            nums[j + 1] = temp;
        }
    }
}

int devision(vector<int> &nums, int left, int right)
{
    // left 为pivot 的写法,当它遇到有序排列的数组时是一种糟糕的选择
    int base = nums[left];
    while (left < right)
    {
        // 右边的数都大于base

        while (right > left && nums[right] >= base)
        {
            right--;
        }
        nums[left] = nums[right];
        // 左边的数都小于base
        while (left < right && nums[left] < base)
        {
            left++;
        }
        nums[right] = nums[left];
    }
    // 此时的left==right,将base存入
    nums[left] = base;
    return left;
}

void quick(vector<int> &nums, int left, int right)
{
    if (left < right)
    {
        int base = devision(nums, left, right);
        quick(nums, left, base);
        quick(nums, base + 1, right);
    }
}

void quicksort(vector<int> &nums)
{
    int N = nums.size();
    // quick(nums,0,N - 1);
    quick_median(nums, 0, N - 1);
}

int main()
{
    vector<int> nums;
    srand((unsigned int)(time(NULL)));
    for (int i = 0; i < 11; i++)
    {
        nums.push_back(rand() % 100);
        cout << nums[i] << " ";
    }
    cout << endl;
    quicksort(nums);
    for (int i = 0; i < 11; i++)
    {
        cout << nums[i] << " ";
    }
    cout << endl;
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值