算法训练#7:快速排序

88 阅读4分钟

“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 9 天,点击查看活动详情 要想使用快速排序去解题,先了解一下快速排序是什么

我眼中的快速排序

快速排序是基于分治法的排序,前身是归并排序。它的大致过程是在一组无序的数字选择一个数字,把这组数字分为两边,一边小于所选数字,一边大于所选数字,然后再对这分开的两组数字重复该过程,在递归到被分开的数组数字小于等于3的时候,整个数组的排序过程就可以快速完成了,这个排序过程的时间复杂度为O(nlog2n)O(n log_{2}{n}),比一般的冒泡排序和插入排序快多了。

具体讲解

比如说对一个值为 {13,8,4,10,3,9,7,15,1,5,14,12,6,2,0,11} 的数组进行排序,我们使用快速排序把基准值(也就是在每次进行分边的过程中选择的数字)定为数组中的第一个值,那么,我们需要以第一个值为基准,用双指针的方式把数组中的值逐一对基准值进行比较

在这里基准值为13,头指针指向8,尾指针指向11 开始遍历后,我们要知道,这一次遍历过程我们要做到把小于13的值放到左边,把大于13的值放到右边,那么我们就需要把大于13和小于13的值进行交换,头、尾指针向中间遍历时,第一对要交换的值是11和15。以此类推,若头尾指针指向的值相同,那么就比较基准值与头指针指向的值,这里因为我定的基准值是第一个数,所以若基准值大于头指针指向的值,就需要进行交换(若定最后一个数为基准值则相反)。 第一次交换后是这样的

基准值为13区间为0-15
[2, 8, 4, 10, 3, 9, 7, 11, 1, 5, 0, 12, 6, 13, 14, 15]

再递归对分开的两组进行该过程

//这里按顺序给上每一轮之后的结果,大家自行验证
基准值为2区间为0-12
[2, 0, 1, 10, 3, 9, 7, 11, 4, 5, 8, 12, 6, 13, 14, 15]
基准值为2区间为0-2
[1, 0, 2, 10, 3, 9, 7, 11, 4, 5, 8, 12, 6, 13, 14, 15]
基准值为10区间为3-12
[0, 1, 2, 8, 3, 9, 7, 6, 4, 5, 10, 12, 11, 13, 14, 15]
基准值为8区间为3-9
[0, 1, 2, 4, 3, 5, 7, 6, 8, 9, 10, 12, 11, 13, 14, 15]
基准值为4区间为3-7
[0, 1, 2, 4, 3, 5, 7, 6, 8, 9, 10, 12, 11, 13, 14, 15]
基准值为5区间为5-7
[0, 1, 2, 3, 4, 5, 7, 6, 8, 9, 10, 12, 11, 13, 14, 15]
基准值为10区间为10-12
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 11, 13, 14, 15]

理解了快速排序之后,我们可以做一道题

把数组排成最小的数

思路

我的基本思路是排好序再把字符一个个拼起来。这里是要把数字拼起来的数最大,所以用普通的比较基准是行不通的,因为若要排序的话,5是要排在34后面的,所以这里我们可以使用字典序,因为在字典序比较中,先比较3跟5,3比5小,所以34在字典序的比较中是要比5小的。

代码实现

class Solution {
    public String minNumber(int[] nums) {
        String[] strs = new String[nums.length];
        for(int i = 0; i < nums.length; i++)
            strs[i] = String.valueOf(nums[i]);
        quickSort(strs, 0, strs.length - 1);
        StringBuilder res = new StringBuilder();
        for(String s : strs)//逐个拼接即可
            res.append(s);
        return res.toString();
    }
    //快速排序
    void quickSort(String[] strs, int l, int r) {
        if(l >= r) return;
        int i = l, j = r;
        String tmp = strs[i];
        while(i < j) {
            //以字典序比较
            while((strs[j] + strs[l]).compareTo(strs[l] + strs[j]) >= 0 && i < j) j--;
            while((strs[i] + strs[l]).compareTo(strs[l] + strs[i]) <= 0 && i < j) i++;
            tmp = strs[i];
            strs[i] = strs[j];
            strs[j] = tmp;
        }
        strs[i] = strs[l];
        strs[l] = tmp;
        quickSort(strs, l, i - 1);
        quickSort(strs, i + 1, r);
    }
}