C语言:快速排序
快速排序是排序算法中,平均时间复杂度为O(n*log n)的一种算法,其实现需要先解决这样的一个问题,对一个序列A[1],A[2],A[3] .......A[N],调整序列中元素的位置,使得A[1](原序列中的第一个元素,下同)的左侧所有元素都不超过A[1],右侧所有元素都大于A[1],例如对序列{5,3,9,6,4,1}来说,调整后变为{3,1,4,5,9,6}这样就让A[1] =5 ,左侧的所有元素,不超过它,右侧的所有元素都大于它。
排序思想
1.快排是对冒泡排序的一种改进,在快速排序中,元素的比较和移动是从两端向中间进行的,关键码较大的元素一次就能从前面移动到后面,关键码较小的元素一次就能从后面移动到前面,元素移动距离的较远,从而减少了总的比较次数和移动次数
2.快速排序是基于分治法设计的,其分治策略是:
①、划分:选定一个元素作为轴值,以轴值为基准将整个序列划分为两个子序列。轴值的位置在划分的过程中确定,并且前一个子序列的元素均小于或者等于轴值,后一个子序列的元素大于或者等于轴值
②、求解子问题:分别对划分后的每一个子序列递归处理
③、合并:由于对子序列的排序是就地进行的,所以合并并不需要执行任何操作
排序方法
1.选择轴值,一般是选取第一个元素的关键码。有一个快排的最坏情况就是如果待排序元素是正序或者逆序,就会将除轴值以外的元素分到轴值的一边。
2.划分
①、设置划分区间:i=first,j=end
②、执行右侧扫描,直到r[j]小于轴值,将r[j]与r[i]交换,i++
③、执行左侧扫描,直到r[i]大于轴值,将r[i]与r[j]交换,j–
④、重复二到三直到i=j,确定看轴值的所在位置,返回该位置
初始键值序列 23 12 35 6 19 50 28
一次划分后 [19 13 6] 23 [35 50 28]
分别进行快速排序 [6 13] 19 [28] 35 [50]
6 [13] 35
13 28 50
最终结果 6 13 19 23 28 35 50
1 //对区间[left,right]进行划分 2 int Partition(int A[],int left, int right) 3 { 4 int temp =A[left]; //存放到临时变量temp 5 6 while(left < right) //只要left与right不相遇 7 { 8 while(left < right && A[right] > temp) right--;//反复左移 9 A[left] = A[right]; 10 11 while(left < right && A[left] <= temp) left++;//反复右移 12 A[right] = A[left]; 13 } 14 15 A[left] = temp; //把temp放到right与left相遇的地方 16 return left; //返回相遇下标 17 }
快速排序算法当序列中元素的排列比较随机时效率高,但是当序列中元素接近有序时,会达到最坏时间复杂度O(n^2),产生这种情况的主要原因在于主元没有把当前区间划分为两个长度接近的子区间。有什么办法能解决这个问题呢?那就是随机选取主元,这样虽然算法的最坏时间复杂度仍然是O(n^2)(例如,总是选择A[left]为主元),但是对于任意输入数据的期望时间复杂度都能达到O(n*log n),也就是说,不存在一组特定的数据能使这个算法出现最坏情况。
1 int randPartition(int A[],int left, int right) 2 { 3 //生成[left,right]内的随机主元 4 int p = (round(1.0*rand()/RAND_MAX)*(right-left)+left); 5 swap(A[p],A[left]); 6 int temp =A[left]; 7 while(left < right) 8 { 9 while(left < right && A[right] > temp) right--;//反复左移 10 A[left] = A[right]; 11 while(left < right && A[left] <= temp) left++;//反复右移 12 A[right] = A[left]; 13 } 14 A[left] = temp; 15 return left; 16 }
快速排序的递归实现如下:
1 //快速排序,left与right初值为序列下标(例如 1 与 n) 2 void quicksort(int A[], int left, int right) 3 { 4 if(left < right) // 当前区间的长度超过1 5 { 6 //将[left,right]按A[right]一分为2 7 int pos = randPartition(A,left,right); 8 quicksort(A, left, pos-1); //对左子区间递归进行快速排序 9 quicksort(A, pos+1, right); //对右子区间递归进行快速排序 10 } 11 }