简单的快速排序算法与封装

快速排序

快速排序(Quicksort)是对冒泡排序的一种改进。由C. A. R. Hoare在1962年提出。

通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列
实现方法:
快速排序一般基于递归实现。其思路是这样的:

1.选定一个合适的值(理想情况中值最好,但实现中一般使用数组第一个值),称为“枢轴”(pivot)。

2.基于这个值,将数组分为两部分,较小的分在左边,较大的分在右边。

3.可以肯定,如此一轮下来,这个枢轴的位置一定在最终位置上。

4.对两个子数组分别重复上述过程,直到每个数组只有一个元素。

5.排序完成。

示意图:
[图片上传失败...(image-9b9105-1528258808854)]

很多实际的项目中使用了快排算法。但通常对算法都进行了调整(tuning),比如Java.util.Arrays类中的sort函数就使用了快排算法,但使用了双参考值(Dual-Pivot Quicksort)等一些改进措施。由于快排算法为递归算法,可以用循环代替递归函数调用,改进性能。

代码地址如下:

https://github.com/zhxhcoder/codeProj

具体简单实现,代码如下

public static void main(String[] args) {
    int[] arr = {0, 0, 0, 4, 5, 1, 5, 1, 5, 1, 5, 1};
    quickSort(arr, 0, arr.length - 1);
    for (int a : arr) {
        System.out.println(a);
    }
}

private static void quickSort(int[] arr, int low, int high) {
    if (low == high || low == (high - 1)) return;

    if (low < high) {
        int pivot = partition(arr, low, high);              //将数组分为两部分
        quickSort(arr, low, pivot - 1);                   //递归排序左子数组
        quickSort(arr, pivot + 1, high);                  //递归排序右子数组
    }
}

private static int partition(int[] arr, int low, int high) {
    int pivot = arr[low];     //枢轴记录
    while (low < high) {
        while (low < high && arr[high] >= pivot) --high;
        arr[low] = arr[high];             //交换比枢轴小的记录到左端
        while (low < high && arr[low] <= pivot) ++low;
        arr[high] = arr[low];           //交换比枢轴小的记录到右端
    }
    //扫描完成,枢轴到位
    arr[low] = pivot;
    //返回的是枢轴的位置
    return low;
}

以下代码是对上面的封装

//对上述快排函数原型修改,使其可以对任意对象类型数组进行排序。这个函数为内部使用,外部排序函数接口为sort(),sort函数要求对象必须实现Comparable接口,可以提供编译时类型检测,见后文。

public static void main(String[] args) {
    int[] arr = {0, 0, 0, 4, 5, 1, 5, 1, 5, 1, 5, 1};
    quickSort(arr, 0, arr.length - 1);
    for (int a : arr) {
        System.out.println(a);
    }
}

private static void quickSort(int[] arr, int begin, int end) {
    if (begin == end || begin == (end - 1)) return;

    if (begin < end) {
        int pivot = partition(arr, begin, end);              //将数组分为两部分
        quickSort(arr, begin, pivot - 1);                   //递归排序左子数组
        quickSort(arr, pivot + 1, end);                  //递归排序右子数组
    }
}

private static int partition(int[] arr, int begin, int end) {
    int pivot = arr[begin];     //枢轴记录
    while (begin < end) {
        while (begin < end && arr[end] >= pivot) --end;
        arr[begin] = arr[end];             //交换比枢轴小的记录到左端
        while (begin < end && arr[begin] <= pivot) ++begin;
        arr[end] = arr[begin];           //交换比枢轴小的记录到右端
    }
    //扫描完成,枢轴到位
    arr[begin] = pivot;
    //返回的是枢轴的位置
    return begin;
}

//使用泛型,对任意对象数组排序,该对象类型数组必须实现Comparable接口
public static > void sort(T[] input) {
    quickSort(input, 0, input.length);
}

//添加对List对象进行排序的功能,参考了Java中的Java.util.Collections类的sort()函数
public static > void sort(List list) {
    Object[] t = list.toArray();//将列表转换为数组
    quickSort(t, 0, t.length); //对数组进行排序
    //数组排序完成后再写回到列表中
    ListIterator i = list.listIterator();
    for (int j = 0; j < t.length; j++) {
        i.next();
        i.set((T) t[j]);
    }
}

