数据结构排序之快速排序
2014-03-26 17:22
162 查看
快速排序:在实践中最快的已知排序算法,它的平均运行时间是O(nlogn)
。该算法之所以快是因为非常精炼和高度优化的内部循环,它是冒泡排序的一种改进。它最坏的情况会退化成冒泡排序,时间复杂度是O(n*n)。但是稍加努力就会避免这种情况的发生,一会给出详细的解决办法。
快速排序思想:首先第一步选出一个支点(枢轴),通过一趟快速排序将待排序记录按照支点分割成两个独立的部分,其中一部分记录的关键字是均小于支点的,另一部分记录的关键字是均大于支点的,然后再对这两部分分别递归进行排序,直到整个序列为有序的。
JAVA实现快排的代码如下:
关于选取枢轴元的问题:
两种错误的想法:
1.直接将第一个元素作为枢纽是不好的,是没有经过充分考虑。随机输入是随机的,那么这样还是可以的,但是待排序的序列是有序的或是预排序的,那么这么做是一个非常糟糕的做法,这样就把所有的元素划分为s1或是s2中。这样快速排序花费的时间将是二次方。因此使用第一个元素作为支点是一个非常糟糕的主意。
2.另一种想法是选取前两个互异的关键字中较大的作为支点,这种和1中带来一样的不好的效果,因此也不推荐使用。
解决办法:
安全的做法是随机选取支点,这种策略比较安全。可以在网上查找三数种植分割法,看看具体怎么做。
。该算法之所以快是因为非常精炼和高度优化的内部循环,它是冒泡排序的一种改进。它最坏的情况会退化成冒泡排序,时间复杂度是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中带来一样的不好的效果,因此也不推荐使用。
解决办法:
安全的做法是随机选取支点,这种策略比较安全。可以在网上查找三数种植分割法,看看具体怎么做。
相关文章推荐
- 【python 数据结构 1:排序】冒泡排序和快速排序
- 数据结构学习笔记 --- 排序(冒泡排序、快速排序)
- 数据结构之交换排序之快速排序(参考整理严蔚敏数据结构)
- 数据结构--排序之快速排序(分治,递归)
- 数据结构经典排序---快速排序
- 【数据结构】排序算法(二)之交换排序之快速排序(QuickSort)
- 数据结构和算法-011 数组排序 快速排序
- 数据结构14-排序方法之快速排序的实例
- 【数据结构】排序算法(二)之交换排序之快速排序(QuickSort)
- 数据结构第三周选择排序与快速排序差别
- 数据结构 排序(快速排序)
- 数据结构例程—— 交换排序之快速排序
- 数据结构学习笔记 --- 排序(冒泡排序、快速排序)
- 数据结构学习笔记23 快速排序和基尔排序
- 【数据结构和算法之排序】快速排序
- java数据结构排序之快速排序
- 挖掘算法中的数据结构(三):O(n*logn)排序算法之 快速排序(随机化、二路、三路排序) 及衍生算法
- 图解"数据结构--内部排序算法"----交换排序:冒泡排序、快速排序
- 算法和数据结构---排序---快速排序
- 数据结构排序-交换排序-快速排序