快速排序算法的笔记博客

快速排序算法笔记



快速排序算法图解

假设原始数组 int [ ] arr = new int [7]如下:


1
2
3
5
6
7
4

选取最左边下标为0的元素 4 为基准值,使小于分界值的元素放到数组的左边,大于分界值的元素放到数组的右边。算法实现如下

在这里插入图片描述

首先定义两个索引 left 和 right分别指向数组第一个元素(此处为0)和数组最右端+1(此处为7,注意:此时,right索引已超数组长度)。


第一步:从右往左搜索,right 依次递减,找到一个比基准值小的数( arr [ - -right ] < 4 ) 为止。当right 递减 5 时,找到 。

在这里插入图片描述
第二步,从左往右搜索,left 依次递加,找到一个比基准值 大的数 (arr[ ++ left ] > 4 ) 为止。当 left 递加到 1 时,找到 。

在这里插入图片描述

第三步,交换 left , right 索引对应的值。得到数组 [ 4,1,2,3,7,5,6 ] 。然后 right 索引继续递减,寻找比基准值4 小的数。当 right 递减到 3 时,找到。

在这里插入图片描述
第四步, left 索引继续依次递加,寻找比基准值4大的数,但是未找到,就遇见 right 索引了,此时,数组中所有数都已经被寻找过一遍了,left索引不再继续递加,与 right 索引指向同一个位置。

在这里插入图片描述

第五步,交换基准值4 与 right 、 left 索引指向的3 的位置,得到如下数组。

1
2
3
4
5
6
7

4 为分界值将数组切分为两部分,得到数组1,数组2 。

在这里插入图片描述

同时4的索引设为 x (此处为3)。

1
2
3

第一个部分数组的索引为 0 到 x-1 (此处为2)。同理,选最左边下标为 0 的元素 3 为基准值,再次按上述方法进行分组。此时, right = 2 = left 。将基准值 3 和right、left一起指向的 2互换得到如下。
1
2
3


然后以3 分界线,将数组分为 [ 2,1]。因为3 右边无值。只能分成一个数组。



算法需要用到的几个方法

  1. 比较大小的方法
   public boolean compare(int c,int d,int[] arr){
       return arr[c]>arr[d];
   }
  1. 交换元素的方法
  public void exchange(int[] arr ,int a,int b ){
      int temp=0;
      temp=arr[a];
      arr[a]=arr[b];
      arr[b]=temp;
  }
  1. 递归排序方法
     public void sort(int[] arr,int l0,int r0){
        if(l0>=r0) return;//如果输入数组的最小索引l0>r0,则排序无意义,直接返回

        int bound = part(arr, l0, r0);//调用下面的数组分区方法(核心算法)

        sort(arr,l0,bound-1);//将切分掉的两个数组递归调用sort()方法
        sort(arr,bound+1,r0);
    }
  1. 数组分区方法(核心算法)
   public int part(int[] arr,int l0,int r0){
       int left=l0;//将left索引设置为输入数组的索引最小值,不一定就是0
       int right=r0+1;//将right索引设置为输入数组的索引最大值+1,此时arr[right]不存在
       while(true){
           //当right>left时,搜索才有意义。right索引自右往左找比基准值小的数。找到时,表达式为false结束循环
           // 必须写成--right,因为一开始的 arr[right]不存在,写成right--会报异常
           while (right>left&&compare(--right,l0,arr)){
               
           }
           //当left<right时,搜索才有意义,left索引自左往右找比基准值大的数,找到后,表达式为false结束循环
           while(left<right&&compare(l0,++left,arr)){
               
           }
           //当left==right时,数组中所有元素均已找过一边,交换基准值与right索引指向的值。同时退出循环
           if(right==left){
               exchange(arr,l0,right);
               break;
           }else {//数组仍未遍历完,交换值,继续循环
               exchange(arr,right,left);
           }
       }
       //返回分界值的索引
       return left;
   }


代码演示


import java.util.Arrays;

public class Demo{
    public void exchange(int[] arr ,int a,int b ){
        int temp=0;
        temp=arr[a];
        arr[a]=arr[b];
        arr[b]=temp;
    }

    public boolean compare(int c,int d,int[] arr){
        return arr[c]>arr[d];
    }

    public void sort(int[] arr,int l0,int r0){
        if(l0>=r0) return;

        int bound = part(arr, l0, r0);

        sort(arr,l0,bound-1);
        sort(arr,bound+1,r0);
    }

    public int part(int[] arr,int l0,int r0){
        int left=l0;
        int right=r0+1;
        while(true){
            while (right>left&&compare(--right,l0,arr)){
                
            }
            
            while(left<right&&compare(l0,++left,arr)){

            }
          
            if(right==left){
                exchange(arr,l0,right);
                break;
            }else {
                exchange(arr,right,left);
            }
        }
        return left;
    }

    public static void main(String[] args) {
        QuickSort qp = new QuickSort();
        int[] array={4,5,2,3,7,1,6};
        qp.sort(array,0,array.length-1);
        System.out.println(Arrays.toString(array));
    }
}

输出结果:

[1,2,3,4,5,6,7]

快速排序的时间复杂度为O(nlogn)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值