Java基础算法(5)——快速排序

Java基础算法(5)——快速排序

1.快速排序简述

快速排序是一种分治的排序算法,由冒泡排序改进而来,冒泡排序只对相邻元素进行比较,每次相邻元素交换也只能消除一个逆序。而快速排序通过两不相邻元素的一次交换消除多个逆序,大大加快排序速度。

过程简述:以升序为例,在数组中选取切分元素(本例中选取未排序数组第一个元素),通过一次排序使其左边均小于它,右边均大于它。然后对小于它的前一部分数组和大于它的后一部分数组递归进行同样的操作,直至递归的数组只有一个元素,排序完成。

快速排序动态演示网站地址

切分元素的选取最好**保持其随机性,**使其不受对输入的依赖。

可以在排序前再随机打乱数组,然后选取其未排序数组第一个元素

在本篇文章中的示例会随机生成一个数组,切分元素也是选择未排序数组第一个元素

2.快速排序过程

以56 104 44 111 84 21 91 27 15 53 65 119 为例,

快速排序前
56 104 44 111 84 21 91 27 15 53 65 119

快速排序过程

扫描二维码关注公众号,回复: 8960584 查看本文章

最外层左递归

切分元素56 下标为0
21 53 44 15 27 56 91 84 111 104 65 119
切分元素21 下标为0
15 21 44 53 27 56 91 84 111 104 65 119
切分元素44 下标为2
15 21 27 44 53 56 91 84 111 104 65 119

最外层右递归

切分元素91 下标为6
15 21 27 44 53 56 65 84 91 104 111 119
切分元素65 下标为6
15 21 27 44 53 56 65 84 91 104 111 119
切分元素104 下标为9
15 21 27 44 53 56 65 84 91 104 111 119
切分元素111 下标为10
15 21 27 44 53 56 65 84 91 104 111 119

快速排序后
15 21 27 44 53 56 65 84 91 104 111 119

3.代码实现

3.1 简洁代码(不含注释)

代码来自《算法第四版》

 public static void sort(Comparable[] a, int low, int high) {
        if (high <= low) return;
        int pivotloc = partition(a, low, high);
        sort(a, low, pivotloc - 1);
        sort(a, pivotloc + 1, high);
    }

  private static int partition(Comparable[] a, int low, int high) {
        int i = low, j = high + 1;
        Comparable v = a[low];
        while (true) {
            while (less(a[++i], v)) if (i == high) break;
            while (less(v, a[--j])) if (j == low) break;
            if (i >= j) break;
            exch(a, i, j);
        }    
        exch(a, low, j);
        return j;
    }

3.2完整代码(包括运行实例,注释,打印信息)

package Algorithm.Sort;

/**
 * 排序(5)
 * 快速排序
 */
public class QuickSort extends Template {


    /**
     * 算法P182
     * Comparable[] a    需排序的数组
     * int low 数组头的下标
     * int high 数组尾的下标
     */
    public static void sort(Comparable[] a, int low, int high) {
        if (high <= low) return;//长度为<=1
        int pivotloc = partition(a, low, high);//pivotloc是切分元素下标,将数组一分为二
        sort(a, low, pivotloc - 1);//对左边递归 排序
        sort(a, pivotloc + 1, high);//对右边递归 排序
    }

    private static int partition(Comparable[] a, int low, int high) {
        int i = low, j = high + 1;
        Comparable v = a[low];//基准数据 这里选择数组首位(基准数据随机取)
        System.out.println("切分元素" + v + " 下标为" + low);
        while (true) {
            //选取小于切分元素的元素
            while (less(a[++i], v)) if (i == high) break;
            //选取大于于切分元素的元素
            while (less(v, a[--j])) if (j == low) break;
            if (i >= j) break;
            exch(a, i, j);
        }
        show(a);//切分元素还处于参数a首部
        exch(a, low, j);
        show(a);//切分元素正确位置
        return j;
    }


