快排 java实现

快排 java实现

快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。

快排的核心思想是:将要排序的序列(假设下标是从start到end)中选任意一个数据作为pivot(分区点,也叫基准点),然后遍历数据,将小于pivot 的数据放在pivot的前面,大于等于 pivot 的数据放在pivot的后面。之后递归的将两个子序列排序。

过程如下。

快排1.PNG

这里我们给出的是原地排序的实现,也就是算法的执行过程中不需要额外的空间。

public class Quick {
    // 快速排序,a是数组,n表示数组的大小
    public static void quickSort(int[] a, int n) {
        quickSortInternally(a, 0, n - 1);
    }

    // 快速排序递归函数
    private static void quickSortInternally(int[] a, int start, int end) {
        if (start >= end) {
            return;
        }

        int q = partition(a, start, end); // 获取分区点
        quickSortInternally(a, start, q - 1);
        quickSortInternally(a, q + 1, end);
    }
}

上面的这个是递归实现的,可以看出跟归并排序的代码有点相似,这里最主要的就是分区点的获取。

private static int partition(int[] a, int start, int end) {
    int pivot = a[end];
    int i = start;
    for (int j = start; j < end; ++j) {
        if (a[j] < pivot) {
            if (i == j) {
                ++i;
            } else {
                swap(a, i, j);
                ++i;
            }
        }
    }
    swap(a, i, end);
    return i;
}

public static void swap(int[] a, int i, int j) {
    int tmp = a[i];
    a[i] = a[j];
    a[j] = tmp;
}

在这里我们的分区点都是选择需要排列的数组的最后一个节点。下面有第一个分区点的获取步骤的演示,可以看看。

快排.gif

可以看出 i 始终指向的是数组中第一个值大于分区点的节点,j 则是遍历数组,寻找值小于分区点的节点,然后与i指向的节点交换位置,之后i++,这样当j遍历一遍数组后i左边的都是值小于分区点的,i右边都是值大于等于分区点,最后i与分区点交换位置。这样第一遍遍历就完成了。

快排是一种原地、不稳定的算法,他的时间复杂度是 O(nlogn),相比较于归并排序,快排具有空间的优势,但是他的时间复杂度并不如归并排序那么稳定,当需要排列的数组近乎有序时,我们仍选择最后一个元素作为分区点的话,快排的时间复杂度就变成了O(n2)了,

猜你喜欢

转载自www.cnblogs.com/youch/p/10951363.html