快速排序
快速排序是冒泡排序的改进版,也是最好的一种内排序,在很多面试题中都会出现,也是作为程序员必须掌握的一种排序方法。
【思想】
1.在待排序的元素任取一个元素作为基准(通常选第一个元素,但最的选择方法是从待排序元素中随机选取一个作为基准),称为基准元素;
2.将待排序的元素进行分区,比基准元素大的元素放在它的右边,比其小的放在它的左边;
3.对左右两个分区重复以上步骤直到所有元素都是有序的。
你可以把快速排序联想成东拆西补或西拆东补,一边拆一边补,直到所有元素达到有序状态。
图解如下:
6.对元素5两边的元素也重复以上操作,直到元素达到有序状态。
很明显代码用递归写更方便。
我用数组来模拟快速排序。
【写法一】
1 #include<iostream> 2 using namespace std; 3 int a[10]; 4 void fastSorting(int left, int right) 5 { 6 int x = a[left], l = left, r = right;//以第一个数为参照做比较 7 if (l >= r)return; 8 while (l<r) 9 { 10 while (l<r&&a[r] >= x) //x=a[s] 11 r--; //不小于分界值的留在右边,遇到小于的停止 12 a[l] = a[r]; 13 while (l<r&&a[l] <= x) 14 l++; //小于分界值的留在左边,遇到不小于的停止 15 a[r] = a[l]; 16 } 17 a[r] = x; 18 fastSorting(left, r - 1); 19 fastSorting(r + 1, right);//递归 20 } 21 22 int main() 23 { 24 int i; 25 for (i = 0; i<10; i++) 26 a[i] = 10 - i; //输入数组元素 27 fastSorting(0, 9); //执行排序函数 28 for (i = 0; i<10; i++) //输出排序后结果 29 cout << a[i] << " "; 30 cout << endl; 31 system("pause"); 32 }
效果如上图所示。
【写法二】
1 #include<iostream> 2 #include<iomanip> 3 using namespace std; 4 5 //一趟排序过程 6 int Partition(int *arr, int low, int high) 7 {//对数组arr中的arr[low...hight]进行一趟排序,返回枢轴位置 8 int pivotkey= arr[low]; //用子表的第一个记录做枢轴记录,枢轴记录关键字保存在pivotkey中 9 while(low < high) //从表的两端交替的向中间扫描 10 { 11 while(low < high && arr[high] >= pivotkey) 12 --high; 13 arr[low] = arr[high]; //比枢轴记录小的记录移动到低端 14 15 while(low < high && arr[low] <= pivotkey) 16 ++low; 17 arr[high] = arr[low]; //比枢轴记录大的记录移动到高端 18 19 } //while 20 arr[low] = pivotkey;//arr[0] //枢轴记录到位 21 22 return low; //返回枢轴位置 23 } 24 25 //递归调用 26 void QSort(int *arr, int low, int high) 27 { 28 if(low < high) //长度大于1 29 { 30 int pivotloc = Partition(arr,low,high); //将arr[low..... high]一分为二,pivotloc是枢轴位置 31 QSort(arr,low,pivotloc-1); //对左字标递归排序 32 QSort(arr,pivotloc+1,high); //对右字标递归排序 33 } 34 } 35 36 //对数组做快速排序 37 void QuickSort(int *arr, int n) 38 { 39 40 QSort(arr,0,n-1);//n为数组中值的个数 所以最后一个下标为n-1 41 } 42 43 44 int main() 45 { 46 int a[100]; 47 for(int i = 0; i < 10; i++) 48 a[i] = 10-i; 49 50 QuickSort(a,10); 51 for(int j = 0; j < 10; j++) 52 cout<<a[j]<<ends; 53 cout<<endl; 54 55 return 0; 56 }
效果如上图所示。
算法分析:1.当分区选取的基准元素为待排序元素中的最大或最小值时,为最坏的情况,时间复杂度和直接插入排序的一样,移动次数达到最大值
Cmax = 1+2+...+(n-1) = n*(n-1)/2 = O(n2) 此时最好时间复杂为O(n2)
2.当分区选取的基准元素为待排序元素中的"中值",为最好的情况,时间复杂度为O(nlog2n)。
3.快速排序的空间复杂度为O(log2n).
4.当待排序元素类似[6,1,3,7,3]且基准元素为6时,经过分区,形成[1,3,3,6,7],两个3的相对位置发生了改变,所是快速排序是一种不稳定排序。