数据结构与算法分析笔记与总结(java实现)--排序5:快速排序练习题

题目:对于一个int数组,请编写一个快速排序算法,对数组元素排序。给定一个int数组A及数组的大小n,请返回排序后的数组。测试样例:[1,2,3,5,2,3],6 [1,2,2,3,3,5]

思路:

快速排序是使用二分思想,通过递归来实现排序的。对于一个数组,它先随机选择一个元素A将数组分成两个部分,将小于元素A的元素放到数组的A的左边,将大于A的元素放到A的右边,然后再对左右两侧的子数组分别进行递归的分割排序,递归的边界条件是当最终分割得到的数组只有一个元素,即被元素A分割得到的某个数组大小是1,那么这个大小为1的数组就直接就是结果,不用再进行递归了,对于元素数目多于1的数组继续进行分割递归排序。快速排序的关键①随机元素的选取,直接决定了排序的复杂度,但是通常选取数组的中间元素作为分界元素;②已知数组array和其中的分界元素array[k],如何将数组中小于等于array[k]的元素放在其左边而将大于array[k]的元素放在其右边?这里采取的策略是,创建一个抽象的小于等于区间{}。先将array[k]与数组的最后一个元素array[length-1]进行交换,使得分界元素位于最后面,然后假设初始的小于等于array[k]的数组smallArray[]在array[0]位置的左侧,初始为空,即为{};然后使用两个指针p1,p2对数组array[]和smallArray[]进行遍历,p1初始值是0,p2初始值是-1,将array[p1]与array[k]=A进行比较,如果array[p1]>A,那么p2保持不变,p1++,表示这个元素大于A,不能放入到左侧的{}中;如果array[p1]<A,那么说明A元素小于分界值A,可以放入到左侧的{}中,此时将p2++,表示{}要开始容纳一个元素,然后将array[p2]与array[p1]进行交换,此时得到{0}5641723;然后再p1++即开始遍历下一个元素,即当遇到一个元素array[p1]<A时总是先对p2进行p2++,再将其array[p2]与array[p1]进行交换,再对p1进行p1++。即快速排序也是基于交换的,需要进行nlogn次交换。

快速排序的时间复杂度O(nlogn),空间复杂度O(1),不稳定。

采用该思路失败的代码:

import java.util.*;

//快速排序:借助二分法的思想,使用递归,选定中间元素,将小于该值的元素放到左边,大于等于的放到右边

public class QuickSort {

    public int[]quickSort(int[] A, int n) {

        //特殊输入

        if(A==null||A.length<=0)return A;

        //调用递归方法进行二分和元素的移动,完成排序

        this.adjust(A,0,A.length-1);

        return A;

}

//写一个递归的分割方法,将数组二分,然后以此元素为界将数组进行移动,小于等于的位于左边,大于等于的位于右边

    /*public voiddivide(int[] array,int start,int end){

        //递归一定要写终止的边界条件

        if(start==end)return;

        //找任意一个元素作为分界点,但是通常选择中间元素作为分界点

        int middle=(start+end)/2;

        //对当前的数组根据中间点进行分界,使得小于等于的位于左边,大于的位于右边

        this.adjust(array,start,end);

        //继续对2个子数组进行二分

       this.divide(array,start,middle);

        this.divide(array,middle+1,end);

        //调用adjust()方法将[start,end]范围内的数组以middle为界进行移动使之按照大小位于2边

        this.adjust(array,start,end);

    }

   */

    //写一个方法adjust(),将[start,end]范围内的元素按照中间值分成2个部分并调整大小,小于等于的在左,大的在右

    public voidadjust(int[] array,int start,int end){

         //递归一定要写终止的边界条件,这里的边界条件是需要分界的数组只有一个元素

        if(start==end)return;

        //显然分界元素是middle

        intmiddle=(start+end)/2;

        //核心逻辑,将小于middle的元素放到左边,大于middle的元素放到右边

        //①先将分界元素与最后的元素交换使得分界元素位于最后面

       this.swap(array,middle,end);

        //②设置指针p指向抽象的小于等于middle的数组smallArray{}456123;指针i用来遍历原始数组array,每次调整都是从0开始进行遍历调整

        int p=start-1;

        for(inti=start;i<=end;i++){

           if(array[i]<=array[end]){

                //如果元素i小于分界元素,那么就与小于等于数组区间{}的下一个元素进行交换

               swap(array,++p,i);

            }

        }

        /*

        ③本次调整结束,小于等于array[middle]值的元素全部位于数组的前列,大于的位于后面,注意,middle只是位置上面的中间,并不是大小的中间值(中位数),于是调整后的数组原来的分界值并不在中间位置,只是确保该值前面的都是小于该值的,该值后面的都是大于该值的而已。于是在此之后要继续对分界后的2个子数组进行分界排序,即对2个子数组调用递归过程。注意此时的2个子数组的分界位置是调整后的分界值所在的新位置,即上面循环过后的p的位置。于是对[start,p]和[p+1,end]进行调整

 *///假设执行adjust()方法后就完成了调整功能,即将[start,end]范围的元素进行了分界,不要考虑递归细节

       this.adjust(array,start,p);

       this.adjust(array,p+1,end);

    }

    //专门写一个辅助函数用来交换数组中的2个元素

    public voidswap(int[] array,int p1,int p2){

        inttemp=array[p1];

       array[p1]=array[p2];

        array[p2]=temp;

    }

}

对于快速排序,换成这种思路:

快速排序和归并排序一样,都采用分治的思想,先分再合,写一个divide(array,start,end)方法来对数组array中从start到end范围的数组进

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值