import java.util.Arrays;
/**
*
* @author Administrator
* 快速排序的思想:(1)首先判断左右哨兵的关系(break),然后选取基准数temp,然后从左向右找到小于temp的元素停下来,接着从右向左找到大于temp的元素停下来
* (2)如果左右哨兵不相等,就交换左右两个哨兵的元素
* (3)重复(1)(2),直到左右哨兵相等,将哨兵i元素和temp互换
* (4)再次重复递归
*/
public class QuickSort {
/**
*
* @param array 将要排序的数组
* @param left 数组的队首元素
* @param right 数组的队尾元素
*/
public static void quickSort(int array[],int left,int right){
int i,j,t,temp;
//相当重要,必不可少,退出递归的条件
if(left>right) return;
i = left;
j = right;
temp = array[left];
while(i != j){
//顺序很重要,先从右往左找,找到小于基准数temp的元素停下来
while(i<j && array[j]>=temp)
j--;
//再从左往右找,找到大于基准数temp的数停下来
while(i<j && array[i]<=temp)
i++;
//交换两个数在数组中的位置
if(i < j){ //当哨兵i和哨兵j没有相遇时
t = array[j];
array[j] = array[i];
array[i] = t;
}
} //end while
//最终将基准数归位,此时i=j
array[left] = array[i];
array[i] = temp;
quickSort(array, left, i-1); //继续处理左边的,这里是一个递归的过程
quickSort(array, i+1, right); //继续处理右边的,这里是一个递归的过程
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int a[] = {9,8,7,6,5,4,3,2,1};
quickSort(a, 0, 8);
System.out.println(Arrays.toString(a));
}
}
运行结果:
[1, 2, 3, 4, 5, 6, 7, 8, 9]
快速排序特点总结:
(1)最坏时间复杂度:最坏情况是每次区间划分的结果都是基准关键字的左边(或者右边)序列为空,而另一边区间中的记录项仅比排序前少一项,即选择的基准关键字是带排序的所有记录中最小或者最大的。最坏情况下时间复杂度是O(n^2).
(2)最好时间复杂度:选择的基准关键字为待排序的记录的中间值。时间复杂度为O(nlogn)
(3)平均时间复杂度:平均时间复杂度为O(nlogn)。在所有平均时间复杂度为O(nlogn)的算法中,快速排序的平均性能是最好的。
(4)空间复杂度:快速排序的实现过程中需要一个栈空间来是先递归。快排的平均空间复杂度为O(logn)
(5)基准关键字的选取。基准关键字的选取是决定快速排序算法性能的关键。常用的基准关键字的选取方式如下:
三者取中:在当前序列中,将其首、尾和中间位置上的记录进行比较,选择三者的中值作为基准关键字,在划分开始前交换序列中的第一个记录与基准关键字的位置。
取随机数:取left(左边)和right(右边)之间的一个随机数m(left<=m<=right),用n[m]作为基准关键字。这种方式使得n[left]和n[right]之间的记录时随机分布的,采用此方法得到的快速排序一般称为随机的快速排序。
快速排序与归并排序的区别于联系:
联系:快速排序和归并排序的原理都是基于“分而治之”思想,即首先把待排序的元素分成两组,然后分别对这两组排序,最后把两组结果合并起来。
区别:进行分组的策略不同,后面的合并策略也不同。
归并排序的分组策略是假设待排序的元素存放在数组中,那么其把数组前面一半元素作为一组,后面一半作为另外一组。
而快速排序则是根据元素的值来分组,即大于某个值的元素放在一组,而小于的放在另外一组,该值称为基准。
所以,对整个排序过程而言,基准值的挑选就非常重要,如果选择不合适,太大或太小,那么所有元素都分在一组了。总的来说,快速排序和归并排序,如果分组策略越简单,则后面的合并策略就越复杂,因为快速排序在分组时,已经根据元素大小来分组了,而合并时,只需把两个分组合并起来就行了,归并排序则需要对两个有序的数组根据大小合并