快速排序
快速排序,纵观各类技术博客,关于快速排序,方法很多,各有千秋,但是,我拙见:
快速排序需要用递归,二分,分治的思想去操作,那么在这其中,就需要找一个基准,通过这个基准,把序列分开,达到可以用分治的思想取解决的目的;
能看到这里的,基本对快排都有个了解,不多说,盗了几个图看看,更方便记忆:
动态图只能理解个意思,主要还是理解第一张图,说的很明白了,结合代码,分析:
#pragma once
//方法一:
void swap(int* a, int left, int right)
{
int temp = a[left];
a[left] = a[right];
a[right] = temp;
}
int partitionNumOne(int* a, int left, int right)
{
//The selected benchmark example :left
int markKey = a[left];
int mark = left;
while (left < right)
{
while (left < right && a[right] >= markKey)
right--;
while (left < right && a[left] <= markKey)
left++;
swap(a, left, right);
}
swap(a,mark,left);
return left; //or right because left == right
}
void QuickSortNumOne(int* a, int left, int right)
{
if (left >= right)
return;
int position = partitionNumOne(a, left, right);
QuickSortNumOne(a, left, position - 1);
QuickSortNumOne(a, position + 1, right);
}
void SortNumOne(int* a,int size)
{
assert(a);
QuickSortNumOne(a, 0, size - 1);
}
//方法二:
int part(int* a, int left, int right)
{
int markKey = a[left];
while (left < right)
{
while (left < right && a[right] >= markKey)
right--;
a[left] = a[right]; //小的直接覆盖左边
while (left < right && a[left] <= markKey)
left++;
a[right] = a[left];
}
a[left] = markKey;
return left;
}
void QuickSortNumTwo(int* a, int left, int right)
{
if (left >= right)
return;
int pos = part(a,left,right);
QuickSortNumTwo(a,left,pos-1);
QuickSortNumTwo(a,pos+1,right);
}
void SortNumTwo(int* a, int size)
{
assert(a);
QuickSortNumTwo(a,0,size-1);
}
//方法三:
//计算中间那个位置 一边都大于他 一边都小于他
int Partition(int *a, int left, int right)
{
int key = a[right];
int begin = left;
int end = right - 1;
while (begin < end)
{
//key是自己选
while (a[begin] < key && begin < end) //也就是说 key左边的都比key小 右边的都比key大
{
++begin;
}
while (a[end] > key && end > begin)//处理右边
{
--end;
}
//但凡上边任何一个循环跳出来,都是因为遇到条件 下面判断
if (begin < end)
{
swap(a[begin], a[end]);
}
}
if (a[begin] < key)
{
return right;
}
else
{
swap(a[begin], a[right]);
return begin;
}
}
void QuickSortOne(int *a, int left, int right)
{
assert(a);
if (left <= right)
{
int tmp = Partition(a, left, right); //单趟排序
QuickSortOne(a, left, tmp - 1);
QuickSortOne(a, tmp + 1, right);
}
}
//方法四:
void QsortMedianOfThree(int* a, int low, int high)
{
if (low >= high) return; //递归出口
PartitionMedianOfThree(a, low, high); //三数取中
int partition = Partition(a, low, high); //将 >= x 的元素交换到右边区域,将 <= x 的元素交换到左边区域
QsortMedianOfThree(a, low, partition - 1);
QsortMedianOfThree(a, partition + 1, high);
}
// 三数取中确定基准元,将确定好的基准元与第一个数交换,无返回值
void PartitionMedianOfThree(int* a, int low, int high)
{
int mid = low + (high + -low) / 2;
if (a[mid] > a[high])
{
swap(a, mid, high);
}
if (a[low] > a[high])
{
swap(a, low, high);
}
if (a[mid] > a[low])
{
wap(a, mid, low);
} //将中间大小的数与第一个数交换
}
三种方法,都测试通过,前两种都是按图中方案写的代码,第二种方法优化了一点,不同第一种方法的地方是,第二种不用交换,直接覆盖,节省了时间;
之后:快速排序是不稳定的,其时间平均时间复杂度是O(nlgn)。
附一张图:
赐教!