Java实现快速排序(这里提供了两种方法、递归)

14 篇文章 1 订阅
9 篇文章 0 订阅

        快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。

        快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两个子串行(sub-lists)。

        快速排序又是一种分而治之思想在排序算法上的典型应用。本质上来看,快速排序应该算是在冒泡排序基础上的递归分治法。

        快速排序的名字起的是简单粗暴,因为一听到这个名字你就知道它存在的意义,就是快,而且效率高!它是处理大数据最快的排序算法之一了。虽然 Worst Case 的时间复杂度达到了 O(n²),但是人家就是优秀,在大多数情况下都比平均时间复杂度为 O(n logn) 的排序算法表现要更好,可是这是为什么呢,我也不知道。好在我的强迫症又犯了,查了 N 多资料终于在《算法艺术与信息学竞赛》上找到了满意的答案:

快速排序的最坏运行情况是 O(n²),比如说顺序数列的快排。但它的平摊期望时间是 O(nlogn),且 O(nlogn) 记号中隐含的常数因子很小,比复杂度稳定等于 O(nlogn) 的归并排序要小很多。所以,对绝大多数顺序性较弱的随机数列而言,快速排序总是优于归并排序。

1. 算法步骤

  1. 从数列中挑出一个元素,称为 "基准"(pivot);

  2. 重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面(相同的数可以到任一边)。在这个分区退出之后,该基准就处于数列的中间位置。这个称为分区(partition)操作;

  3. 递归地(recursive)把小于基准值元素的子数列和大于基准值元素的子数列排序;

2. 代码实现

    2.1 第一种实现代码

/**
     * 实现快速排序,以最后一个数为基值
     *
     * @param arr   需要排序的数组
     * @param begin 数组的开始位置
     * @param pivot 基值下标
     */
    public static void quickSort(int[] arr, int begin, int pivot) {
        //判断数组长度是否大于1
        if (pivot - begin <= 0) {
            //如果数组长度小于等于1则返回数组
            return;
        } else {
            //如果数组长度大于1
            //先数组进行分组,比基值小的放左边,大的放右边
            int middle = Division(arr, begin, pivot);
            //对比基值小的数进行快速排序
            quickSort(arr, begin, middle - 1);
            //对比基值大的数进行快速排序
            quickSort(arr, middle + 1, pivot);
        }
    }

    /**
     * 定义一个方法将数组进行分组,以最后一个数为基值,比基值小的放左边,大的放右边
     *
     * @param arr   需要进行分组的数组
     * @param begin 数组的开始位置
     * @param pivot 基值下标
     * @return
     */
    public static int Division(int[] arr, int begin, int pivot) {
        int temp;
        //左指针
        int left = begin;
        //右指针
        int right = pivot - 1;
        while (true) {
            //从arr[left]开始遍历找到一个比arr[pivot]大的数
            while (arr[left] < arr[pivot]) {
                //比arr[pivot]小则左指针++
                left++;
            }
            //从arr[right]开始反向遍历找到一个比arr[pivot]小的数
            while (arr[right] > arr[pivot] && right > 0) {
                //比arr[pivot]大则右指针--
                right--;
            }
            //判断左右指针是否交叉
            if (left >= right) {
                //交叉则退出循环
                break;
            } else {
                //未交叉则交换arr[left]和arr[right]的位置
                swap(arr, left, right);
                //交换位置之后左指针右移,右指针左移
                left++;
                right--;
            }
        }
        //左右指针交叉之后说明已经遍历完一遍,这时把arr[pivot]与arr[left]交换位置把基值放到中间
        swap(arr, left, pivot);
        //这时比arr[pivot]小的全在左边,大的全在右边
        //此时返回arr[pivot]的下标,它的下标为left,
        // swap(arr[pivot],arr[left])这一步只是交换了它们的值,与下标无关,所以下标还是原来arr[left]的下标
        return left;
    }

    /**
     * 定义一个方法来交换数组中的两个值
     *
     * @param arr   数组
     * @param left  第一个值
     * @param right 第二个值
     */
    public static void swap(int[] arr, int left, int right) {
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
    }

    2.2第二种实现代码

