快速排序
快速排序接近二分查找;时间效率为O(NlogN)-O(N^2);
快速排序的效率依赖于key值
快速排序算法:
快速排序是冒泡排序的一种改进,那可以先选定一个值,然后扫描待排序序列,把小于该值的记录和大于该值的记录分成两个单独的序列,然后分别对这两个序列进行上述操作。我们把选定的那个值称为枢纽值(key),如果枢纽值为序列中的最大值,那么一趟快速排序就变成了一趟冒泡排序。
快速排序使用分治法来把一个区间分为两个区间。
递归地把小于基准值元素key的子数列和大于基准值元素的子数列排序。
递归的最底部情形,是数列的大小是零或一,也就是永远都已经被排序好了。虽然一直递归下去,但是这个算法总会退出,因为在每次的迭代中,它至少会把一个元素摆到它最后的位置去。
函数简介:
函数PartionSort()版本一:递归;
函数PartionSort1()版本二:挖坑法;
函数PartionSort2()版本三:指针prev/cur;
快速排序的优化:
函数GetMidIndex()优化一:三树取中法(三平均分区),优化了函数函数PartionSort();
函数InsertSort()优化二:根据分区大小调整算法;当递归到接近有序时,用插入排序,提高效率;优化了函数QuickSort();
函数QuickSort_Non():处理桟溢出的问题,当有许多数时将左右区间下标压桟;用桟实现非递归。
函数QuickSort():实现递归,单趟排序,分为三部分;去调用函数PartionSort(),或者函数PartionSort1(),或者函数PartionSort2();
代码如下:
<span style="font-size:18px;">#include<iostream>
#include<assert.h>
using namespace std;
void Print(int* arr, int len)
{
if (arr == NULL && len <= 0)
return;
for (int i = 0; i < len; ++i)
{
cout << arr[i] << " ";
}
cout << endl;
}
#include<stack>
//处理桟溢出的问题
//函数声明,实现在下方
int PartionSort(int* array, int left, int right);
void QuickSort_Non(int* arr,int left,int right)
{
//assert(arr);
stack<int> s;
s.push(right);
s.push(left);
while (!s.empty())
{
int left = s.top();
s.pop();
int right = s.top();
s.pop();
int index = PartionSort(arr, left, right);
if (index == -1)
continue;
if (left < index - 1)
{
s.push(index - 1);
s.push(left);
}
if (index + 1 < right)
{
s.push(right);
s.push(index + 1);
}
}
}
//快速排序的优化:三树取中法
int GetMidIndex(int* arr, int left, int right)
{
assert(arr);
int mid = left + (right - left) / 2;
if (arr[left] < arr[mid])
{
if (arr[mid] < arr[right])
return mid;
else if (arr[left] < arr[right])
return right;
else
return left;
}
else
{
if (arr[left] < arr[right])
return left;
else if (arr[mid] < arr[right])
return right;
else
return mid;
}
}
//指针prev/cur
int PartionSort2(int* arr, int left, int right)
{
assert(arr);
int prev = left - 1;
int cur = left;
int key = arr[right];
while (cur < right)
{
//cur找小,停下来与++prev交换数据,否则cur一直走
if (arr[cur] < key && ++prev != cur)
swap(arr[prev], arr[cur]);
++cur;
}
swap(arr[++prev], arr[right]);
//返回正确位置上的值
return prev;
}
//快速排序挖坑法
int PartionSort1(int* arr, int left, int right)
{
assert(arr);
int begin = left;
int end = right;
int key = arr[begin];
while (begin < end)
{
while (begin < end && arr[end] >= key)
--end;
if (begin < end)
arr[begin++] = arr[end];
while (begin < end && arr[begin] <= key)
++begin;
if (begin < end)
arr[end--] = arr[begin];
}
arr[begin] = key;
return begin;
}
//函数声明,实现在下方
void InsertSort(int* arr, int len);
//key,递归
int PartionSort(int* arr, int left, int right)
{
assert(arr);
int begin = left;
int end = right - 1;
快速排序的优化1:三树取中法
int midIndex = GetMidIndex(arr, left, right);
if (midIndex != right)
swap(arr[midIndex], arr[right]);
//关键字key的值
int key = arr[right];
while (begin < end)
{
// 找大 =为了判断多个5的情况
while (begin < end && arr[begin] <= key)
++begin;
// 找小 =为了判断多个5的情况
while (begin < end && arr[end] >= key)
--end;
//小的数换到前面,大的数换在后面
if (begin < end)
swap(arr[begin], arr[end]);
}
//begin与end相遇,用key去交换相遇处的值
//一般情况,If是解决俩个数时的情况,eg:3,4
if (arr[begin] > key)
swap(arr[begin], arr[right]);
//逆序时的情况
else
begin = right;
//返回正确位置上的值
return begin;
}
//快速排序依赖于key的值,当key为最大或者最小时,快排的时间效率为O(N^2);
void QuickSort(int* arr,int left,int right)
{
assert(arr);
//递归返回条件
if (left >= right)
return;
//优化快速排序2:当递归到接近有序时,用插入排序,提高效率
if (right - left < 16)
{
InsertSort(arr + left, right - left + 1);
return;
}
//1.递归
int div = PartionSort(arr, left, right);
//2.挖坑填坑法
//int div = PartionSort1(arr, left, right);
//3.快慢指针prev/cur
//int div = PartionSort2(arr, left, right);
//递归左区间
if (left < div)
QuickSort(arr, left, div - 1);
//递归右区间
if (div < right)
QuickSort(arr, div + 1, right);
}
//直接插入排序
void InsertSort(int* arr,int len)
{
if (arr == NULL && len <= 0)
return;
for (int i = 0; i < len - 1; ++i)
{
int end = i;
int cur = arr[end + 1]; //待插入的数据
// 挪动数据
while (end >= 0 && arr[end] > cur)
{
arr[end + 1] = arr[end];
--end;
}
arr[end + 1] = cur;
}
}
//测试用例
//递归测试
void TestQuickSort()
{
int array[] = { 2, 9, 5, 8, 3, 6, 1, 7, 4, 0 };
QuickSort(array, 0, 9);
Print(array, 10);
int array1[] = { 3, 4 };
QuickSort(array1, 0, 1);
Print(array1, 2);
int array2[] = { 5, 9, 5, 8, 3, 6, 1, 5, 4, 5 };
QuickSort(array2, 0, 9);
Print(array2, 10);
int array3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
QuickSort(array3, 0, 9);
Print(array3, 10);
int array4[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
QuickSort(array4, 0, 9);
Print(array4, 10);
}
//非递归测试
void TestQuickSort_Non()
{
int array[] = { 2, 9, 5, 8, 3, 6, 1, 7, 4, 0 };
QuickSort_Non(array, 0, 9);
Print(array, 10);
int array1[] = { 3, 4 };
QuickSort_Non(array1, 0, 1);
Print(array1, 2);
int array2[] = { 5, 9, 5, 8, 3, 6, 1, 5, 4, 5 };
QuickSort_Non(array2, 0, 9);
Print(array2, 10);
int array3[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
QuickSort_Non(array3, 0, 9);
Print(array3, 10);
int array4[] = { 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };
QuickSort_Non(array4, 0, 9);
Print(array4, 10);
}
</span>