版权声明:转用请注明出处 https://blog.csdn.net/weixin_39411321/article/details/89212212
基本思想:
快速排序算法的基本思想:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
可能从字面感觉不到他的好处,我们通过例子来学习他的精妙之处;
例如:假设我们要对数组{50,10,90,30,70,40,80,60,20}进行排序
我们先来看代码:
快速排序法的普通版本
int Partition(SeqList*L, int low, int high)
{
int pivotkey;
pivotkey = L->data[low];
while (low<high)
{
while (low<high&&L->data[high]>pivotkey)
{
high--;
}
swap(pivotkey, L->data[high]);
while (low < high&&L->data[low] < pivotkey)
{
low++;
}
swap(pivotkey, L->data[low]);
}
return low;
}
void Qsort(SeqList*L,int low,int high)
{
int pivot;
if (low < high)
{
pivot = Partition(L, low, high);
Qsort(L, low, pivot - 1);
Qsort(L, pivot + 1, high);
}
}
void Quicksort(SeqList *L)
{
Qsort(L, 1, L->cursize);
}
//
int Partition(SeqList*L, int low, int high)
{
int pivotkey;
pivotkey = L->data[low]; //用子表的第一个记录作为枢轴记录
while (low<high) //从表的两端交替向中间扫描
{
while (low<high&&L->data[high]>pivotkey)
{
high--;
}
swap(pivotkey, L->data[high]); //将比枢轴记录小的交换到低端
while (low < high&&L->data[low] < pivotkey)
{
low++;
}
swap(pivotkey, L->data[low]); //将比枢轴记录大的交换到高端
}
return low; //返回枢轴所在的位置
}
快速排序法的优化版本
1.优化选取枢轴
int m = low + (high - low) / 2;//计算数组中间元素下标
if (L->data[low] > L->data[high])
swap(low, high);
if (L->data[m] > L->data[high])
swap(m, high);
if (L->data[m] > L->data[low])
swap(m, low);
//此时L->data[low]已经为整个序列左中右三个关键字的中间值了
2.优化不必要的交换
观察上边的图我们发现,50这个关键字,他的变换位置是1–》9–》3–》6–》5;其最终目标位置是5; 当中的其他交换是不需要的;因此我们对Partition函数进行优化;
//快速排序法的优化算法
int Partition(SeqList*L, int low, int high)
{
int pivotkey;
int m = low + (high - low) / 2;//计算数组中间元素下标
if (L->data[low] > L->data[high])
swap(low, high);
if (L->data[m] > L->data[high])
swap(m, high);
if (L->data[m] > L->data[low])
swap(m, low);
//此时L->data[low]已经为整个序列左中右三个关键字的中间值了
pivotkey = L->data[low];//用子表的第一个记录做枢轴记录
L->data[0] = pivotkey; //将枢轴关键字备份到L->data[0]中
while (low<high)
{
while (low<high&&L->data[high]>pivotkey)
{
high--;
}
//swap(pivotkey, L->data[high]);
L->data[low] = L->data[high]; //采用替换而不是交换的方式进行操作
while (low < high&&L->data[low] < pivotkey)
{
low++;
}
//swap(pivotkey, L->data[low]);
L->data[high] = L->data[low]; //采用替换而不是交换的方式进行操作
}
L->data[low] = L->data[0];
return low;
}
我们事实上将pivotkey备份到L->data[0]中,而以前swap的时候我们现在只进行替换工作,最终当low与high会和,及就是找到了枢轴位置时,再将L->data[0]赋给L->data[low],在这个当中少了很多的交换函数,性能也提升了一些。
3.优化小数组时的排序方案
//快速排序法的优化算法
#define MAX_LENGTH_INSERT_SORT 7
void Qsort(SeqList*L, int low, int high)//对顺序表L中的子序列L->[low-high]做快速排序
{
int pivot;
if ((high - low) > MAX_LENGTH_INSERT_SORT)
{
//当high-low大于MAX_LENGTH_INSERT_SORT时用快速排序法
pivot = Partition(L, low, high); //将数组一分为二并且算出枢轴值pivot
Qsort(L, low, pivot - 1); //对低子表递归排序
Qsort(L, pivot + 1, high); //对高子表递归排序
}
else //当high-low小于MAX_LENGTH_INSERT_SORT时用直接插入排序
InsertSort(L);
}
4.优化递归操作
//快速排序法尾递归的优化算法
#define MAX_LENGTH_INSERT_SORT 7
void Qsort(SeqList*L, int low, int high)//对顺序表L中的子序列L->[low-high]做快速排序
{
int pivot;
if ((high - low) > MAX_LENGTH_INSERT_SORT)
{
//当high-low大于MAX_LENGTH_INSERT_SORT时用快速排序法
while (low < high)
{
pivot = Partition(L, low, high);//将数组一分为二并且算出枢轴值pivot
Qsort(L, low, pivot - 1); //对低子表递归排序
low = pivot + 1; //尾递归
}
}
else//当high-low小于MAX_LENGTH_INSERT_SORT时用直接插入排序
InsertSort(L);
}
因为第一次递归以后,变量low就没有用处了,所以可以将pivot+1赋值给low,再循环后,来一次Partition(L,low,high),他的效果等同于QSort(L,pivot+1,high);结果是相同的 ,但是因为采用的是迭代而不是递归可以缩减堆栈深度,从而整体提高了性能。