快速排序分析

来源:互联网 发布:数据库 图标 编辑:程序博客网 时间:2024/06/01 09:41

前言:


刚刚学习到快速排序,快速排序是个基础问题,去网上查了下,发现竟然没有一个让人满意的答案。
就连为什么快速排序比冒泡排序快这个基本的概念,也没人说清楚。
一般而言,网上对于为什么快速排序比冒泡快,有两种方向:
1.算时间复杂度
2.二分法的优越性


对于这两种解释,明显没有从根本上触及原理。
对于1.算时间复杂度
这是逻辑颠倒,恰恰是效率高导致时间复杂度低。所以说这种解释因果倒置。
对于2.二分法的优越性
这个我不知道说什么好。

这里预先我给出我的答案:冒泡法一轮比较,只确定了一个数的位置。而快速排序,可以确定一个点的同时,还将数组一分为二。冒泡排序由于是不同的数相比较而快速排序是和相同的数比较。相当于在比较中选择了最极端的模式,浪费了信息。冒泡排序可以算是每次都是最坏选择的快速排序。(实际操作中:为提高效率,快速排序一般是一分为二,而没有确定一个点的位置)

概念:
快速排序:对一个数组操作,将数组分成两部分,前面的一部分比后面的一部分小(同组之间乱序),然后继续分割两个小数组。。。

将数组分成两部分的操作:选取数组中的一个数,从两端开始比较,左端的话如果小于就说明这个数可以放左边,比较下一个,如果大于那么先待定;右边的话,如果大于基数那么说明这个数可以放右边,比较下一个,如果小于那么和刚刚那个数对换。这样依次确认位置,就能划分完整个数组。



如何通过比较和交换位置,达到左边的都比该数小,右边的都比该数大.

这里直接给出思路:


1.单边确认
规定:需要排序的数组为arr ,选取的第一个排序数为:arr[random](r表示在数组下标范围之内的随机数)

1.if(arr[0]>arr[random]){arr[0]和arr[length-1]交换位置(此操作等于确定了数组最后一个位置的值)}
2.if(arr[0]<arr[r]){比较下一个(此操作等于确定了数组第一个位置的值)}

基于以上思路,给出代码:

public static void sort(int[] arr,int left,int right) {//设置递归结束条件if (right-left<1) {return ;}int l=left;int r=right;int sPoint=arr[left+new Random().nextInt(right-left+1)];//用随机位置确定比较的基数while (l<=r) {//使用等于为了比较每一个数if (arr[l]<=sPoint) {l++;//这里就确定了一个左边位置}else if(arr[l]>sPoint){int temp=arr[r];arr[r]=arr[l];arr[l]=temp;r--;//这里是一个交换操作,不过用往后抛形容更恰当,因为这样操作一次,右边的位置就确定了一个}}if (l-1>=0) {sort(arr, left,l-1);}sort(arr, r+1, right);}

此时我们发现:有很多交换操作是不必要的,例如:如果最后一个数是大于基数的就没必要换过来。以及对于等于的情况没有处理,所以无法排序有等值的数列。
2.双边排序+等值处理
public static void sort2(int[] arr,int left,int right) {if (right-left<1) {return ;}int l=left;int r=right;int index=left+new Random().nextInt(right-left+1);int sPoint=arr[index];//用随机位置确定比较的基数while (l<r) {while (l<=r&&arr[l]<=sPoint) {//等值处理,及:如果所有的数小于或等于基数,那么将基数移至最后,防止出现无法划分数组的情况if(l==right){if(arr[index]!=arr[right]){int temp=arr[index];arr[index]=arr[right];arr[right]=temp;}break;}l++;//这里就确定了一个左边位置}while(arr[r]>sPoint&&l<r){r--;}if (l<r) {int temp=arr[r];arr[r]=arr[l];arr[l]=temp;}}if (l-1>=0) {sort2(arr, left,l-1);}sort2(arr, l, right);}







原创粉丝点击