快排算法实现

找到分区点,把数组元素放到分区点两侧,再对分区点两侧数组进行排序,完成快排。

同样递归实现快排。

递归公式:

递归终止条件:

当所分区只有一个元素是,即元素下标相同时,递归终止,并返回。

快排实现目的:对数组进行排序

实现过程:

传递一个数组和数组起始下标和终止下标。

进行分区:获取这个数组中的一个分区点,分区点前的数据小于分区点,后的数据大于分区点。

递归:然后通过递归,再对分区点之前的数组和之后的数组进行分区。

结束条件:数组元素下标相等,即只有一个元素,返回。

分区模块实现原理:

以数组的最后一个元素作为分区点。

定义两个数据开始都指向数组的第一个元素,less,great总是循环去寻找小于分区点的数据,找到小于分区点的数据就和less指向的元素进行交换。

小的往前移到数组下标为less的位置,大的往后移到数组下标为great的位置,交换之后,less往后移动一位,继续指向大于分区点的数据,然后great继续循环。

great循环结束的条件是,Great只要循环到分区点的前一个元素就可以了。

当循环退出还要进行分区点和less所指元素的交换,一位less总是指向大于分区点的元素。

这个模块返回分区点。

整个快速排序的过程都是在数组内部进行的排序,只是分部分完成,并没有离开数组。所以当排序完成,数组中的元素也就排好了。

快排的原理就是通过不断地分区细化进行排序

快排中最重要的,实现主要功能的就是分区。

#include <iostream>
#include <vector>

using namespace std;

int partition(vector<int>& myv,int lo,int hi)
{
	int less=lo,great=lo;
	int pivot=myv[hi];
	for(;great<=hi-1;++great)
	{
		if(myv[great]<pivot)
		{
			std::swap(myv[less++],myv[great]);
		}
	}
	std::swap(myv[less],myv[hi]);

	return less;
}
//当有两个以及两个以上,lo必然小于或者等于hi,如果只有一个孩子一个没有,只有一个等于,那就大于
//只有一个: 7 8-1  或者 10+1 11  
//一个没有: 3 3-1  或者 11+1 11  说这个数已经是这个分组最左边或者最右边的下标的值
void sort(vector<int>& myv,int lo,int hi)
{
	if(lo>=hi) return;//其实是小于起作用
	int p=partition(myv,lo,hi);
	sort(myv,lo,p-1);//最后企图利用最左边的左边
	sort(myv,p+1,hi);//最后企图利用最右边的右边
}
void sort(vector<int>& myv)
{
	if(myv.size()<=1) return;
	sort(myv,0,myv.size()-1);
}

void display(vector<int>& myv)
{
	for(auto ite=myv.begin();ite!=myv.end();++ite)
	{
		cout<<*ite<<endl;
	}
	cout<<endl;
}

int main()
{
	vector<int> myv={12,23,3,468,45,2,1,4376,5434,342,77,222};
	display(myv);
	sort(myv);
	display(myv);
	return 0;
}

快排的时间复杂度

对于已经排序好的数组,利用以上方法,去最后一个元素作为分区点时,时间复杂度是O(n^2),无序数组的时间复杂度是O(nlogn),所以当利用以上方法实现是,时间复杂度变大了。

解决办法就是随机选取分区点。

三路快排

三路块排是为了解决数组中含有很多重复元素的情况,提高程序效率。

对分区点有多个相同值时,就只需要对这些相同值之外的数据进行分区。

实现原理图:

 

i;用来遍历数组元素,一开始指向开头。

great;指向大于分区点的第一个元素,开始指向最后一个元素

less;指向小于分区点的最后一个元素,一开始指向第一个元素。

i所指向的元素和分区点进行比较,小于和less交换,less获取小于分区点的值之后往后移;大于和great交换,great获取大于分区点的值之后往前移;i和less交换之后向后移,和great交换不移动,因为:[less--i)的数据是等于分区点的,i和less交换之后,i的值就是等于分区点的,已知的,所以向后移,而i和great交换的数据未知,需要进行判定,所以不移动。

i和less说:来,这个给你,less获取一个之后往占位。

Great同理。

这样,小的都放在less以及less之前,大的都放在great以及great之后。

i到great之间的是未处理的数据,所以循环结束的条件就是i>great,

#include <iostream>
#include <vector>

using namespace std;

void sort(vector<int>& myv,int lo,int hi)
{
	if(lo>=hi) return;
	int i=lo,less=lo,great=hi;
	int pivot=myv[hi];
	while(i<=great)
	{
		if(myv[i]<pivot)
		{
			std::swap(myv[i],myv[less]);
			++i;
			++less;
		}else if(myv[i]>pivot)
		{
			std::swap(myv[i],myv[great]);
			--great;
		}else
		{
			++i;
		}
	}
	sort(myv,lo,less-1);
	sort(myv,great+1,hi);
}
void sort(vector<int>& myv)
{
	if(myv.size()<=1) return;
	sort(myv,0,myv.size()-1);
}

void display(vector<int>& myv)
{
	for(auto ite=myv.begin();ite!=myv.end();++ite)
	{
		cout<<*ite<<endl;
	}
	cout<<endl;
}

int main()
{
	vector<int> myv={12,23,3,468,45,2,1,3,5434,3,77,3};
	display(myv);
	sort(myv);
	display(myv);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值