您的位置:首页 > 理论基础 > 数据结构算法

数据结构排序之快速排序

2014-03-26 17:22 162 查看
快速排序:在实践中最快的已知排序算法,它的平均运行时间是O(nlogn)
。该算法之所以快是因为非常精炼和高度优化的内部循环,它是冒泡排序的一种改进。它最坏的情况会退化成冒泡排序,时间复杂度是O(n*n)。但是稍加努力就会避免这种情况的发生,一会给出详细的解决办法。


快速排序思想:首先第一步选出一个支点(枢轴),通过一趟快速排序将待排序记录按照支点分割成两个独立的部分,其中一部分记录的关键字是均小于支点的,另一部分记录的关键字是均大于支点的,然后再对这两部分分别递归进行排序,直到整个序列为有序的。

JAVA实现快排的代码如下:

</pre><p><strong></strong><pre name="code" class="java">package offer.m4.sort;

/**
* 快速排序:平均时间复杂度O(nlogn),最坏时间复杂度:O(n*n)
* 思想:有一个中心抽,根据这个将数组分成两部分,一部分全部大于轴,一部分全部小于轴
* 		在对左右两边递归调用
* partition函数
* 快速排序函数
* 主函数
* @author fangjie
*
*/
public class QuickSort {

public void quickSort(int[] array,int start,int end){
if(start<end){
int midIndex = partition(array, start, end);
quickSort(array, start, midIndex-1);
quickSort(array, midIndex+1, end);
}
}

private int partition(int[] array,int start,int end){
//随机选取start与end之间的一个整数,
//防止选取某个特定的值,而且数组又是有序导致快速排序性能下降的情况
int midIndex = randomIndex(start, end);
System.out.println("start: "+start+" end: "+end +"随机数为: "+midIndex);
//选取中心值
int midValue=array[midIndex];
if(midIndex!=start){ //优化
swap(array, start, midIndex);
}
while(start<end){
while(start<end && array[end]>midValue){
end--;
}
array[start] = array[end];

while(start < end && array[start]<midValue){
start++;
}
array[end] = array[start];
}
array[start] = midValue;

return start;
}
/**
* 交换数组中指定位置的两个数
* @param array
* @param i:要交换数的下标
* @param j:要交换数的下标
*/
private void swap(int[] array,int i,int j){
if(i==j) return ;
//不使用额外空间交换两个数
array[i] = array[i]+array[j];
array[j] = array[i]-array[j];
array[i] = array[i]-array[j];
//这是使用额外空间交换两个数,这到无所谓
/*int temp =array[i];
array[i] = array[j];
array[j] = temp;*/
}
/**
* 随机选取start与end之间的数,包括start和end
* @param start
* @param end
* @return
*/
private int randomIndex(int start,int end){
return  (int)(Math.random()*(end-start))+start;
}

public void print(int[] array){
System.out.print("{");
for (int i = 0; i < array.length; i++) {
System.out.print(array[i]);
if(i!=array.length-1){
System.out.print(", ");
}
}
System.out.println("}");
}

public static void main(String[] args) {
QuickSort quickSort = new QuickSort();
System.out.println(quickSort.randomIndex(7,9));
int[] array=new int[] { 5, 3, 6, 2, 1, 9, 4, 8, 7 };
System.out.println("排序前:");
quickSort.print(array);
quickSort.quickSort(array, 0, array.length-1);
System.out.println("排序后:");
quickSort.print(array);

}
}


关于选取枢轴元的问题:

两种错误的想法:

1.直接将第一个元素作为枢纽是不好的,是没有经过充分考虑。随机输入是随机的,那么这样还是可以的,但是待排序的序列是有序的或是预排序的,那么这么做是一个非常糟糕的做法,这样就把所有的元素划分为s1或是s2中。这样快速排序花费的时间将是二次方。因此使用第一个元素作为支点是一个非常糟糕的主意。

2.另一种想法是选取前两个互异的关键字中较大的作为支点,这种和1中带来一样的不好的效果,因此也不推荐使用。

解决办法:

安全的做法是随机选取支点,这种策略比较安全。可以在网上查找三数种植分割法,看看具体怎么做。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: