快速排序算法实现

此生再无相见时 提交于 2020-02-01 19:25:05

一般方法

  快速排序每趟都可以确定一个元素的最终位置,使得其左侧元素均小于temp,右侧元素均大于temp。
  快速排序的算法复杂度为O(nlogn)O(nlogn),当需要排序的序列接近有序时,算法复杂度退化为O(n2)O(n^2)

代码如下:

//对区间[left, right]进行划分
int Partition(int A[], int left, int right){
	int temp = A[left];  //将A[left]存放至临时变量temp
	while(left < right){
		while(left < right && A[right] > temp)  right--;  //反复左移right
		A[left] = A[right];
		while(left < right && A[left] <= temp)  left++;  //反复右移left
		A[right] = A[left];
	}
	A[left] = temp;  //放置temp至left与right相遇的地方
	return left;  //返回相遇的下标
}
//快速排序,left与right初值为序列首尾下标(例如1与n)
void quickSort(int A[], int left, int right){
	if(left < right){  //当前区域长度超过1
		//将[left, right]按A[left]一分为二
		int pos = Partition(A, left, right);
		quickSort(A, left, pos - 1);
		quickSort(A, pos + 1, right);
	}
}

优化方法

  当序列中的元素都接近有序时,由于每次temp选取第1个值,导致该主元不能将序列大致划分为两个长度接近的子区间,因此随机选择一个主元来进行优化,使对任意序列的期望时间复杂度为O(nlogn)O(nlogn)

随机数的生成函数

  需要添加stdlib.h和time.h两个头文件,在main函数开头加上“srand((usigned)time(NULL));”,该语句将生成随机数的种子。之后使用rand函数生成随机数即可。

随机数的范围设定

  rand函数只能生成[0, RAND_MAX]范围内的数字,若要生成[a, b]内的随机数,可使用“rand()%(b - a + 1) + a”;若要生成大于RAND_MAX的区间[a, b]内的数,可先用rand生成一个数,再用该数除以RAND_MAX来得到其在RAND_MAX范围内的占比,在乘以b - a,就是该数在[a, b]的占比。

例如生成[10000, 60000]间的随机数:

#include<cstdio>
#include<cstdlib>
#include<ctime>
#include<cmath>
int main(){
	srand((usigned int)time(NULL));
	int result = (int)(round(1.0 * rand() / RAND_MAX * (60000 - 10000) + 10000));
	//round()函数位于<math.h>,round(x)用于返回x的四舍五入整数值
	return 0;
}

随机快排

  在A[left]至A[right]中随机选取一个作为主元,即在[left, right]间选取一个随机数p。将A[p]与A[left]进行交换,其余与基础算法一致。

代码如下:

//选取随机主元,对区间[left, right]进行划分
int randPartition(int A[], int left, int right){
	//生成[left, right]内的随机数p
	int p = (round(1.0 * rand() / RAND_MAX * (right - left) + left));
	swap(A[p], A[left]);
	//以下为原先Partition()函数的划分过程,不需要改变任何语句
	int temp = A[left];  //将A[left]存放至临时变量temp
	while(left < right){
		while(left < right && A[right] > temp)  right--;  //反复左移right
		A[left] = A[right];
		while(left < right && A[left] <= temp)  left++;  //反复右移left
		A[right] = A[left];
	}
	A[left] = temp;  //放置temp至left与right相遇的地方
	return left;  //返回相遇的下标
}

参考资料

[1]. 《算法笔记》P142-146
[2]. srand((usigned)time(NULL));

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!