【算法】快速排序

追求适度,才能走向成功;人在顶峰,迈步就是下坡;身在低谷,抬足既是登高;弦,绷得太紧会断;人,思虑过度会疯;水至清无鱼,人至真无友,山至高无树;适度,不是中庸,而是一种明智的生活态度。

导读:本篇文章讲解 【算法】快速排序,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

在这里插入图片描述

一、单边循环快排(lomuto洛穆托分区方案)

原理说明:

  1. 选择最右元素作为基准点元素
  2. j指针负责找到比基准点小的元素,一旦找到则与i进行交换
  3. i指针维护小于基准点元素的边界,也是每次交换的目标索引
  4. 最后基准点与i交换,i即为分区位置

代码实现:

package com.demo.controller;

import java.util.Arrays;

/**
 * @Author: JYC
 * @Title: demo
 * @Description: TODO
 * @Date: 2022/8/9 20:10
 */
public class QuickSort1 {
    public static void main(String[] args) {
        int[] a = {5, 3, 7, 2, 9, 8, 1, 4};
        quick(a, 0, a.length - 1);
    }

    public static void quick(int[] a, int l, int h) {
        if (l >= h) {
            return;
        }
        int p = partition(a, l, h); // p 索引值
        quick(a, l, p - 1); // 左边分区的范围确定
        quick(a, p + 1, h); // 右边分区的范围确定
    }

    private static int partition(int[] a, int l, int h) {
        int pv = a[h]; // 基准点元素
        int i = l;
        for (int j = l; j < h; j++) {
            if (a[j] < pv) {
                swap(a, i, j); // 自定义的交换方法,将i、j互换
                i++;
            }
        }
        swap(a, h, i);
        System.out.println(Arrays.toString(a) + " i = " + i);
        // 返回值代表了基准点元素所在的正确索引,用它确定下一轮分区的边界
        return i;
    }

    public static int[] swap(int[] a, int i, int j) {
        int k = a[i];
        a[i] = a[j];
        a[j] = k;
        return a;
    }
}

运行结果:
在这里插入图片描述

二、双边循环快排(并不完全等价于hoare霍尔分区方案)

原理说明:

  1. 选择最左元素作为基准点元素
  2. j指针负责从右向左找比基准点小的元素,i指针负责从左向右找比基准点大的元素,一旦找到二者交换,直至i,j相交
  3. 最后基准点与i(此时i与j相等)交换,i即为分区位置

代码实现:

package com.demo.controller;

import java.util.Arrays;

/**
 * @Author: JYC
 * @Title: demo
 * @Description: TODO
 * @Date: 2022/8/9 20:10
 */
public class QuickSort1 {
    public static void main(String[] args) {
        int[] a = {5, 3, 7, 2, 9, 8, 1, 4};
        quick(a, 0, a.length - 1);
    }

    public static void quick(int[] a, int l, int h) {
        if (l >= h) {
            return;
        }
        int p = partition(a, l, h); // p 索引值
        quick(a, l, p - 1); // 左边分区的范围确定
        quick(a, p + 1, h); // 右边分区的范围确定
    }

    private static int partition(int[] a, int l, int h) {
        int pv = a[l]; // 基准点元素
        int i = l;
        int j = h;
        while (i < j) {
            // j 从右找小的
            while (i < j && a[j] > pv) {
                j--;
            }
            // i 从左找大的
            while (i < j && a[i] <= pv) {
                i++;
            }
            swap(a, i, j);
        }
        swap(a, l, j);
        System.out.println(Arrays.toString(a) + "j = " + j);
        // 返回值代表了基准点元素所在的正确索引,用它确定下一轮分区的边界
        return j;
    }

    public static int[] swap(int[] a, int i, int j) {
        int k = a[i];
        a[i] = a[j];
        a[j] = k;
        return a;
    }
}

注意要点:

  1. 基准点在左边,并且要先 j 后 i
  2. while (i < j && a[j] > pv) j–
  3. while (i < j && a[i] <= pv) i++
    运行结果:
    在这里插入图片描述

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/131147.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!