交换排序—快速排序

八大排序
在这里插入图片描述
1.快速排序的思想
平均时间复杂度:O(n logn)
空间复杂度:O(logn)~O(n)
稳定性:不稳定×

在 A[1…n]中任取一个数据元素作为比较的“基准”(不妨记为 X),将数据区划分为左右两个部分:A[1…i-1]和

A[i+1…n],且 A[1…i-1]≤X≤A[i+1…n] (1≤i≤n),当 A[1…i-1]和 A[i+1…n]非空时,分别对它们进行上述的划分过程,直至所有数据元素均已排序为止。

2.算法实现

可以使用递归函数实现这一算法。假定待排序序列的下标范围为 low~high。

借用两个整型变量 i、j 作为指针,约定初值分别为 low、high。

排序过程:

① 选定基准 X(不妨用 A[low])

② j 向前扫描,直到 A[j],交换 A[i]与 A[j],i+1。保证了 A[low…i-1]≤X

③ i 向后扫描,直到 A[i]>X,交换 A[i]与 A[j],j-1。保证了 X≤A[j…high]

④ 继续执行②、③,直到 i=j。这时,X 恰好在 A[i]位置上。

⑤ 对序列 A[low…i-1]及 A[i+1…high]按照上述规律继续划分,直到序列为空。

仔细分析算法,我们发现,在排序中,我们总是用基准 X 与另一数据交换,因此,一趟排序结束后,X 就能确切定位其最终位置。

3.排序过程示例

待排序数据:6767145229990548771
X=67ij
扫描 jij
交换5467145229990678771
扫描 iij
交换5467145229967908771
j=i,结束i j
第一趟排序后:54671452299[67]908771
X=54, 90 扫描jijij
96714522954[67]718790
扫描iiji j
95414522967[67]718790
扫描jiji j
92914525467[67]718790
扫描ii ji j
第二趟排序后:9291452[54]67[67]7187[90]
X=9,67,71 扫描ji ji ji j
第三趟排序后:[9]291452[54676771]87[90]
X=29 ,87 扫描jiji j
[9]142952[54676771]87[90]
扫描ii ji j
第四趟排序后[9]14[29]52[546767718790]
第五趟排序后[9]142952546767718790]

4.程序代码

public class QuickSort {

    public static void main(String[] args) {
        int[]  data = {67,67,14,52,29,9,90,54,87,71};
        QuickSort qs = new QuickSort();
        qs.data = data;

        qs.print(data);
        System.out.println();
        qs.sort(0, data.length-1);
        qs.print(data);
    }

    public int[] data;
    /**
     * 每一轮比较的逻辑
     * 确定一个范围后
     * 先从后往前扫描   找小的数交换
     * 再从前往后扫描  找大的数交换
     * 一轮结束
     */
    public int quickSort(int[] data, int low, int high){
        // 选取第一个数作为key
        int key = data[low];
        while (low < high){
            // 从high位置向前扫描,直到data[high]小于key值
            while (low < high && data[high] >= key){
                high--;
            }
            // 找到第一位比key小的值  把小的值交换给key的位置
            data[low] = data[high];
            // 从low位置向后扫描, 直到有数比key大
            while (low < high && data[low] <= key){
                low++;
            }
            //  交换这个大的值给key新的位置
            data[high] = data[low];
        }
        // 第一轮完成后  key放在刚刚交换的low下标处
        data[low] = key;
        // 返回这个low下标
        return low;
    }

    /**
     * 递归调用实现多轮排序  直到low==high 递归结束  排序完成
     * @param low
     * @param high
     * @return
     */
    public int[] sort(int low, int high){
        if (low < high){
            int result = quickSort(data, low, high);
            sort(low, result-1);
            sort(result+1, high);
        }
        return data;
    }

    public void print(int[] data){
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i] + " ");
        }
    }

}

67 67 14 52 29 9 90 54 87 71 
9 14 29 52 54 67 67 71 87 90 

5.算法分析

(1)稳定性:不稳定

(2)时间复杂度:

每趟排序所需的比较次数为待排序区间的长度-1,排序趟数越多,占用时间越多。

①最坏情况:

每次划分选取的基准恰好都是当前序列中的最小(或最大)值,划分的结果 A[low…i-1]为空区间或 A[i+1…high]是空区间,且非空区间长度达到最大值。这种情况下,必须进行 n-1 趟快速排序,第 i 次趟去见长度为 n-i+1,总的比较次数达到最大值:n(n-1)/2=O(n²)

②最好情况:

每次划分所取的基准都是当前序列中的“中值”,划分后的两个新区间长度大致相等。共需 lgn 趟快速排序,总的关键字比较次数:O(nlgn)

③基准的选择决定了算法性能。经常采用选取 low 和 high 之间一个随机位置作为基准的方式改善性能。

(3)空间复杂度:快速排序在系统内部需要一个栈来实现递归,最坏情况下为 O(n),最佳情况下为 O(lgn)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值