深入探究快速排序 && 随机快速排序

深入探究快速排序 && 随机快速排序

本篇博客将展示快速排序中两种partition的写法,同时讲解随机快速排序,并将它们进行对比

快速排序

1、第一种partition

这种partition的写法主要是确定一个基准值(一般最右侧的值),然后两个指针从两头往中间移动,,当两个指针相遇后,将基准值与指针交换,这样使得小于基准值的值在基准值的左侧,大于基准值的值在基准值的右侧。

int partition(vector<int> &q, int l, int r)
{
	int x = q[r];
	int i = l;
	int j = r - 1;
	while (i < j)
	{
		while (i < r && q[i] <= x)
			i++;
		while (j > l && q[j] >= x)
			j--;
		if (i < j)
			swap(q[i], q[j]);
		else
			j--;
	}
	if ((i != j) || (i == j && q[i] > q[r]))
		swap(q[i], q[r]);
	return i;
}

2、第二种partition

这种partition是基于交换的,定义两个变量i和j分别指向当前小于基准值的数组元素,j用于遍历数组。

int partition(vector<int> &nums, int low, int high) {
	int i = 0, j = 0;
	for (i = low, j = low; j < high; ++j) {
		if (nums[j] <= nums[high]) {
			swap(nums[i++], nums[j]);
		}
	}
	swap(nums[i], nums[j]);
	return i;
}

3、快速排序主体

void quick(vector<int> &q, int l, int r)
{
	if (l >= r)
		return;
	int part = partition(q, l, r);
	quick(q,l, part - 1);
	quick(q, part + 1, r);
}

随机快速排序

上面版本的快排在选取基准值的时候,都选取了最右边的元素。但是当序列为有序时,会发现划分出来的两个子序列一个里面没有元素,而另一个则只比原来少一个元素。这种情况就会成为快速排序最坏情况。为了避免这种情况,引入一个随机化量来破坏这种有序状态。

在随机化的快排里面,选取a[left…right]中的随机一个元素作为基准值,然后再进行划分,就可以得到一个平衡的划分。

下面是随机快速排序的伪代码以及c++代码,这里代码选择第一种partition的写法。

randomPartition (A, l, r)
index = random(l, r)
exchange A[index]  with A[r]
return partition(A, l, r)

randomQuick (A, l, r)
if (l<r)
     q  =  randomPartition (A, l, r)
     randomQuick (A, l, q-1)
     randomQuick (A, q+1, r)
int partition(vector<int> &q, int l, int r)
{
	int x = q[r];
	int i = l;
	int j = r - 1;
	while (i < j)
	{
		while (i < r && q[i] <= x)
			i++;
		while (j > l && q[j] >= x)
			j--;
		if (i < j)
			swap(q[i], q[j]);
		else
			j--;
	}
	if ((i != j) || (i == j && q[i] > q[r]))
		swap(q[i], q[r]);
	return i;
}

int randomPartition(vector<int> &q, int l, int r)
{
	srand((unsigned int)time(NULL));
	int index = rand() % (r - l) + l;
	swap(q[index], q[r]);
	return partition(q, l, r);
}

void quick(vector<int> &q, int l, int r)
{
	if (l >= r)
		return;
	int part = randomPartition(q, l, r);

	cout << "After Change: ";
	for (int i = 0; i < q.size(); i++)
	{
		cout << q[i] << "  ";
	}
	cout << "\n" << "\n";

	quick(q,l, part - 1);
	quick(q, part + 1, r);
}

结果比较

1、无序数组

随机化快排因为要生成随机数,所以有一些性能损失,所以数据规模较小,数据分布均匀时普通快排还是比随机化快排要快些的,不过随着数据规模的上升,随机化快排的性能优势就展现出来了。

10w:
算法第一次第二次第三次平均值
普通快排14ms15ms14ms14.3ms
随机快排26ms30ms23ms26.3ms
100w:
算法第一次第二次第三次平均值
普通快排104ms110ms99ms104.3ms
随机快排130ms120ms123ms124.3ms
1000w:
算法第一次第二次第三次平均值
普通快排1390ms1444ms1373ms1402.3ms
随机快排1395ms1386ms1309ms1363.3ms

2、有序数组

在有序数组的情况下,随机快速排序的效果就能很好地体现出来了。

10w:
算法第一次第二次第三次平均值
普通快排溢出溢出溢出溢出
随机快排16ms9ms12ms12.3ms
1w:
算法第一次第二次第三次平均值
普通快排104ms123ms163ms130ms
随机快排2ms1ms1ms1.3ms
1000w:
算法第一次第二次第三次平均值
随机快排740ms792ms812ms781.3ms
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值