快速排序
概述
快速排序(Quicksort)是对冒泡排序的一种改进。
快速排序由C. A. R. Hoare在1960年提出。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。
简而言之,快速排序就是,先确定一个中间值,这个值通常是 第一个数字,然后将所有比它小的值放到它前面,这样,以它为中线,左右又分为不同的两组,在左右两组循环以上操作,即可完成排序。
图源:百度百科
原理
一趟快速排序的算法是:
1)设置两个变量i、j,开始的时候:i=0,j=N-1,需要排序的数组为 int[ ] A;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j–),找到第一个小于key的值A[j],将A[j]和A[i]的值交换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]的值交换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
排序演示
假设一开始序列{xi}是:5,3,7,6,4,1,0,2,9,10,8。
此时,ref=5,i=1,j=11,从后往前找,第一个比5小的数是x8=2,因此序列为:2,3,7,6,4,1,0,5,9,10,8。
此时i=1,j=8,从前往后找,第一个比5大的数是x3=7,因此序列为:2,3,5,6,4,1,0,7,9,10,8。
此时,i=3,j=8,从第8位往前找,第一个比5小的数是x7=0,因此:2,3,0,6,4,1,5,7,9,10,8。
此时,i=3,j=7,从第3位往后找,第一个比5大的数是x4=6,因此:2,3,0,5,4,1,6,7,9,10,8。
此时,i=4,j=7,从第7位往前找,第一个比5小的数是x6=1,因此:2,3,0,1,4,5,6,7,9,10,8。
此时,i=4,j=6,从第4位往后找,直到第6位才有比5大的数,这时,i=j=6,ref成为一条分界线,它之前的数都比它小,之后的数都比它大,对于前后两部分数,循环以上方法排序即可。
代码
package sort;
public class QuickSort {
public static void main(String[] args) {
// int[] array = {49, 38, 65, 97, 76, 13, 27, 49};
// int i = 0;
// int j = array.length-1;
// int[] ints = quickSort(array, i, j);
// for (int anInt : ints) {
// System.out.print(anInt + " ");
// }
int[] array = new int[80000];
for (int i = 0; i < array.length; i++) {
array[i] = (int)(Math.random()*800000);
}
int i = 0;
int j = array.length-1;
long startTime=System.currentTimeMillis();
quickSort(array, i, j);
long endTime=System.currentTimeMillis();
System.out.println("程序运行时间: "+(endTime - startTime)+"ms");
}
//快速排序排序80k长度的数组,在我这台电脑上只用了0.05秒左右,而希尔排序则需要0.09秒多
public static int[] quickSort(int[] array, int start, int end){
int i = start;
int j = end;//保存本次开始和结束的下标,方便对其操作而不改变其原数据大小
int key = array[i];//中间值通常为开始的那个数字
while (i < j){
//从后向前找,只要没找到比中间值小的数字,就继续往前找
while (i < j && array[j] >= key ){
j--;
}
//找到后退出循环,交换以j和i为下标数字的位置
int temp = array[j];
array[j] = array[i];
array[i] = temp;
//交换完,再从前向后找,直到找到比中间值大的数字,退出循环
while (i < j && array[i] <= key){
i++;
}
//找到后交换i,j的位置
temp = array[j];
array[j] = array[i];
array[i] = temp;
}
//↑结束循环,此时中间值前的数字全部小于中间值,后面的数字全部大于中间值
//判断,防止需要排序的只剩一个数字了还继续递归
if (i-1>start) {
//递归,对中间值前面的部分排序
array=qsort(array,start,i-1);
}
if (j+1<end) {
//递归,对中间值后面的部分排序
array=qsort(array,j+1,end);
}
return array;
}
}