快速排序
快速排序是对冒泡排序的一种改进。基本思想是分治法:在待排序表 L[1.....n]中任取一个元素pivot作为基准,通过一趟排序将待排序表划分为独立的两部分 L[1...k-1]和 L[k+1...n] ,使得L[1...k-1]的所有元素小于pivot,L[k+1...n]中所有元素大于pivot,则pivot放在了其最终位置L(k)上,这个过程称为一趟快速排序。而后分别递归的对两个子表重复上述过程,直至每部分内只有一个元素或空为止,即所有元素放在了其最终位置。
快速排序思路:
a. 取一个元素p(第一个元素),使元素p归位;
b. 列表被p分成两部分,左边都比p小,右边都比p大;
c. 递归完成排序。
假设划分算法已知,记为partation(),递归的调用快排,具体结构如下:
def quick_sort(data, left, right): if left < right: mid = partition(data, left, right) quick_sort(data, left, mid - 1) quick_sort(data, mid + 1, right)
可以看出快排关键在于划分操作,同时快排性能也主要取决于划分操作好坏。
对于划分算法,假设每次总是以当前表中第一个元素作为枢纽值(基准)对表进行划分,则必须将表中枢纽值大的元素向右移,比枢纽值小的向左移动,使得一趟partition()操作后,表中的元素被枢纽值一分为二。
def partition(data, left, right): tmp = data[left] while left < right: while left < right and data[right] >= tmp: right -= 1 data[left] = data[right] while left < right and data[left] <= tmp: left += 1 data[right] = data[left] data[left] = tmp return left
快排性能分析:
空间效率:
由于快排是递归的,需要借助一个递归工作栈来保存每一层递归调用的必要信息,其容量应于递归调用的最大深度一致。最好情况下为[log(n+1)];最坏情况下,O(n)。所以空间复杂度:平均为O(logn),最坏情况O(n)。
时间效率:与划分是否对称有关,快排最坏情况发生在两个划分区域分别含n-1个元素和0个元素时,这种最大程度的不对称性发生在每一层递归上,就得到最坏情况下的时间复杂度O(n^2)。如所有逆序排列的元素,对其进行快排,时间复杂度O(n^2)。
在理想状态下partition()可以做到最平衡的划分,此时时间复杂度为O(nlogn)。
快速排序是内部排序平均性能最优的算法。
快排在划分算法时,若右端区间存在两个关键字相同,且均小于基准值记录,则在交换到左区间后,相对位置发生变化,故快排是一个不稳定排序方法。