排序算法-快速排序

5 篇文章 0 订阅
4 篇文章 0 订阅

一、10大排序算法

在这里插入图片描述
在这里插入图片描述

二、快速排序原理

快速排序为什么快的一个主要原因就是:通过选主元,进行过子集划分,主元一次性就被放到了正确的位置上了

算法思想与步骤
1.选主元,藏一边
2.进行子集划分,划分过程中会进行交换,保证主元左侧元素比主元小,右侧元素比主元大
3.对子集进行递归调用
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

三、细节问题

问题1
在这里插入图片描述
关于这个问题,我一开始认为最好情况是初始就是有序的,实际上初始有序,主元要是选一端的话时间复杂度会是O(N^2),原因可见下图:(这里的时间复杂度分析是按照递推的方法进行的,其中O(n)指每次选主元的都要遍历下数据,所以为O(n)).也就是说原先是有序的,且每次主元都选在了一端(子集划分时偏向一侧).反而是最坏的情况.
最好的情况:每次选的主元都能将序列大致等分

在这里插入图片描述

问题2
在这里插入图片描述
为什么呢?
举一个极端的例子,如果一个序列都是相等的,比如十个1,
如果交换,那么坏处是:进行了很多无畏的交换;好处:每次交换完成后,首尾的指针都会继续前进,最后两个子序列基本都是等分的,这样时间复杂度就会是O(nlog(n))
如果不交换,那么好处就是,不用进行无畏的交换了,坏处就是,主元每次都选在了一端,时间复杂度就是O(n^2)

问题3、小规模数据处理问题
快速排序的一个问题是:它使用了递归算法,递归算法层层压栈,小规模数据性能并不好.
在这里插入图片描述

四、防止栈溢出的方法

第一种是限制递归深度。一旦递归过深,超过了我们事先设定的阈值,就停止递归。
第二种是通过在堆上模拟实现一个函数调用栈,手动模拟递归压栈、出栈的过程,这样就没有了系统栈大小的限制

在这里插入图片描述
在这里插入图片描述

五、代码实现

namespace QuickSort{
    int median3(int a[],int left,int right){
//        Dump(a,10,"Median3 before : ");
        int mid=(left+right)/2;

        if(a[left]>a[right]){
            swap(a[left],a[right]);
        }
        if(a[mid]<a[left]){
            swap(a[mid],a[left]);
        }
        if(a[mid]>a[right]){
            swap(a[mid],a[right]);
        }
//        cout<<"median: "<<a[mid];//调试代码
        swap(a[mid],a[right-1]);//将主元藏在右侧(倒数第二个元素) 目的:方便后面做子集划分
//        Dump(a,10," Median3 After : ");//调试代码
        return a[right-1];
    }
    void Qsort(int a[],int left,int right){

        //递归退出条件
        if(right-left<=1){
            return;
        }
        //1.选主元
        int pivot=median3(a,left,right);
        //2.子集划分(细节1)
        int l=left;//最左侧肯定比主元小了,不用考虑了,所以下面是++l
        int r=right-1;//最右侧肯定比主元大,倒数第二个是主元,都不用考虑了,所以下面是--r
        //2.1
        while(1){
            //(细节2 ++l,--r)
            while(a[++l]<=pivot && l<r){}
            while(a[--r]>=pivot && l<r){}
            if(l<r){
                swap(a[l],a[r]);
            }else{
                break;
            }
        }
        //2.2 将主元放在正确的位置(细节3,交换的是a[right-1]小心不能写作pivot)
        swap(a[right-1],a[l]);

//        cout<<"media: "<<pivot;//调试代码
//        Dump(a,10," after put pivot: ");

        //3 递归调用左右两侧(细节4,都写成l,)
        Qsort(a,left,l);//这里是l,不能是l-1
        Qsort(a,l+1,right);//这里这里是l+1,或l都可

    }
    void Func(int a[],int size){
        if(size<=1){
            return;
        }
        Qsort(a,0,size-1);
    }
}

namespace Test{
    int arr1[]={1,0,4,3,5,9,7,2,6,8,13,12,18,15,20,24,99,33};
    int arr2[]={1,0,3};
    int arr3[]={1};
    int arr4[]={2,2,2,2,0,2,2,2};
    int arr5[]={3,3,3,3,3,3,3};
    void QuickSortTest(){
        cout<<"test1"<<endl;
        Dump(arr1,sizeof(arr1)/sizeof(int),"before:\n");
        QuickSort::Func(arr1, sizeof(arr1)/sizeof(int));
        Dump(arr1,sizeof(arr1)/sizeof(int),"after:\n");
        cout<<endl;

        cout<<"test2"<<endl;
        Dump(arr2,sizeof(arr2)/sizeof(int),"before:\n");
        QuickSort::Func(arr2, sizeof(arr2)/sizeof(int));
        Dump(arr2,sizeof(arr2)/sizeof(int),"after:\n");
        cout<<endl;

        cout<<"test3"<<endl;
        Dump(arr3,sizeof(arr3)/sizeof(int),"before:\n");
        QuickSort::Func(arr3, sizeof(arr3)/sizeof(int));
        Dump(arr3,sizeof(arr3)/sizeof(int),"after:\n");
        cout<<endl;

        cout<<"test4"<<endl;
        Dump(arr4,sizeof(arr4)/sizeof(int),"before:\n");
        QuickSort::Func(arr4, sizeof(arr4)/sizeof(int));
        Dump(arr4,sizeof(arr4)/sizeof(int),"after:\n");
        cout<<endl;

        cout<<"test5"<<endl;
        Dump(arr5,sizeof(arr5)/sizeof(int),"before:\n");
        QuickSort::Func(arr5, sizeof(arr5)/sizeof(int));
        Dump(arr5,sizeof(arr5)/sizeof(int),"after:\n");
    }
}

int main()
{
    Test::QuickSortTest();
    return 0;
}


参考:
数据结构MOOC课程

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值