<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">快速排序是交换排序的一种。其主要过程为:</span>
1.在一组数中选取一个key
2.将大于key的放到一边,小于key的放到另一边
3.分区,重复上两步
快速排序最易理解算法1:
1.将最右边的数选为key
2.begin和end分别为左下标和右下标
3.从begin向后,找到比key大的数停下来;从end向前找,找到比key小的数停下来
4.交换begin和end指向的值
5.从key分区,继续重复过程1、2、3、4。
int partition(int *a, int left, int right)
{
<span style="white-space:pre"> </span>int key = a[right];
<span style="white-space:pre"> </span>int begin = left;
<span style="white-space:pre"> </span>int end = right - 1;
<span style="white-space:pre"> </span>while (begin < end)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>while (a[begin] < key)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>++begin;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>while (begin < end&&a[end]>key)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>--end;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if (begin < end)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>swap(a[begin], a[end]);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>if (a[begin]>a[right])
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>swap(a[begin], a[right]);
<span style="white-space:pre"> </span>return begin;
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>else
<span style="white-space:pre"> </span>return right;
}
void QuickSort(int *a, int left,int right)
{
<span style="white-space:pre"> </span>assert(a);
<span style="white-space:pre"> </span>if (left < right)
<span style="white-space:pre"> </span>{
<span style="white-space:pre"> </span>int div = partition(a, 0, right);
<span style="white-space:pre"> </span>QuickSort(a, 0, div - 1);
<span style="white-space:pre"> </span>QuickSort(a, div + 1, right);
<span style="white-space:pre"> </span>}
}
快速排序优化之挖坑法
1.选取最右边的数a[right]为“坑”,同时选取最右边的数为key,左下标为begin,右下标为end
2.从begin开始找大于key的数,找到后,将这个数填到“坑”中,即a[end],填好后,end--,a[begin]为新"坑"
3.从end向前找比key小的数,找到后,将这个数填到“坑”中,即a[begin],填好后,begin++,a[end]为新“坑”
4.当begin=end时,这个坑就是,a[begin],用key填进去
5.以key为分区,在每个分区重复1、2、3、4
int partition(int *a, int left, int right)
{
int key = a[right];
int begin = left;
int end = right;
while (begin < end)
{
while (begin<end&&a[begin] <= key)
{
begin++;
}
if (begin < end)
{
a[end] = a[begin];
end--;
}
while (begin<end&&a[end]>key)
--end;
if (begin < end)
{
a[begin] = a[end];
begin++;
}
}
a[begin] = key;
return begin;
}
void QuickSort(int *a, int left,int right)
{
assert(a);
if (left < right)
{
int div = partition(a, 0, right);
QuickSort(a, 0, div - 1);
QuickSort(a, div + 1, right);
}
}
优化三数取中法
由于快速排序在key取到接近最大或者接近最小的值时是快速排序的最坏情况,所以,在取key时,比较a[right],a[left],a[mid]的值后,取中间的数作为key时间效率最好
void GetMid(int *a,int left,int right)//将中间的值换到right的位置上
{
if (left<right)
{
int mid = left + ((right - left) >> 1);
if (a[mid] > a[left])//arr[mid]<=a[left]
{
swap(a[mid], a[left]);
}
if (a[right] > a[left])//a[right]<=a[left]
{
swap(a[left], a[right]);
}
if (a[mid]>a[right])//a[mid]<=a[right]
{
swap(a[mid], a[right]);
}
}
return ;
//a[mid]<=a[right]<=a[left]
}
除了三数取中的方法优化外,还有另一种方法:
1.设置一个cur和prev
2.prev始终在cur的前一个或者比key大的前一个
这种方法可以用于链表的快速排序
int partition(int *a, int left, int right)
{
//prev指向cur前一个或者比key大的前一个
int key = a[right];
int prev = left - 1;
int cur = left;
while (cur < right)
{
if (a[cur] <= key&&++prev != cur)
swap(a[prev], a[cur]);
++cur;
}
swap(a[++prev], a[right]);
return prev;
}
void QuickSort(int *a, int left,int right)
{
assert(a);
if (left < right)
{
int div = partition(a, 0, right);
QuickSort(a, 0, div - 1);
QuickSort(a, div + 1, right);
}
}
若遇到很多数的时候想使用快速排序,则先使用快排,当划分的区间较小的时候,使用插入排序
void QuickSort(int *a, int left, int right)
{
if ((right - left) < N)//N表示一个常数
{
InsetSort(a + left, right - left + 1);//插入排序
}
else
{
int div = partition(a, 0, right);//快速排序
QuickSort(a, 0, div - 1);
QuickSort(a, div + 1, right);
}
}
#include<stack>
void QuickSort(int *a, int left, int right)
{
stack<int>s;
s.push(left);
s.push(right);
while (!s.empty())
{
int end = s.top();
s.pop();
int begin = s.top();
s.pop();
int div = partition(a, begin, end);
if (begin < div - 1)
{
s.push(begin);
s.push(div - 1);
}<pre name="code" class="cpp"><span style="white-space:pre"> </span>if (div + 1 < end)
{
s.push(div + 1);
s.push(end);
}
}
}