找到分区点,把数组元素放到分区点两侧,再对分区点两侧数组进行排序,完成快排。
同样递归实现快排。
递归公式:
递归终止条件:
当所分区只有一个元素是,即元素下标相同时,递归终止,并返回。
快排实现目的:对数组进行排序
实现过程:
传递一个数组和数组起始下标和终止下标。
进行分区:获取这个数组中的一个分区点,分区点前的数据小于分区点,后的数据大于分区点。
递归:然后通过递归,再对分区点之前的数组和之后的数组进行分区。
结束条件:数组元素下标相等,即只有一个元素,返回。
分区模块实现原理:
以数组的最后一个元素作为分区点。
定义两个数据开始都指向数组的第一个元素,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;
}