    public static void main(String[] args) {
        //Comparable[] a = Template.getData(12);
        Comparable[] a = {56, 104, 44, 111, 84, 21, 91, 27, 15, 53, 65, 119};
        System.out.println("快速排序前");

        show(a);

        System.out.println("快速排序过程");
        sort(a, 0, a.length - 1);

        assert isSorted(a);
        System.out.println("快速排序后");
        show(a);

    }

}

4.理解代码

4.1 理解代码——拆解第一趟排序

 private static int partition(Comparable[] a, int low, int high) {
        int i = low, j = high + 1;
        Comparable v = a[low];
        while (true) {
            while (less(a[++i], v)) if (i == high) break;
            while (less(v, a[--j])) if (j == low) break;
            if (i >= j) break;
            exch(a, i, j);
        }    
        exch(a, low, j);
        return j;
    }

partition(Comparable[] a, int low, int high)

函数参数:需要排序的数组a,a的第一个下标,a的最后一个下标

返回值:切分元素的下标

此函数做的事情就是使数组中切分元素左边均小于它,右边均大于它

举例:56 104 44 111 84 21 91 27 15 53 65 119

以第一趟排序为例,在这个例子中是将切分元素56左边均小于它,右边均大于它:

做了一张ppt如下

在这里插入图片描述

新建一个Comparable变量 v 暂存切分元素,v = a[low],这里切分元素即56 。

代码中以int i = low, j = high + 1开始,只是为了后面代码的简洁性,在while循环中**++i --j**可以看到,其实第一次使用下标i和j的时候还是以i = low, j = high + 1开始。

while循环中:

  1. 从下标为切分元素(56)的后一个元素开始向右遍历,即从i=low+1遍历,找大于切分元素(56)的元素。(条件:i还没有遍历到high)
  2. 从数组a最后一个元素开始向左遍历,即从j=high遍历,找小于切分元素(56)的元素。(条件:i还没有遍历到high)
  3. 交换上述步骤1,步骤2的元素。(条件:i小于j,即它两还在往中间凑,没碰到一起)

通过while循环的这些步骤,104与53交换 111与15交换 84与27交换
红框里面的那对数组 21 和 91并没有交换 因为此时i大于j

while循环后,交换切分元素(56)与下标为j的元素是因为:此时 a[i]=91 a[j]=21 21<56<91,切分元素最终应当放在91前且21后才能保证切分元素(56)左边均小于它,右边均大于它。

此时的数组:

56 53 44 15 27 21 91 84 111 104 65 119

a[low+1]到a[j]均小于切分元素(56) a[i]到a[high]均大于切分元素(56)

交换 a[j]=21与a[low]=56即可达到切分元素(56)左边均小于它,右边均大于它的目的

21 53 44 15 27 56 91 84 111 104 65 119

这样,第一趟排序就完成了。

4.2 理解代码——递归

public static void sort(Comparable[] a, int low, int high) {
        if (high <= low) return;//长度为<=1
        int pivotloc = partition(a, low, high);//pivotloc是切分元素下标,将数组一分为二
        sort(a, low, pivotloc - 1);//对左边递归 排序
        sort(a, pivotloc + 1, high);//对右边递归 排序
    }

sort(Comparable[] a, int low, int high)

函数参数:需要排序的数组a,a的第一个下标,a的最后一个下标

第一趟排序完成后,此时元素56左边均小于它,右边均大于它,利用此时56元素的下标进行递归操作

pivotloc即此时切分元素(56)的下标。

此时切分元素左边和切分元素右边均可看作无须数组。

a[low]到a[pivotloc-1] 切分元素左边的无序数组

a[pivotloc+1]到a[high] 切分元素右边的无序数组

对这两者再排序即可,直至只有一个元素(high <= low)。

sort(a, low, pivotloc - 1);//对左边递归 排序
sort(a, pivotloc + 1, high);//对右边递归 排序

发布了67 篇原创文章 · 获赞 32 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/qq_42391904/article/details/100859561