算法设计与分析之分而治之篇(2)

一、回顾

  • 分而治之框架
    • 分解原问题
    • 解决子问题
    • 合并问题解
  • 归并排序
    • 将数组分解为一个一个只有一个元素的小数组,这些单元素小数组只有一个元素,天然便是有序的,这样一来我们就可以递归的合并这些小数组,直到排好序。
  • 在前面我们分而治之策略的问题大部分都侧重于合并问题解的部分,今天我们说的问题则简化了合并部分,侧重分解问题。

二、快速排序

  • 基本思想
    • 任选元素x作为分界线,称为主元
    • 交换重排,满足x左侧元素小于右侧

  •  实现方法
    • 选取固定位置主元x
    • 维护两个部分右端点变量i,j
    • 考察数组元素A[j],只和主元比较
      • A[j] \leq x,则交换A[j]和A[i+1],i,j右移
      • A[j]>x,则j右移
    • 最后将主元放在中间作为分界线

  •  算法实例

  •  复杂度分析

  •  我们分析最坏情况是如何产生的:我们之前每次都将末尾元素作为主元,如果每次我们划分后除了主元外的其余元素都在主元一侧。这种情况是非常罕见的,是针对性构造的,为了避免这种问题,我们每次可以随机选择主元,这样就无法针对性的构造最差情况。

  •  快速排序代码实现
package com.tiger.study;


// 快速排序:有一个数组,我们选择一个主元(可以固定的选,也可以随机选),然后我们将主元右边全部放置比主元小的数,左边放置比主元大的数,递归求解,最终合并就是有序的


import java.util.Random;

public class QuickSort {
    public static void main(String[] args) {
        int[] arr = {2, 6, 7, 1, 3, 5, 6, 4};
//        int[] arr = {4, 3, 2, 1};
        quickSort(arr, 0, arr.length - 1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }

        System.out.println("=====");
        quickSortRandom(arr, 0, arr.length - 1);
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }

    // 固定主元
    private static void quickSort(int[] arr, int left, int right) {
        if (left >= right) return;
        int mainEleIndex = partition(arr, left, right);
        quickSort(arr, left, mainEleIndex - 1);
        quickSort(arr, mainEleIndex + 1, right);
    }

    private static int partition(int[] arr, int left, int right) {
        int mainEleIndex = right;
        int i = left - 1, j = left;
        while (j < right) {
            if (arr[mainEleIndex] > arr[j]) {
                int temp = arr[i + 1];
                arr[i + 1] = arr[j];
                arr[j] = temp;
                j++;
                i++;
            } else {
                j++;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[mainEleIndex];
        arr[mainEleIndex] = temp;
        return i + 1;
    }

    // 随机主元
    private static void quickSortRandom(int[] arr, int left, int right) {
        if (left >= right) return;
        int mainEleIndex = partitionRandom(arr, left, right);
        quickSort(arr, left, mainEleIndex - 1);
        quickSort(arr, mainEleIndex + 1, right);
    }

    private static int partitionRandom(int[] arr, int left, int right) {
        Random random = new Random();
        int mainEleIndex = left + random.nextInt(right - left + 1);
        int i = left - 1, j = left;
        while (j < right) {
            if (arr[mainEleIndex] > arr[j]) {
                int temp = arr[i + 1];
                arr[i + 1] = arr[j];
                arr[j] = temp;
                j++;
                i++;
            } else {
                j++;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[mainEleIndex];
        arr[mainEleIndex] = temp;
        return i + 1;
    }
}

 三、第k小的数

  • 问题描述:找到给定数组中的第k小的数
package com.tiger.study;


// 问题描述:寻找数组中第k小的元素

public class SerachKMinValue {
    public static void main(String[] args) {
        int[] arr = {21, 17, 37, 28, 13, 14, 22, 52, 40, 24, 48, 24, 48, 4, 47, 8, 42, 18};
        System.out.println(findKthMinValue(arr, 0, arr.length - 1, 5));
    }

    private static int findKthMinValue(int[] arr, int left, int right, int k) {
        int x;
        int mainValueIndex = partition(arr, left, right);
        if (k == (mainValueIndex - left + 1)) {
            x = arr[mainValueIndex];
        } else if (k < (mainValueIndex - left + 1)) {
            x = findKthMinValue(arr, left, mainValueIndex - 1, k);
        } else {
            x = findKthMinValue(arr, mainValueIndex + 1, right, k - (mainValueIndex - left + 1));
        }
        return x;
    }

    private static int partition(int[] arr, int left, int right) {
        int mainValueIndex = right;
        int i = left - 1, j = left;
        while (j < right) {
            if (arr[j] < arr[mainValueIndex]) {
                int temp = arr[i + 1];
                arr[i + 1] = arr[j];
                arr[j] = temp;
                i++;
                j++;
            } else {
                j++;
            }
        }
        int temp = arr[i + 1];
        arr[i + 1] = arr[mainValueIndex];
        arr[mainValueIndex] = temp;
        return i + 1;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值