简介
快速排序 Qucik Sort
又称为划分交换排序。快速排序
是对冒泡排序
的一种改进方法。
在冒泡排序中,进行记录关键字的比较和交换是在相邻记录之间进行,记录每次交换只能上移或下移动一个相邻的位置,因而移动和交换的次数比较多。
为什么叫做快速排序?因为在快速排序当中,记录关键字的比较和记录的交换是从两端向中间进行的,待排序关键字较大的记录一次就能交换到后面的单元中,而关键字较小的记录一次就能交换到前面去,由于记录每次移动的距离较远,因此比较和交换的次数减少,所以叫做快速排序。
基本思想
首先在无序区 R[low...hign]
中选取一个记录作为排序为基准(可设为 x),用此基准将当前的无序区划分为两个较小的无序区 R[low..i-1]
和 R[i+1...high]
,并使左边的无序区中所有记录的关键字均小于等于基准关键字,右边的无序区大于所有的记录的关键字均大于基准关键字。而基准关键字 x 则位于最终排序的 x 上。即 R[low...i-1]
中关键字 <= x.key
<= R[i+1..high]
中的关键字。
这个过程称为一趟快速排序,当 R[low..i-1]
和 R[i+1..high]
均为非空时,分别对它们进行上述划分,直到所有的无序区中的记录均已排好序为止。
特点
快速排序
有以下特点:
快速排序
属于交换排序
- 在
快速排序
来说,一般同等值的数字每次排序的结果位置都可能不一样,所以它是不稳定的排序算法
。 - 从
快速排序
结果来说,快速排序
有着非常好的时间复杂度,它优于其他各种排序算法。对 n 个记录进行排序的平均时间复杂度为O(nlog2^n)
。 - 如果待排序的文件的记录已按关键字有序或基本有序时,反而复杂度增大。当复杂度大得离谱的时候,会由
快速排序
转变为冒泡排序
。 - 根据第四点,一般来可以进行优化。从时间上看,
快速排序
优于其他算法;从空间来看,快速排序
是递归实现的,而递归是需要栈空间来实现递归。而栈的大小取决于递归调用的深度。若一趟排序都能使待排序文件比较均匀地分割成两个子区间,则栈的最大深度为[log2^n] + 1
,即使在最坏的情况下,栈的最大深度也不会超过 n。因此,快速排序需要附加额外的空间为O(log2^n)
。
实现
public class QuickSort {
public int partion(int[] target, int i, int j) {
//选取一个地方作为对比点
int ii = target[i];
// 一次循环,包括了 右边检索 和 左边检索
while (i<j) {
//先从右边开始检索
while (i<j&&target[j] >= ii) {
j--;
}
if (i<j) {
target[i] = target[j];
i++;
}
//然后从左边开始检索
while (i<j&& target[i] <= ii) {
target[j] = target[i];
i++;
}
if (i<j) {
target[j] = target[i];
j--;
}
target[i] = ii;
return i;
}
return 0;
}
public void quickSort(int[] target, int low, int high) {
int p ;
if (low<high) {
p = partion(target, low, high);
quickSort(target, low, p-1);
quickSort(target, p+1, high);
}
}
}
测试
public Test {
public static void main(String[] args) {
int[] target = {3,14,55,14,12};
// 循环输出排序前
for (int i=0; i < target.length; i++){
System.out.println(target[i]);
}
new QuickSort().quickSort(target, 0, target.length-1);
//循环输出排序后
for (int i=0; i < target.length; i++){
System.out.println(target[i]);
}
}
}