快速排序
快速排序是从起泡排序改进而得的一种“交换”排序方法。它的基本思想是通过一趟排序将待排记录分割成相邻的两个区域,其中一个区域中的元素均比另一个区域中元素小(区域内不见得有序)则可对这两个区域内的元素进行再排序,以达到整个序列有序。
三步跑(三个while循环)
相当于二叉树的前序遍历:
//快速排序 #include<stdio.h> int Partition(int a[] , int low , int high) { //一次划分 int pivotkey = a[low] ; while(low < high) { while(low < high && a[high] >= pivotkey) high-- ; if(low < high) a[low++] = a[high] ; while(low < high && a[low] <= pivotkey) low++ ; if(low < high) a[high--] = a[low] ; } a[low] = pivotkey ; return low ; } void Qsort(int a[] , int s , int t) { if(s < t) { int pivotloc = Partition(a,s,t) ;//一次划分 通过一趟排序将待排元素分割成两个相邻的区域,一个区域中元素都比pivotloc小,另一个区域元素都比pivotloc大 Qsort(a,s,pivotloc-1) ; //左边递归 分别对两个区域的元素再排序 Qsort(a,pivotloc+1,t) ; //右边递归 分别对两个区域的元素再排序 } } int main() { int a[] = {49,38,65,97,76,13,27,49} ; Qsort(a,0,7); int i ; for(i = 0 ; i < 8 ; i++) printf("%d ",a[i]); printf("\n"); return 0 ; }
在进行一次划分的过程中,从后部开始,找到一个不符合的元素,该指针就要在这个元素上歇一歇,另一个区域无用的位置将该元素复制过去,接着从下一个位置开始找(得到一个元素就继续往下找),一个大循环内部循环一次,需要找出前部和后部各一个不符合的元素进行调换,直到前部指针和后部指针相遇时结束,完成一次划分;(就像接力赛一样)
快速排序在一般情况下,是效率很高的排序方法,快速排序的平均时间复杂度为O(nlogn)。快速排序目前被认为是同数量级(O(nlogn))中最快的内部排序方法,这是由于对区域不断“一分为二”所带来的效益,但这仅就平均性能而言。如果待排序的原始记录已按关键字有序或“基本有序”排列时,快速排序的时间复杂度将蜕化为O(n^2),因为在这种情况下经常会发生这样的情况,即长度为n的记录序列经一次划分后得到的两个子序列的长度分别为 0 和 n-1 ,也就未能达到“一分为二”的划分,从而失去了快速排序的优势。为避免出现“蜕化”情形,通常以“三者取中”的规则选取枢轴记录,三者指的是第一个、最后一个和中间一个,以他们中取“中值”。即使如此也不能使快速排序在待排序记录序列已经有序的情况下达到和起泡排序相同的时间复杂度为O(n)的结果。快速排序的空间复杂度在一般的情况下为O(logn)(递归需要辅助空间),最坏的情况下为O(n^2)。
快速排序是不稳定的排序方法。