有趣算法之快速排序之元素重复与否

2.8 快速排序之元素重复与否

20201002

参考链接:

https://www.jianshu.com/p/a68f72278f8f

https://www.sohu.com/a/246785807_684445

 

 

1.问题描述

 

快速排序算法是基于分支策略的排序算法之一,基本思想是:对输入的子数组a[p:r]按以下三个步骤进行排序:

  1. 分解(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在划分过程中不断地确定。
  2. 递归求解(Conquer):通过递归调用快速排序算法分别对a[p:q-1]和a[q+1:r]进行排序。
  3. 合并(Merge):由于对a[p:q-1]和a[q+1:r]的排序是就地进行的,所以在a[p:q-1]和a[q+1:r]都已排好序后,不需要执行任何计算,a[p:r]就已排好序。

 

 

2.问题分析

 

上面是对基本思想的一个官方性描述,其实简单来说,快速排序的基本思想为:

(下面中第一第二等等位置是相对于划分而言的)

  1. 把集合中第一个数作为为基准值x
  2. 第二个数开始向后(下标i++),最后一个数开始向前(下标j++),不断地与基准x进行比较,当a[i]>x,而a[j]<x时,将a[i]和a[j]进行swap交换。
  3. i与j相遇时,即为中间位置a[j],此时将基准值X的值复制给a[j],而a[j]原来的值放在基准值X原来的位置,即第一个位置。
  4. 以上面基准值a[j]的位置进行划分为a[0:j-1]和a[j+1:n]两部分,分别选取基准值,再重复上述步骤,直至不和划分为止。

 

 

文字略显乏味,下面来几张图作为下饭菜吧!

来自于:https://blog.csdn.net/xdy1120/article/details/97804330

image.png

 

来自于:https://www.runoob.com/?s=%E5%8D%81%E5%A4%A7%E6%8E%92%E5%BA%8F

quickSort.gif

 

quicksoft01.gif

 

下面的图片略有不同,它是将最后一个元素作为基准值,而我们是将第一个作为基准值,其余都类似。

image.png

 

 

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

image.png

 

不重复的代码如下:

//含有重复元素时候,例如: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;
}

再次运行输入结果:

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值