分治法-快速排序

1.快速排序

快速排序是冒泡排序的一种改进,它平均的时间复杂度为O(nlogn)

快速排序的思路如下:对于输入的数组a[p: r]

  1. 分解:以a[p]作为基准值,将数组分为三段 a[p:q-1] a[q]和a[q+1: r],并且满足a[p: q-1]的值小于等于a[q],而a[q+1:r]的值大于等于a[q]。下标q在划分过程中确定。
  2. 递归:递归调用快速排序分别对a[p:q-1]和a[q+1:r]进行排序。
  3. 合并:由于快速排序是原地排序,所以不需要合并。

由于快速排序是对冒泡排序的改进,所以快速排序在每次排序都会确认一个元素的最终值。

快速排序的代码并不算困难:

 

/**
 * 对a[p:r]进行划分 扩展两个区域a[p:i]和a[j:r]
 * @param nums: 数组
 * @param start: 基准值索引 在这里也是第一个值的索引
 * @param end: 数组最后一个值的索引
*/
template<class Type>
int partition(Type nums[], int start, int end) {
	int left = start, right = end + 1;
	Type x = nums[start];
	//将 < x的元素交换到左边区域 > x的元素交换到右边区域
	while (true) {
		while (nums[++left] < x && left < end);
		while (nums[--right] > x);
		if (left >= right) break;

		Type temp = nums[left];
		nums[left] = nums[right];
		nums[right] = temp;
	}
	nums[start] = nums[right];
	nums[right] = x;
	return right;
}

partition函数定死start为基准值,同时也是数组的起始位置。

 

按照快速排序的思路,快速排序的一趟遍历就是让小于等于基准值的元素在基准值左边;大于等于基准值的元素在基准值的右边。partition函数所做的工作如下:

  1. left从左向右遍历,找到一个大于基准值的元素;
  2. right从右向左,找到一个小于基准值的元素,然后两个元素相互交换。重复上述过程直至left >= right。
  3. 之后让基准值和right所在的元素进行交换。

 

/**
 * 快速排序
 * @param nums: 数组
 * @param p: 基准值索引
 * @param r: 数组最后一个值的索引
*/
template<class Type>
void quickSort(Type nums[], int p, int r) {
	if (p < r) {
		int q = partition(nums, p, r);
		quickSort(nums, p, q - 1);
		quickSort(nums, q + 1, r);
	}
}

之后是主函数:

int main() {
	int a[] = { 4, 2, 6, 7, 5, 3, 2};
	int len = sizeof(a) / sizeof(a[0]);
	
	quickSort(a, 0, len - 1);

	for (int i = 0; i < len; i++)
		cout << a[i] << " ";
	cout << endl;
	return 0;
}

2.快速排序的改进

快速排序的性能就在于基准值的选择,最坏情况下就是每次选择的基准值都是当前的最值,此时分成了n-1个元素和1个元素,其最坏时间复杂度为O(n^{2})。所以基准值的选择也是比较重要的。

2.1 随机选择一个元素

随机选择一个元素作为基准值。

/**
 * 随机选择一个基准值index属于[start, end],之后nums[start] 交换 nums[index],
 * @params nums: 数组
 * @params start: 起始索引
 * @params end: 结束索引
*/
template<class Type>
int randomPartition(Type nums[], int start, int end) {
    //随机数
	random_device rd;
	default_random_engine random(rd());
	//随机数分布对象 [start, end]
	uniform_int_distribution<unsigned> uniform(start, end);
	int index = uniform(random);
	//交换值
	Type temp = nums[start];
	nums[start] = nums[index];
	nums[index] = temp;
 
	return partition(nums, start, end);
}
	

这个函数在a[start: end]中随机选择一个元素作为基准值。

default_random_engine为c++11提供的 随机数生成函数,其包含在#include <random>库中。

template<class Type>
void quickSort(Type nums[], int p, int r) {
	if (p < r) {
		int q = randomPartition(nums, p, r);
		quickSort(nums, p, q - 1);
		quickSort(nums, q + 1, r);
	}
}

接着要在快速排序中调用这个函数。 

3.测试

测试基于LeetCode的排序数组

快速排序的性能测试:

 2.1的快速排序的性能测试:

4. 参考

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值