快速排序算法不稳定。
快速排序算法在大多数的计算机上运行得都比其他排序算法快,而且排序算法消耗资源少。就平均时间而言快排是所有内部排序中最好的一个。对于已经排好的数组,最速排序有最坏时间复杂度为o(n^2)。当数组长度很小时,快排往往比其他排序方法要慢。
快排的代码,关键是parition算法。
void QuickSort(int arr[],int low,int high) { if(low<high){ int pivotPos = partion(arr,low,high); QuickSort(arr,low,pivotPos-1); QuickSort(arr,pivotPos+1,high); } }
Paition的三种实现方法
(1)arr[low]的第一个元素为pivot,设两个指针lessIndex=low(该索引之前的数比pivot小,初始值为low),另一个i从low+1开始遍历数组,找到一个比pivot小的数,lessIndex+1,然后交换到前面来。
int partion1int arr[],int low,int high) { if(!arr||low<0||low>high) throw new exception("NULL Array"); //left第一个元素被当做pivot int pivot = arr[low]; int lessIndex = low; for(int i=low+1;i<=high;++i){ if(arr[i]<pivot){ lessIndex++; if(lessIndex!=i){ int temp = arr[lessIndex]; arr[lessIndex] = arr[i]; arr[i] = temp; } } } //这一步破坏了稳定性 arr[low] = arr[lessIndex]; arr[lessIndex] = pivot; return lessIndex; }
int partion2(int arr[],int low,int high) { if(!arr||low<0||low>high) throw new exception("NULL Array"); //left第一个元素被当做pivot int pivot = arr[low]; int i = low+1; int j = high; if(low<high){ for(;;){ while(i<=j&&arr[i]<pivot)++i; while(i<=j&&arr[j]>pivot)--j; if(i<j){ swap(arr[i],arr[j]); ++i; --j; } else break; } arr[low] = arr[j]; arr[j] = pivot; } return j; }
int partion3(int arr[],int low,int high) { if(!arr||low<0||low>high) throw new exception("NULL Array"); //left第一个元素被当做pivot int pivot = arr[low]; int i = low; int j = high; while(i<j){ while(i<j&&arr[j]>pivot)j--; if(i<j){ arr[i] = arr[j]; i++; } while(i<j&&arr[i]<pivot)i++; if(i<j){ arr[j] = arr[i]; j--; } } arr[i] = pivot; return i; }
快排的非递归算法
这里我贴一个非递归的代码:http://blog.csdn.net/wdzxl198/article/details/11999191
#include<iostream> #include<stack> using namespace std; int Partition(int array[],int lhs,int rhs) { int x = array[rhs]; int i = lhs - 1; for(int j=lhs;j<=rhs-1;j++) { if(array[j] <= x) { ++i; std::swap(array[i],array[j]); } } std::swap(array[i+1],array[rhs]); return i+1; } void QuickSort(int *arr,int left,int right) { stack<int> st; if(left < right) { int mid = Partition(arr,left,right); if(left < mid-1) { st.push(left); st.push(mid-1); } if(mid+1 < right) { st.push(mid+1); st.push(right); } while(!st.empty()) { int q = st.top(); st.pop(); int p = st.top(); st.pop(); mid = Partition(arr,p,q); if(p < mid-1) { st.push(p); st.push(mid-1); } if(mid+1 < q) { st.push(mid+1); st.push(q); } } } else return; } int main() { int a[10] ={3,7,6,4,0,2,9,8,1,5}; for(int i=0;i<10;i++) cout<<a[i]<<" "; cout<<endl; cout<<"快速排序:"; QuickSort(a,0,9); for(int i=0;i<10;i++) cout<<a[i]<<" "; cout<<endl; system("PAUSE"); return 0; }
快排的局限性
(1)快排是一个效率很高的排序算法,但是对于长度很小的序列,快排效率低。研究表明长度在5~25的数组,快排不如插入排序。
(2)pivot选择不当,将导致树的不平衡,这样导致快排的时间复杂度为o(n^2);
(3)但数组中有大量重复的元素,快排效率将非常之低。
快排的改进算法
(1)在递归过程,当排序的子序列小于预定的值M时,采用插入插入排序
void QuickSort_Insert(int arr[],int low,int high) { if(high-low<=M){ InsertSort(arr,low,high) else int pivotPos = partion(arr,low,high); QuickSort(arr,low,pivotPos-1);//子序列采用快排 QuickSort(arr,pivotPos+1,high);//子序列采用快排 } }
(2)在划分过程中,对于小规模子序列不进行排序直接跳过,这样快排之后得到一个整体上几乎完全排好的序列。然后再用快排。
void __QuickSort_Insert(int arr[],int low,int high) { if(high-low<=M)return; int pivotPos = partion(arr,low,high); __QuickSort(arr,low,pivotPos-1); __QuickSort(arr,pivotPos+1,high); } void HybridSort(int arr[],int low,int high) { __QuickSort(arr,low,high); InsertSort(arr,low,high) }
(3)取arr[high],arr[mid],arr[left]中位数为pivot。将三者中中间大小的元素挪到left位置,取pivot = arr[left],最大的元素挪到中间。
int Median(int arr[],int len) { if(!arr||len<=0) throw new exception("NULL Array"); int left = 0; int right = len - 1; int mid = left + (right - left>>1); int minIndex = right; if(arr[minIndex]>arr[mid])minIndex = mid; if(arr[minIndex]>arr[left])minIndex = left; if(minIndex!=right)swap(arr[minIndex],arr[right]); if(arr[mid]<arr[left])swap(arr[left],arr[mid]); return left; }
这里出一个题目:以某个数为基准将一个数组分成三部分:第一部分表示小于该pivot,第二部分等于pivot,第三部分大于pivot,要得到三部分得区间范围。(其实相当于有个字符串“RRBBRGBG”转换成“RRRGGBBB”)
void ThreePartion(int arr[],int left,int right) { if(!arr||right<=left)return; int less = left;//指向小与pivot的索引 int greater = right;//指向大于pivot的元素 int pivot = arr[left]; int it = left; while(it<=greater){ if(arr[it]==pivot)++it; else if(arr[it]<pivot){ swap(arr[less],arr[it]); ++it; ++less; } else{ swap(arr[greater],arr[it]); --greater; } } }
void QuickSort(int arr[],int left,int right) { if(!arr||right<=left)return; int less = left;//指向小与pivot的索引 int greater = right;//指向大于pivot的元素 int pivot = arr[left]; int it = left; while(it<=greater){ if(arr[it]==pivot)++it; else if(arr[it]<pivot){ swap(arr[less],arr[it]); ++it; ++less; } else{ swap(arr[greater],arr[it]); --greater; } } QuickSort(arr,left,less-1); QuickSort(arr,greater+1,right); }