快排 java实现
快排 java实现
快速排序使用分治法(Divide and conquer)策略来把一个序列(list)分为较小和较大的2个子序列,然后递归地排序两个子序列。
快排的核心思想是:将要排序的序列(假设下标是从start到end)中选任意一个数据作为pivot(分区点,也叫基准点),然后遍历数据,将小于pivot 的数据放在pivot的前面,大于等于 pivot 的数据放在pivot的后面。之后递归的将两个子序列排序。
过程如下。
这里我们给出的是原地排序的实现,也就是算法的执行过程中不需要额外的空间。
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;
}
在这里我们的分区点都是选择需要排列的数组的最后一个节点。下面有第一个分区点的获取步骤的演示,可以看看。
可以看出 i 始终指向的是数组中第一个值大于分区点的节点,j 则是遍历数组,寻找值小于分区点的节点,然后与i指向的节点交换位置,之后i++,这样当j遍历一遍数组后i左边的都是值小于分区点的,i右边都是值大于等于分区点,最后i与分区点交换位置。这样第一遍遍历就完成了。
快排是一种原地、不稳定的算法,他的时间复杂度是 O(nlogn),相比较于归并排序,快排具有空间的优势,但是他的时间复杂度并不如归并排序那么稳定,当需要排列的数组近乎有序时,我们仍选择最后一个元素作为分区点的话,快排的时间复杂度就变成了O(n2)了,