Python 每日一记226>>>Java实现快速排序算法及细节的理解

一、什么是快速排序

快速排序也使用了递归,将数组按照一个基准值(这里去数组的第一个元素),进行循环操作,有两个指针,首先一个指针j从右往左循环,直到找到一个比基准值小的元素,然后停下;一个指针i从左往右循环,直到找到一个比基准值大的元素,然后停下,如果此时这两个指针i<j,就交换这这两个元素,交换完了之后,继续刚才的操作,如果右边的指针和左边的指针重合,将这个值与最开始的基准值交换,此时基准值就称之为归位,基准值的左边数据,都小于基准值,右边的数据都大于基准值,完成第一次排序;
但是此时左右两边的数据未必是有序的,因此要继续进行递归操作,直到都有序,整个数据就有序了。

关于远离可以参考以下链接,做的图很清晰:
快速排序——JAVA实现(图文并茂)

二、java实现快速排序算法

以下代码摘自https://blog.csdn.net/u014241071/article/details/81565148,小小的修改了一下。

import java.util.Arrays;

public class Test {

    //arr 需要排序的数组
    //low 开始时最左边的索引=0
    //high 开始时最右边的索引=arr.length-1
    public static void quickSort(int[] arr,int low,int high){
        int i,j,temp,t;
        //如果low>hight,不符合要求,直接返回
        if(low>high){
            return;
        }

        i=low;//左边哨兵的索引
        j=high;//右边哨兵的索引
        //temp就是基准位
        temp = arr[low];//以最左边为基准位

        //判断传入的低位索引是否小于高位索引,
        //不满足就直接结束,不再进行后续的排序操作
        //外部循环,i<j的情况下,一直循环,直到将基准位归位
        while (i<j) {

            //内部循环1,从右往左循环j,直到找到一个值比基准值大或者i>=j时退出循环
            //思考1:因为选择的是左边的值作为基准值,因此一定要从右边开始往左循环,为什么?
            //思考2:,为什么要加上条件i<j?
            while (arr[j]>=temp&&i<j) {
                j--;
            }

            //内部循环2,从左往右循环i,直到找到一个值比基准值小或者i>=j时退出循环
            //思考一下,为什么要加上条件i<j?
            //步骤和上面类似
            while (arr[i]<=temp&&i<j) {
                i++;
            }

            //能到这一步,说明i,j都已经停下来了
            //i确定了一个比基准值大的值,j确定了一个比基准值小的值,或者i>=j时退出的循环
            //接下来如果是因为确定了值而跳出了循环就,交换这两个值,如果i>=j时退出的循环,那么不用交换值,直接到将基准与i,j共同所在位置的元素交换这一步

            //思考3:内层循环都有i<j的判断了,为什么这里还要加i<j的条件?
            if (i<j) {

                //z、y 都是临时参数,用于存放左右哨兵所在位置的数据
                int z = arr[i];
                int y = arr[j];

                // 左右哨兵 交换数据(互相持有对方的数据)
                arr[i] = y;
                arr[j] = z;
            }
        }

        //这时跳出了 “while (i<j) {}” 循环,第一次的归位已经完成
        //说明 i=j 左右在同一位置
        //最后将基准与i,j共同所在位置的元素交换
        //如果i根本没动,直接是j移到基准值处,那么此时i,j,low三值在一起,根本不用交换,直接到递归那一步即可
        if(low<i){
             arr[low] = arr[i];//或 arr[low] = arr[j];
             arr[i] = temp;//或 arr[j] = temp;//temp值最开始保存了基准值
        }
        //i=j
        //这时左半数组<(i或j所在索引的数)<右半数组,但是左右数组还不一定处于有序状态
        // 只要用相同的方法 分别处理  左右数组就可以了
        //关于这里的递归的理解,后面有解释

        //递归调用左半数组
        quickSort(arr, low, j-1);
        //递归调用右半数组
        quickSort(arr, j+1, high);
    }


    public static void main(String[] args){
        //测试排序
        int[] arr = {9,8,7,6,4,2,1,10,50};
        System.out.println("排序前的数组"+ Arrays.toString(arr));
        Test.quickSort(arr, 0, arr.length-1);
        System.out.println("排序后的数组"+Arrays.toString(arr));
    }
}

三、几点需要思考的点

1、左边的值作为基准值,因此一定要右边指针从右边开始往左循环,为什么?

结束排序循环的条件是,两个指针相遇,如果左边指针先向右边循环,如果找到了一个值大于基准值,停下来了,然后右边指针开始向左循环,和这个值相遇了,那么就要将这个值和基准值交换,但是这样肯定是不对的,因为这个值大于基准值,交换后,基准值左边的数就不是全部都小于基准值的,这样是不符合要求的。
因此得出结论如果左边的值作为基准值,一定要右边指针从右边开始往左循环,可自行模拟一下,可行的。
当然如果右边的值作为基准值,要左边指针从左边开始往右循环。

2 、while (temp<=arr[j]&&i<j)和 while (temp>=arr[i]&&i<j) 为什么要加上条件i<j?

代码中while (temp<=arr[j]&&i<j),而不是while (temp<=arr[j]),为什么要要加上条件i<j呢?
如果不加上条件i<j,缺陷是很明显的,例如,我们的j在小于i的时候找到一个值小于基准值,然后i向右循环找到一个值大于基准值,此时还有必要交换两个元素的值吗?再有,他们两个还会相遇吗?所以这是不允许的。

3、内层循环都有i<j的判断了,为什么在交换元素的时候还要加i<j的条件?

内层循环都结束之后,说明i找到了一个元素大于基准值,j找到了一个元素小于基准值,但是还有一种情况那么就是i>=j时退出的循环,既然是因为i=j导致的内层循环结束,那么不用交换值,直接到将基准与i,j共同所在位置的元素交换这一步即可

四、递归流程

在这里插入图片描述
在这里插入图片描述

发布了235 篇原创文章 · 获赞 24 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/weixin_44663675/article/details/105324489
今日推荐