【快速排序】

快速排序

递归法

1、快排

  快速排序算法使基于分治策略的一个排序算法,其基本思想是,对于输入的子数组 nums[left : right] 按以下3个步骤排序:

(1)分解:以 nums[left] 为基准元素将 nums[left : right] 划分成3段 nums[left: mid-1],nums[mid] 和 nums[mid+1:right],使得nums[left:mid-1] 中任何元素小于等于 nums[mid], nums[mid+1:right] 中任何元素大于等于 nums[right]。下标 mid 在划分过程中确定。

(2)递归求解: 通过递归调用快速排序算法,分别对 nums[left:mid-1] 和 nums[mid+1:right] 进行排序。

(3)合并 : 由于对 nums[left:mid-1] 和 nums[mid+1:right] 的排序是就地进行的,所以在 nums[leftmid-1] 和 nums[mid+1:right] 都已排好的序后不需要执行任何计算,nums[left:right] 就已排好序。

//递归法,双向开工,left向左 right向右
//打印函数
void PrintInt(const int* nums, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%5d", nums[i]);
	}
	printf("\n");
}

//划分函数的功能是将小于tmp的元素放在左半部分,大于tmp放在右边部分
int Partition(int* nums,int left, int right)//划分函数,i==j 时while循环推出,此时i or j左边均小于nums[i],youbianjun
{
	int i = left, j = right;
	int tmp = nums[i];
	while (i < j)// i < j是为了不发生划分时交叉了
	{
		while (i < j && nums[j] > tmp)
			--j;
		if (i < j)
			nums[i] = nums[j];
		while (i < j && nums[i] <= tmp)
			++i;
		if (i < j)
			nums[j] = nums[i];
	}
	nums[i] = tmp;
	return i;//return j;
}
//快排
void QuickSort(int *nums, int left, int right)
{
	if (left < right)
	{
		int mid = Partition( nums, left,  right);
		QuickSort(nums, left,mid - 1);
		QuickSort(nums, mid + 1, right);
	}
}
主函数
int main()
{
	int ar[] = { 56,23,78,45,90,89,12,34,56,67,89,100 };
	int n = sizeof(ar) / sizeof(ar[0]);
	PrintInt(ar, n);
	QuickSort(ar, 0, n - 1);
	PrintInt(ar, n);
}

2、快排的优化

快 排 的 退 化 , 当 数 据 有 序 时 , 快 排 的 速 度 越 慢 , 快排的退化,当数据有序时,快排的速度越慢, 退
分析:
  快排的的运行时间于划分是否对称性有关,最坏的情况是划分中两个区域分别包含n-1个元素和1个元素的情况,Partition的计算时间为O(n),若每一步都出现这种不对称划分,计算时间为O(n^2).

解决方法:   利用随机选择策略使初始数组变的无序
  修改Partition算法,在数组还没有被划分时,可以在nums[left : right]中随机选择一个元素作为划分基准,这样可以使划分基准的选择是随机的,划分比较对称。

//随机策略,使数据更有序
int RandPartition(int* nums, int left, int left)
{
	srand(time(nullptr));
	int ropos = (rand() % (right - left + 1)) + left;//随机位置,加left是因为right - left是相对法,要加上此时的left
	std::swap(nums[left], nums[ropos]);//交换随机位置和left的值
	return Partition(nums, left, right);//调用划分函数
}
//递归法,双向开工,left向左 right向右
//打印函数
void PrintInt(const int* nums, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%5d", nums[i]);
	}
	printf("\n");
}

//划分函数的功能是将小于tmp的元素放在左半部分,大于tmp放在右边部分
int Partition(int* nums,int left, int right)//划分函数,i==j 时while循环推出,此时i or j左边均小于nums[i],youbianjun
{
	int i = left, j = right;
	int tmp = nums[i];
	while (i < j)// i < j是为了不发生划分时交叉了
	{
		while (i < j && nums[j] > tmp)
			--j;
		if (i < j)
			nums[i] = nums[j];
		while (i < j && nums[i] <= tmp)
			++i;
		if (i < j)
			nums[j] = nums[i];
	}
	nums[i] = tmp;
	return i;//return j;
}
//快排
void QuickSort(int *nums, int left, int right)
{
	if (left < right)
	{
		int mid = Partition( nums, left,  right);
		QuickSort(nums, left,mid - 1);
		QuickSort(nums, mid + 1, right);
	}
}
主函数
int main()
{
	int ar[] = { 56,23,78,45,90,89,12,34,56,67,89,100 };
	int n = sizeof(ar) / sizeof(ar[0]);
	PrintInt(ar, n);
	QuickSort(ar, 0, n - 1);
	PrintInt(ar, n);
}

3、非递归法

利用队列或栈来实现非递归快排

#include<iostream>
#include<stdio.h>
#include<queue>
//非递归
void PrintInt(const int* nums, int n)
{
	for (int i = 0; i < n; i++)
	{
		printf("%5d", nums[i]);
	}
	printf("\n");
}
int Partition(int* nums, int left, int right)//划分函数,i==j 时while循环推出,此时i or j左边均小于nums[i],youbianjun
{
	int i = left, j = right;
	int tmp = nums[i];
	while (i < j)// i < j是为了不发生划分时交叉了
	{
		while (i < j && nums[j] > tmp)
			--j;
		if (i < j)
			nums[i] = nums[j];
		while (i < j && nums[i] <= tmp)
			++i;
		if (i < j)
			nums[j] = nums[i];
	}
	nums[i] = tmp;
	return i;//return j;
}

void QuickSort(int *nums, int left, int right)
{
	std::queue<int> qu;
	qu.push(left);
	qu.push(right);
	while (!qu.empty())//为空跳出
	{
		int sleft = qu.front();//取队头
		qu.pop();//出队
		int sright = qu.front();
		qu.pop();
		int mid = Partition(nums, sleft, sright);
		if (sleft < mid - 1)
		{
			qu.push(sleft);
			qu.push(mid - 1);
		}
		if (mid + 1 < sright)
		{
			qu.push(mid + 1);
			qu.push(sright);
		}
	}
	
}

int main()
{
	int ar[] = { 56,23,78,45,90,89,12,34,56,67,89,100 };
	int n = sizeof(ar) / sizeof(ar[0]);
	PrintInt(ar, n);
	QuickSort(ar, 0, n - 1);
	PrintInt(ar, n);
}

结 果 : 结果:
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值