1、简介
快速排序(Quicksort)是对冒泡排序的一种改进,快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
2、原理详细分析
- 从要排序的数组中选择一个参考值,一般为第一个或者最后一个,记为B,这里我们选最后一个作为参考值。
- 用一个指针L指向左边第一个,再用一个指针R指向右边起第二个(因为第一个已经作为参考值了)。
- 判断左边指针指向的值是否小于参考值,如果小于则向右移动,直到移动到L指针指向的值大于参考值则停下来;L指针停下来之后,R指针开始向右移动,直到R指针指向的值小于参考值B,则停下来;此时L和R指针都停了下来,也就意味着L>B,R<B,然后让L和R的值交换。交换之后继续移动。
- 当L指针和R指针相遇时,指针不需要再移动。1、如果共同指向的值大于参考值B,则将共同指向的值与B交换,本轮排序完成,那么本轮可确定位置的值就是L、R共同指向的值,然后以L、R共同指向的值为分界线,将左边和右边部分分成两组,分别重复以上四个步骤,即可完成排序; 2、如果共同指向的值小于参考值B,则本轮排序完成,可以确定位置的值是B,因为B在最右边,此时B右边已经没有数据了,只需要将B左边的数据重复以上四个步骤即可。
图1. 第一轮排序
图2. 递归排序
3、Java代码实现
public class QuickSort {
/**
* 快速排序
*
* @param array 待排序数组
* @param marker 标记的参考值
* @param leftIndex 左边指针所指向的索引
* @param rightIndex 右边指针所指向的索引
*/
private static void sort(int[] array, int marker, int leftIndex, int rightIndex) {
if (array.length < 2) {
return;
}
while (true) {
//左右指针指到同一个数时,一轮排序结束
if (leftIndex == rightIndex) {
//如果这个数比标记数大则交换,此时这个数为已排好的数;否则标记为排好的数
if (array[marker] < array[leftIndex]) {
change(array, marker, leftIndex);
//递归,进入下一轮排序,分别排右边和左边的
if (leftIndex < array.length - 3) {
//右边排序
sort(array, array.length - 1, leftIndex + 1, array.length - 2);
}
if (leftIndex > 1) {
//左边排序
sort(array, leftIndex - 1, 0, leftIndex - 2);
}
} else {
//标记数已排好,如【3,2,5】,标记数为5,已排好,只需要排3,2即可。
if (leftIndex > 1) {
//左边排序
sort(array, leftIndex, 0, leftIndex - 1);
}
}
//退出循环
break;
}
//如果左边指针数小于等于标记数则把指针右移(加等于是因为数组可能存在重复的数值)
if (array[leftIndex] <= array[marker]) {
leftIndex++;
continue;
}
//如果右边指针数大于等于标记数则把指针左移(加等于是因为数组可能存在重复的数值)
if (array[rightIndex] >= array[marker]) {
rightIndex--;
continue;
}
//当左边指针值大于标记数,右边指针小于标记数时,将左右指针值交换
change(array, leftIndex, rightIndex);
}
}
/**
* 交换数值
*
* @param array 数组
* @param index1 要交换的数索引
* @param index2 要交换的数索引
*/
static void change(int[] array, int index1, int index2) {
int temp = array[index1];
array[index1] = array[index2];
array[index2] = temp;
}
public static void main(String[] args) {
int[] array = {3, 5, 8, 1, 2, 9, 4, 7, 6};
sort(array, array.length - 1, 0, array.length - 2);
StringBuilder sb = new StringBuilder();
for (int i : array) {
sb.append(i);
sb.append(",");
}
System.out.println(sb.toString());
}
}
运行结果
试一下有重复数据:
运行结果: