快速排序的思想是:选取一个枢轴值,一趟排序后,将待排序列分成两部分,左边部分均不大于这个枢轴值,右边部分均不小于这个枢轴值。然后再次对两侧进行快速排序,直至整个序列有序。
实例:
#include "stdio.h"
#define MAXSIZE 10
int data[MAXSIZE] = {5,4,3,6,8,1,2,9,7,0};
void swap(int data[],int i,int j)
{
int temp = data[i];
data[i] = data[j];
data[j] = temp;
}
/*
* 功能:将一个数据插到一个左边不大于,右边不小于他的位置
* 输入:1.排序数组;2.数组下标;3.数组上标
* 输出:上面功能提及的那个位置
*/
int partition(int data[],int low,int high)
{
int pivotkey = data[low]; // 选取第一个元素为枢轴值
while(low < high) // 条件都为当下标小于上标,通过移动两个游标,当两者相等时就是该枢轴返回的位置。
{
while(low < high && data[high] >= pivotkey) // 当右侧元素大于等于枢轴值时,上标--
high--;
swap(data,low,high); // 否则交换位置
while(low < high && data[low] <= pivotkey) // 交换后的第一个判断一定成立,当左侧元素小于等于枢轴值时下标++
low++;
swap(data,low,high); // 否则交换位置
} // 直至枢轴值插到一个左边不大于,右边不小于他的位置
return low;
}
/*
* 功能:快速排序
* 输入:1.排序数组;2.数组下标;3.数组上标
* 输出:无
* 算法:将一个数放在一个左边不大于它右边不小于它的位置,然后不断递归
*/
void quickSort(int data[],int low,int high)
{
int pivot;
if(low < high)
{
pivot = partition(data,low,high); // 返回枢轴值所在位置
quickSort(data,low,pivot-1); // 再次对左侧分组进行快速排序
quickSort(data,pivot+1,high); // 再次对右侧分组进行快速排序
}
}
void print(int *data)
{
for(int i = 0; i < MAXSIZE; i++)
printf("%d ",data[i]);
printf("\n");
}
void main(int argc, char* argv[])
{
print(data);
quickSort(data,0,MAXSIZE-1);
print(data);
}
打印结果:
优化:
①优化选取枢轴值
固定选取第一个元素作为枢轴是不太合理的,因为待排序的序列可能是常常是基本有序的。partition函数显然会做了大量的无用功,很可能成为性能的瓶颈。
方法:三数取中,取三个元素的中间值作为枢轴。最方便的做法就是选取左右两端以及中间三个数的中间值。
int pivotkey;
/*三数取中以获得较好的枢轴值*/
int m = low + (high-low)/2;
if(data[low] > data[high])
swap(data,low,high);
if(data[m] > data[high])
swap(data,m,high);
if(data[m] > data[low])
swap(data,m,low);
pivotkey = data[low]; // 选取一个数值尽量靠中间的为枢轴
②优化不必要的交换
while(low < high)
{
while(low < high && data[high] >= pivotkey)
high--;
data[low] = data[high]; // 直接赋值取代了交换
while(low < high && data[low] <= pivotkey)
low++;
data[high] = data[low];
}
data[low] = pivotkey;
③优化递归操作,递归对性能无疑有一定影响,尤其是在递归深度越深时。
while(low < high)
{
pivot = partition(data,low,high); // 返回枢轴值所在位置
quickSort(data,low,pivot-1); // 再次对左侧分组进行快速排序
low = pivot+1; // low此时没用了,用迭代来取代递归,缩减堆栈的深度
}
做了一个小测试,选的值都是比较适中的。因为测试的都是随机数,所以第一个优化基本无效,第二个优化就是这次比较的结果,第三个优化应该对时间性能上影响不大。
快速排序法的平均时间复杂度是O(nlogn)