/**
     * 实现快速排序,以第一个数为基值
     *
     * @param arr   需要排序的数组
     * @param pivot 基值下标
     * @param end   数组的结束位置
     */
    public static void quickSort1(int[] arr, int pivot, int end) {
        //判断数组长度是否大于1
        if (end - pivot <= 0) {
            //如果数组长度小于等于1则返回数组
            return;
        } else {
            //如果数组长度大于1
            //先数组进行分组,比基值小的放左边,大的放右边
            int middle = Division1(arr, pivot, end);
            //对比基值小的数进行快速排序
            quickSort1(arr, pivot, middle - 1);
            //对比基值大的数进行快速排序
            quickSort1(arr, middle + 1, end);
        }
    }

/**
     * 定义一个方法将数组进行分组,以第一个数为基值,比基值小的放左边,大的放右边
     *
     * @param arr   需要进行分组的数组
     * @param pivot 基值下标
     * @param end   数组的结束位置
     * @return
     */
    public static int Division1(int[] arr, int pivot, int end) {
        int temp;
        //左指针
        int left = pivot + 1;
        //右指针
        int right = end;
        while (true) {
            //从arr[left]开始遍历找到一个比arr[pivot]大的数
            while (arr[left] < arr[pivot] && left < right) {
                //比arr[pivot]小则左指针++
                left++;
            }
            //从arr[right]开始反向遍历找到一个比arr[pivot]小的数
            while (arr[right] > arr[pivot] && right > pivot) {
                //比arr[pivot]大则右指针--
                right--;
            }
            //判断左右指针是否交叉
            if (left >= right) {
                //交叉则退出循环
                break;
            } else {
                //未交叉则交换arr[left]和arr[right]的位置
                swap(arr, left, right);
                //交换位置之后左指针右移,右指针左移
                left++;
                right--;
            }
        }
        //左右指针交叉之后说明已经遍历完一遍,这时把arr[pivot]与arr[left]交换位置把基值放到中间
        swap(arr, right, pivot);
        //这时比arr[pivot]小的全在左边,大的全在右边
        //此时返回arr[pivot]的下标,它的下标为left,
        // swap(arr[pivot],arr[left])这一步只是交换了它们的值,与下标无关,所以下标还是原来arr[left]的下标
        return right;
    }

/**
     * 定义一个方法来交换数组中的两个值
     *
     * @param arr   数组
     * @param left  第一个值
     * @param right 第二个值
     */
    public static void swap(int[] arr, int left, int right) {
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
    }

    2.3测试代码及测试结果展示

public static void main(String[] args) {

        int[] arr1 = new int[]{3, 35, 33, 36, 42, 10, 141, 19, 27, 44, 26, 55};
        quickSort1(arr1, 0, arr1.length - 1);
        System.out.println(Arrays.toString(arr1));

        int[] arr = new int[]{3, 35, 33, 36, 42, 10, 141, 19, 27, 44, 26, 55};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(Arrays.toString(arr));

//        int[] arr = new int[100 * 100 ];
//        for (int i = 0; i < arr.length; i++) {
//            arr[i] = (int) (Math.random() * arr.length);
//        }
//        System.out.println(Arrays.toString(arr));
//        int[] ints = Arrays.copyOf(arr, arr.length);
//        int[] ints1 = Arrays.copyOf(arr, arr.length);
//
//        long begin = System.currentTimeMillis();
//        quickSort(ints, 0, arr.length - 1);
//        long end = System.currentTimeMillis();
//        System.out.println(end - begin);
//
//        begin = System.currentTimeMillis();
//        quickSort1(ints1, 0, arr.length - 1);
//        end = System.currentTimeMillis();
//        System.out.println(end - begin);

    }

        到这里快速排序就结束啦!有任何问题可以在评论区留言。 

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欲戴王冠♛必承其重

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值