快速排序运用了递归的思想,通过选取一个点pivot,将比它小的数放在左边,比它大的数放在右边;这样就将原来的数组切分成比pivot小的左子树和比pivot大的右子树组;再对两个子数组进行一样的操作。
常见的算法会直接选择左值来作为pivot点。当数组本身为有序数组时,每一个元素都会与左值比较,但都不会交换,比较次数达到,这是最坏的情况。这里用三数中值分隔解决这个问题:取三个元素,将大小居中的元素作为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;
}