快速排序是C.R.A.Hoare提出的一种划分交换排序。它采用了一种分治的策略。
分治法基本思想:将原问题分解成若干个规模更小但结构与原问题相似的子问题,递归的解决这些子问题,然后将子问题的解组合为原问题的解。
快速排序:设当前待排序数组为array[low..high]
(1)分解
在array[low..high]中任选一个记录作为基准(一般以第一个元素为基准),以此基准将当前无序数组划分为左右两个较小的子区间array[low..pivotpos-1]和array[pivotpos+1..high],并使左子区间中的所有记录的关键字都小于等于基准记录的关键字。右边子区间的所有记录的关键字都大于等于基准记录的关键字。基准则位于正确的位置。划分的关键是要求出基准记录所在的位置。
(2)求解
通过递归调用快速排序对左右子区间快速排序。
(3)组合
递归调用结束时,其左右子区间已经有序,就无需在做什么。
快速排序算法:
1 void QuickSort(SeqList array, int low, int high) 2 {//对array[low..high]快速排序 3 int pivotpos; //划分后基准记录的位置 4 if(low<high) //仅当区间长度大于1时才需排序 5 { 6 privotpos = Partition(array, low, high); 7 //对array[low..high]做划分 8 QuickSort(array, low, pivotpos-1); //对左区间递归排序 9 QuickSort(array, pivotpos+1, high);//对右区间递归排序 10 } 11 }
对整个数组排序只需调用QuickSort(array, 1, n)即可。
划分算法Partition
(1)设置两个指针i,j,它们的初始值分别为区间的下界和上界,即i=low,i=high;选取第一个元素作为基准记录,将它保存在pivotpos中。
(2)令j自high起向左扫描,直到遇到第一个比pivotpos.key小的记录array[j],将array[j]移动到i位置,使关键字小于基准的记录移动到基准的左边,然后令i指针自i+1位置开始向右扫描,直到找到第一个比pivotpos.key大的记录array[i],将array[i]移动到j所指的位置上,相当于实现array[i]和基准array[j]的交换,是关键字大于基准的记录移动到基准的右边。接着令指针j自位置j-1开始向左扫描,如此交替改变方向,从两端各自往中间靠拢,直至i=j时,i便是基准pivot的最终位置,将pivot放到此位置就完成了一次划分。
划分算法代码:
int Partition(SeqList array, int i, int j) {//调用Partition时对array[low..high]做划分并返回基准所在位置 ReceType pivot = array[i];//用区间的第一个记录作为基准 while (i<j)//从区间两端交替向中间扫描,直至i=j为止 { while(i<j && array[j] >= pivot) j--;//从右向左扫描,查找第一个关键字小于pivot的记录array[j] if(i<j) array[i++] = array[j]; while(i<j && array[i] <= pivot) i++;//从左向右扫描,查找第一个关键字大于pivot的记录array[i] if(i<j) array[j--] = array[i]; } array[i] = pivot; //基准记录已被最后定位 return i; }
时间复杂度:快速排序是一种不稳定的排序方法,平均时间复杂度O(nxlgn/lg2),最差情况时间复杂度为O(n*n)。