//由于Java中原始数据类型(int、double、byte等)无法使用泛型,所以只能使用函数重载机制实现对这些原始类型数组(int[]、double[]、byte[]等)的排序。这里为了共用同一个排序函数,利用原始类型的(AutoBoxing,UnBoxing)机制将其封装为对应对象类型,组成新的对象数组,排序后再解封装,这样的缺点是需要额外的转换步骤、额外的空间保存封装后的数组。另一种方式是将排序代码复制到各个重载函数中,官方API中的Java.util.Arrays这个类中的sort()函数就是使用这种方法,可以从Arrays类的源代码看出。
public static void sort(int[] input) {
    Integer[] t = new Integer[input.length];
    for (int i = 0; i < input.length; i++) {
        t[i] = input[i];//封装
    }
    quickSort(t, 0, t.length);//排序
    for (int i = 0; i < input.length; i++) {
        input[i] = t[i];//解封装
    }
}

//double[]数组的重载函数
public static void sort(double[] input) {
    Double[] t = new Double[input.length];
    for (int i = 0; i < input.length; i++) {
        t[i] = input[i];
    }
    quickSort(t, 0, t.length);
    for (int i = 0; i < input.length; i++) {
        input[i] = t[i];
    }
}

//byte[]数组的重载函数
public static void sort(byte[] input) {
    Byte[] t = new Byte[input.length];
    for (int i = 0; i < input.length; i++) {
        t[i] = input[i];
    }
    quickSort(t, 0, t.length);
    for (int i = 0; i < input.length; i++) {
        input[i] = t[i];
    }
}

//short[]数组的重载函数
public static void sort(short[] input) {
    Short[] t = new Short[input.length];
    for (int i = 0; i < input.length; i++) {
        t[i] = input[i];
    }
    quickSort(t, 0, t.length);
    for (int i = 0; i < input.length; i++) {
        input[i] = t[i];
    }
}

//char[]数组的重载函数
public static void sort(char[] input) {
    Character[] t = new Character[input.length];
    for (int i = 0; i < input.length; i++) {
        t[i] = input[i];
    }
    quickSort(t, 0, t.length);
    for (int i = 0; i < input.length; i++) {
        input[i] = t[i];
    }
}

//float[]数组的重载函数
public static void sort(float[] input) {
    Float[] t = new Float[input.length];
    for (int i = 0; i < input.length; i++) {
        t[i] = input[i];
    }
    quickSort(t, 0, t.length);
    for (int i = 0; i < input.length; i++) {
        input[i] = t[i];
    }
}

//测试用的main函数
public static void main(String[] args) {
    //生产一个随机数组成的int[]数组,用来测试
    int LEN = 10;
    int[] input = new int[LEN];
    Random r = new Random();
    System.out.print("int[] before sorting: ");
    for (int i = 0; i < input.length; i++) {
        input[i] = r.nextInt(10 * LEN);
        System.out.print(input[i] + " ");
    }
    System.out.println();
    System.out.print("int[] after sorting: ");
    sort(input);
    for (int i : input) {
        System.out.print(i + " ");
    }
    System.out.println();

    //生成一个字符串数组,用来测试
    String[] s = new String[]{"b", "a", "e", "d", "f", "c"};
    System.out.print("String[] before sorting: ");
    for (int i = 0; i < s.length; i++) {
        System.out.print(s[i] + " ");
    }
    System.out.println();
    System.out.print("String[] after sorting: ");
    sort(s);
    for (int i = 0; i < s.length; i++) {
        System.out.print(s[i] + " ");
    }
    System.out.println();

    //生成一个字符串列表,用来测试
    List l = new LinkedList();
    s = new String[]{"b", "a", "e", "d", "f", "c"};
    System.out.print("LinkedList before sorting: ");
    for (int j = 0; j < s.length; j++) {
        l.add(s[j]);
        System.out.print(s[j] + " ");
    }
    System.out.println();
    sort(l);
    System.out.print("LinkedList after sorting: ");
    for (String ts : l) {
        System.out.print(ts + " ");
    }
    System.out.println();
}

你可能感兴趣的:(简单的快速排序算法与封装)