吾爱破解 - LCG - LSG |安卓破解|病毒分析|www.52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 1503|回复: 13
收起左侧

[Java 转载] 排序算法----快速排序遇坑史

[复制链接]
逸帅 发表于 2021-3-23 00:02
本帖最后由 逸帅 于 2021-3-23 00:05 编辑

1、项目场景:

记录一次快速排序遇坑史,周围的室友、朋友不会数据结构和算法...
无奈,今天大部分时间都在快速排序上面了

2、问题描述:

1.快速排序传值的左边索引和右边索引一直是变化的,没理解怎么变化的
2.使用了递归,递归没有加return

3、原因分析:

  1. 每次递归的左边索引和右边索引都是变化的,每次排序后,中轴值的索引,是左边元素的最右边索引,是右边元素最左边的索引,但是左边元素的左边索引,还是上次排序的左边索引,右边元素的右边索引,还是上次排序的右边索引。
    也就是说,下一次还要用到上一次的左边索引和右边索引,所以要保留这两个索引
    例如:
    第一次:左边索引是0,右边索引是length-1,中轴值假设是center,排序后,中轴值左边的元素数组称为左数组,右边的元素数组称为右数组
    第二次:左数组的左边索引还是0,但是右边索引是center-1,右数组的右边索引是length-1,左边索引是center+1

以此类推,所以左边的索引和右边的索引,每次都需要传值进去,因为一直在变化。

4、解决方案:

1、将左边的索引和右边的索引分别赋值给一个新的变量

public static void quickSort(int[] initial, int left, int right) {
        int leftIndex = left;
        int rightIndex = right;
        //取第一个数做中轴值
        int center = initial[leftIndex];

2、添加结束递归的条件

    public static void quickSort(int[] initial, int left, int right) {
        //当达到结束的条件,结束递归
        if (left >= right){
            return;
        }

5、完整的代码:

package com.yishuai.sort;

import java.util.Arrays;

/**
 * home.php?mod=space&uid=686208 yishuai
 * @description 快速排序算法
 * home.php?mod=space&uid=686237 2021/3/22 9:02 下午
 */
public class Quick {
    public static void main(String[] args) {
        int[] initial = {5, 9, 2, 8, 6, 3, 1, 4, 7};
        quickSort(initial, 0, initial.length - 1);
        System.out.println(Arrays.toString(initial));
    }

    /**
     * 快速排序算法:
     * 取第一个数做中轴值,形成一个"坑",定义左右两个索引,左边的索引从第二个数开始,右边的索引从最右边开始
     * 先从右边的索引开始寻找,找到比中轴值小的数,则放到坑中,这个数所在的地方,则变成一个新的"坑"
     * 再从左边开始寻找,找到比中轴值大的数,则放到新的坑中
     * 当左边的索引=右边的索引时,将中轴值填入到当前的坑中,结束本次排序。
     * 然后将中轴值的两遍的数,按照相同的方法,分别进行快排,直到中轴值左边的索引大于等于右边的索引
     */
    //把left和right放到参数里,是因为每次递归排序,要传入左右的索引,每次递归都是变化的
    public static void quickSort(int[] initial, int left, int right) {
        //当达到结束的条件,结束递归
        if (left >= right){
            return;
        }
        int leftIndex = left;
        int rightIndex = right;
        //取第一个数做中轴值
        int center = initial[leftIndex];

        //只要左边的索引比右边的索引小,就要一直执行下去,直到两个索引重合,则代表当前的排序结束
        while (leftIndex < rightIndex) {
            //一直循环,直到找到比中轴值小的数
            while (initial[rightIndex] > center && leftIndex < rightIndex) {
                rightIndex--;
            }
            //将比中轴值小的数放入到坑中,右边的索引所在的位置,则代表新的坑
            initial[leftIndex] = initial[rightIndex];
            while (initial[leftIndex] < center && leftIndex < rightIndex) {
                leftIndex++;
            }
            initial[rightIndex] = initial[leftIndex];
        }
        //此时initial[left]=initial[right]把中轴值填入坑中,本次排序结束
        initial[rightIndex] = center;

        //递归,把左边进行快排
        quickSort(initial, left, rightIndex - 1);
        //递归,把右边进行快排
        quickSort(initial, rightIndex + 1, right);
    }
}

免费评分

参与人数 4吾爱币 +3 热心值 +4 收起 理由
woyucheng + 1 + 1 谢谢@Thanks!
wxue + 1 + 1 谢谢@Thanks!
科西嘉滕 + 1 谢谢@Thanks!
为之奈何? + 1 + 1 我很赞同!

查看全部评分

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

 楼主| 逸帅 发表于 2021-3-23 10:00
majia4075669072 发表于 2021-3-23 09:51
我记得快排有一个变种版的,可以固定住一端不动,去追另一端,这个版本的弄起来好一点。

你写的这种两边 ...

我只看到两个,一个尚硅谷的交换法,找到左右两边符合条件的,然后两个数做交换,我感觉那样子的不是很好,就直接看挖坑法,取第一个数做中轴数的
 楼主| 逸帅 发表于 2021-3-23 09:57
zjytrhy 发表于 2021-3-23 09:14
排序算法会递归就很好理解了,归并算法也是

递归倒是理解了,卡死在两个参数的传递转换了,一直没弄懂两个索引的变更是怎么实现的,看了好久
hmhm 发表于 2021-3-23 00:15
TSW1024 发表于 2021-3-23 00:18
感谢分享经验
bookaccount 发表于 2021-3-23 05:21
这个看了N遍,好像也看懂了,就是记不住,因为实践中一次也没用到过
wuai10753 发表于 2021-3-23 07:29
谢谢分享
加奈绘 发表于 2021-3-23 08:56
感谢楼主分享,解决了我的疑惑。
zjytrhy 发表于 2021-3-23 09:14
排序算法会递归就很好理解了,归并算法也是
chen472015439 发表于 2021-3-23 09:38
感谢分享!
木头人zZ 发表于 2021-3-23 09:44
感谢楼主分享!
majia4075669072 发表于 2021-3-23 09:51
我记得快排有一个变种版的,可以固定住一端不动,去追另一端,这个版本的弄起来好一点。

你写的这种两边往中间缩的,确实有点复杂,要考虑的corner case太多了。
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则 警告:本版块禁止灌水或回复与主题无关内容,违者重罚!

快速回复 收藏帖子 返回列表 搜索

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2024-5-10 10:18

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表