快速排序剖析

快速排序剖析

快速排序是排序算法中最为经典,综合表现最好,也是面试中问的最多的排序算法,没有之一。所以,是不是很有必要深入理解这个算法呢。

原理:
从一组待排序的数据中,任意选择一个数作为基准。经过一定运算,达到一个状态,使基准左边的数都比基准小,基准右边的数字都比基准大。接着,用递归分治的思想,对基准左边和右边的数据分别重复上述操作,直到数据有序。

详细的步骤:
1. 任意选择一个数作为基准数,为了简单起见,一般将最左边的第1个数定为基准。
2. 新起左右两个指针,先从右指针开始依次往左找(这个很关键),直到找到一个比基准数小的数。,接着左指针开始依次往右找,直到找到一个数比基准数小。然后交换两个指针找到的数。到这里,一次交换结束。但并没完,接着进行下一次查找和交换,直到左右两个指针相遇。最后,将基准数和右指针进行交换。
3. 经过步骤2,已经达到基准左边的数都比基准小,基准右边的数都比基准大,紧接着,对左右区域的数据进行递归处理即可。

一大堆步骤,咱们来举一个例子,帮助理解,比如有一个待排序的数组:
5, 3, 2, 1, 4, 5, 6, 4, 7, 2, 9, 8

  1. 选取最左边的数作为基准,因为这样最简单,在这里5就是基准了。
  2. 左右两个指针,从两边向中间靠拢。先从右指针开始,这个是很有讲究的,下面会分析。咱们现阶段的目标是要达到一个状态,使得基准左边的数比基准小,基准右边的数比基准大。所以要把基准右边比它小的数交换到左边去,从右往左第三个数,我们找到2比基准要小,右指针暂停;接着左指针从左边第二个开始找,我们看到左边起第七个数字要比基准数5大,第一次查找结束。于是,交换两边的6和2。第一次交换结束后的状态:
    5, 3, 2, 1, 4, 5, 6, 4, 7, 2, 9, 8
    5, 3, 2, 1, 4, 5, 2, 4, 7, 6, 9, 8
    右指针继续从交换后的数字6上左移,紧接着再左移两位找到了4,暂停;又换左指针,左指针从左起第七个数字2上开始继续右移,移动一位后,与左指针相遇。然后,将第一位的基准数5和第八位的右指针所在的4进行交换。交换前后的变化为:
    5, 3, 2, 1, 4, 5, 2, 4, 7, 6, 9, 8
    4, 3, 2, 1, 4, 5, 2, 5, 7, 6, 9, 8
    经过上述运算,已经做到了,原基准5左边的数都不大于5, 5右边的数都大于5。
    接下来分别对原基准数的左右两边的数做分治递归处理,将问题化简化小,最终达到排序的目的。

以下是代码, 保证可编译可运行,经过各种测试:

package com.clb.algorithm;

import java.util.Arrays;

public class QuickSort {

    static int[] data = {5, 3, 2, 1, 4, 5, 6, 4, 7, 2, 9, 8};

    public static void main(String[] args) {
        quickSort(data, 0, data.length - 1);
        System.out.println("finally value=" + Arrays.toString(data));
    }

    private static void quickSort(int[] data, int left, int right) {
        if (left >= right) {
            return;
        }
        int j = partition(data, left, right);
        System.out.println("partition=" + j + ", value=" + data[j]);
        quickSort(data, left, j-1);
        quickSort(data, j+1, right);
    }


    private static int partition(int[] data, int left, int right) {
        int base = data[left];
        int baseIndex = left;
        while (left < right) {
            while (left < right && data[right] >= base) {
                right--;
            }

            while(left < right && data[left] <= base) {
                left++;
            }

            if (left != right) {
                swap(data, left, right);
                System.out.println("tmp Value=" + Arrays.toString(data));
            }
        }

        if (data[baseIndex] != data[right]) {
            swap(data, baseIndex, right);
            System.out.println("    Value=" + Arrays.toString(data));
        }
        return right;
    }

    private static void swap(int[] data, int i, int j) {
        int tmp = data[i];
        data[i] = data[j];
        data[j] = tmp;
    }
}

绝大多数情况下,懂原理和实现出来完全是两码事。如果只是在脑子里过过原理,也不会发现隐藏在细节里的问题。所以说,一定要多敲代码多实践。

算法中的很多细节值得推敲,到目前为止也不敢说对快排完全理解。多思考,然后断点debug对算法的理解也是大有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值