2.8 快速排序之元素重复与否
20201002
参考链接:
https://www.jianshu.com/p/a68f72278f8f
https://www.sohu.com/a/246785807_684445
1.问题描述
快速排序算法是基于分支策略的排序算法之一,基本思想是:对输入的子数组a[p:r]按以下三个步骤进行排序:
- 分解(Divide):以a[p]为基准元素,将a[p:r]划分为三段a[p:q-1],a[q],和a[q+1:r],使得a[p:q-1]中任何一个元素小于等于a[q],而a[q+1:r]中任何一个元素大于等于a[q]。下标q在划分过程中不断地确定。
- 递归求解(Conquer):通过递归调用快速排序算法分别对a[p:q-1]和a[q+1:r]进行排序。
- 合并(Merge):由于对a[p:q-1]和a[q+1:r]的排序是就地进行的,所以在a[p:q-1]和a[q+1:r]都已排好序后,不需要执行任何计算,a[p:r]就已排好序。
2.问题分析
上面是对基本思想的一个官方性描述,其实简单来说,快速排序的基本思想为:
(下面中第一第二等等位置是相对于划分而言的)
- 把集合中第一个数作为为基准值x
- 第二个数开始向后(下标i++),最后一个数开始向前(下标j++),不断地与基准x进行比较,当a[i]>x,而a[j]<x时,将a[i]和a[j]进行swap交换。
- i与j相遇时,即为中间位置a[j],此时将基准值X的值复制给a[j],而a[j]原来的值放在基准值X原来的位置,即第一个位置。
- 以上面基准值a[j]的位置进行划分为a[0:j-1]和a[j+1:n]两部分,分别选取基准值,再重复上述步骤,直至不和划分为止。
文字略显乏味,下面来几张图作为下饭菜吧!
来自于:https://blog.csdn.net/xdy1120/article/details/97804330
来自于:https://www.runoob.com/?s=%E5%8D%81%E5%A4%A7%E6%8E%92%E5%BA%8F
下面的图片略有不同,它是将最后一个元素作为基准值,而我们是将第一个作为基准值,其余都类似。
3.代码实现
// quicksort.cpp : Defines the entry point for the console application.
//
#include "stdio.h"
#include "iostream.h"
#define N 1024
template<class Type>
inline void Swap(Type &a,Type &b)
{
Type temp=a;a=b;b=temp;
}
template<class Type>
int Partition(Type a[],int p,int r)
{
int i=p,j=r+1;
Type x=a[p];
//对<x的元素交换到基准元素的左边区域
//对>x的元素交换到基准元素的右边区域
while(true){
while(a[++i]<x && i<=r);//左边元素小于基准值x且左标记i<r
while(a[--j]>x);//右边元素大于基准值x
if(i>=j) break;//当i>=j时,左右标记相遇
Swap(a[i],a[j]);//左边元素大于基准值x或者右边元素小于a[p]
}
a[p]=a[j];//i,j相遇处a[j]属于基准左边,因此将a[j]放在a[p]处
a[j]=x;//a[j]为基准值x
cout<<"基准为"<<j<<endl;
return j;//返回基准下标
}
template<class Type>
void quicksort(Type a[],int p,int r)
{
if(p<r){
int q=Partition(a,p,r);
cout<<endl;
quicksort(a,p,q-1);//对左半段排序
quicksort(a,q+1,r);//对右半段排序
}
}
int main(int argc, char* argv[])
{
// printf("Hello World!\n");
int n,count,i=0;
int a[N];
cout<<"请问你需要输入多少元素呢!"<<endl;
cin>>count;
for(i=1;i<=count;i++){
cout<<"请输入第"<<i<<"个元素"<<endl;
cin>>n;
a[i]=n;
}
quicksort(a,1,count);
for(i=1;i<=count;i++){
cout<<"第"<<i<<"个元素为"<<a[i]<<endl;
}
return 0;
}
4.代码纠错之元素重复怎么办?
之前在写代码的时候,只是把一组不重复的元素输入进去了,并没与发现什么异常,最近在利用之前快速排序的时候元素含有重复,运行自己之前的函数时候发现,上面的代码只有在元素不重复的时候才有效果,当元素重复时,对于重复元素效果并不是很好。例如:
输入元素:2 2 2 3 1 5
不重复的代码如下:
//含有重复元素时候,例如:2 2 2 1 3 5
template<class Type>
int Partition_sort(Type a[],int low,int high)
{
int x=a[low];
int i=low,j=high;
while(i!=j){
while(x<=a[j] && i<j) j--;
if(i<j) {
int temp=a[i];
a[i]=a[j];
a[j]=temp;
i++;
}
while(x>=a[i] && i<j) i++;
if(i<j) {
int temp=a[i];
a[i]=a[j];
a[j]=temp;
j--;
}
}
for(int m=1;m<=6;m++){
cout<<"第"<<m<<"个元素为"<<a[m]<<endl;
}
return i;
}
再次运行输入结果: