算法笔记——快速排序优化之双路快排序(Java实现)

双路快速排序算法——上接快速排序

经过我们的优化,我们的基础快速排序在大多数情况下都有着不错的表现,但是面对某些特殊情况,它依然存在着问题,下面我们来测试这样一组测试用例,我们的量级N缩小为十万量级(更大的量级可能导致递归调用过多,栈溢出而报错),但是我们的数组范围缩小至0-10,可以预见,我们的数组将包含大量的重复元素,

//测试QuickSort
public static void main(String[] args){
           
        int N = 100000;
        Integer[] arr = SortTestHelper.generateRandomArray(N, 0, 10);
        Integer[] arr1 = Arrays.copyOf(arr,arr.length);
        SortTestHelper.testSort("com.company.MergeSort2", arr);
        System.out.println();
        SortTestHelper.testSort("com.company.QuickSort",arr1);
}

测试结果

在这里插入图片描述

可以看到相对于归并排序的表现,我们的快速排序再次出现了问题,似乎又退化到了O(n2)级别

在这里插入图片描述

这是因为我们的写逻辑的时候没有处理e==v的情况,而当数组含有大量重复的元素时,无论我们将v并到<=v还是>=v中,都无可避免的会导致分组的失衡,尽管我们选的标定点可能是中间位置的,但是由于大量重复元素的不平衡分布,还是会让我们的算法退化至O(n2)级别。

这已经难在我们原有的思路上进行改进了,所以我们不妨换一种思路

在这里插入图片描述

现在我们将小于v和大于v的数组分别放在数组的两端,自然的,我们需要一个新的索引来记录大于v的一端下一个要扫描的元素的位置。

  1. 首先我们从i一端开始扫描,当扫描到的元素小于v时,我们继续向后扫描,直到我们碰到某个元素e>=v,停止
  2. 然后我们从j一端开始扫描,逻辑同上,直到我们碰到e<=v,停止
  3. 然后我们将i和j所指的元素交换位置,之后i和j继续扫描,重复以上逻辑
  4. 直到i和j所指的索引重合也就代表整个数组遍历完毕了

当然,仔细看完我们算法逻辑你会发现,图中的橙色和紫色部分分别代表的是<=v和>=v量部分元素,这也是partition2和partition的区别,我们将v分散到了小于v和大于v两部分,按照我们的逻辑,当i和j都指向v的时候,也会交换一次元素,这样就可以避免大量重复的键值集中在一边的情况,让我们的算法在面对大量重复键值也可以将其均匀的平铺开来。

源代码

import java.util.*;

public class QuickSort2Ways {
   
    // 我们的算法类不允许产生任何实例
    private QuickSort2Ways(){
   
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java中的分治算法实现快速排序的步骤如下: 1. 选择一个基准元素(pivot),可以是数组中的任意一个元素。 2. 将数组分成两部分,小于等于基准元素的放在左边,大于基准元素的放在右边。 3. 对左右两部分分别进行递归调用快速排序算法,直到每个部分只有一个元素或为空。 4. 合并左右两部分,得到最终排序结果。 下面是Java代码实现快速排序的示例: ```java public class QuickSort { public static void quickSort(int[] arr, int low, int high) { if (low < high) { int pivotIndex = partition(arr, low, high); // 获取基准元素的位置 quickSort(arr, low, pivotIndex - 1); // 对左侧子数组进行快速排序 quickSort(arr, pivotIndex + 1, high); // 对右侧子数组进行快速排序 } } private static int partition(int[] arr, int low, int high) { int pivot = arr[low]; // 选择第一个元素作为基准元素 int i = low + 1; // 左指针 int j = high; // 右指针 while (i <= j) { if (arr[i] <= pivot) { i++; } else if (arr[j] > pivot) { j--; } else { swap(arr, i, j); // 交换左右指针所指向的元素 } } swap(arr, low, j); // 将基准元素放到正确的位置上 return j; // 返回基准元素的位置 } private static void swap(int[] arr, int i, int j) { int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; } public static void main(String[] args) { int[] arr = {5, 2, 9, 1, 7, 6, 3}; quickSort(arr, 0, arr.length - 1); for (int num : arr) { System.out.print(num + " "); } } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值