\(▔^▔)/由于种种原因,很久没有写blog了,总觉得写blog的时间好长额。。。。
加上整个假期过来自己都郁闷了一点≡(▔﹏▔)≡。。。。自己趁着假期又新增了兴趣,学了一堆。。。
总觉得自己啥米都学了点可是啥米都学不精通,
所以还是回归自己最熟悉的语言Java好好学学先,至于其他兴趣再好好学学吧。
快速排序的算法复杂度最快和平均的时候都是O(nlog(n)),而且是很多复杂度为O(nlog(n))的排序算法中最快的,所以想先从这个入手说一说,像Java里面的Arrays.sort()里面用的就是快速排序。据书上有一段说法(关于java里面的Arrays.sort()方法的):
当n<=40时,它选取的基准元素是(s0,sn/2,sn-1)三者的中间值;n>40时,选取9个间隔相当的元素的中间值,当n<7时,还会切换成插入排序。
先列出源代码,再一步一步分析:
private static int partition(int[]arr,int low, int high){
int temp = arr[low];
while(low < high){
while(low=temp)
high--;
if(low
while(low
low++;
if(low
}
a[high]=temp;
return high;
}
public static void sort(int []arr){
sort(arr, 0 , arr.length);
}
private static void sort(int[]arr ,int low, int high){
if(high > low) return ;
int m = partition(arr, low, high);
sort(arr, low, m);
sort(arr, m+1, high);
}
举例,假如我们现在要排序:
arr={46,35,60,94,76,12,28};
首先取得基准元素temp=arr[0]=46,此时low=0,low
然后此时arr[low]=28<=temp,所以low++,移到35,同理low++,到60的时候跳出循环,此时60对应的值比temp大,因为arr[high]的值之前已经存到arr[low]中,所以可以放心地把60这个值放到arr[high]中。
因为此时依然符合low
那么现在arr在准备进入第一层大循环之前的值为:arr={28,35,60,94,76,12,60}
我们发现,60出现了两次,不过不用担心,最后a[high]=temp还是会被替换回去的。
第二次循环此时low从60开始,high还是从最后一个元素开始。
arr的每次结束一次循环的变化应该如下:
arr={28,35,12,94,76,94,60}
最后赋值有:arr={28,35,12,46,76,94,60}
此时可以看出基准元素46的两侧一边比它小,一边比它大,但是还是米有完全排序好的,要怎么才能排序好呢?
应该用的就是分治的一种原则啦~~~~
看程序中的sort(int []arr, int low,int high)中可以看出来,假设我们第一次sort(arr,low,m),此时相当于sort(arr,0,3),递归调用,high>low,其实觉得直接sort(arr,0,2)比较好,因为觉得没有必要把46重新放入下面的方法中(虽然放了也不会错)。还是改成sort(arr,low, m-1)比较恰当,因为左边的元素总比基准元素m小的,没有必要考虑m。
然后此时又会得到一个排序的序列,不停递归调用知道high
快排的最好和平均的时间复杂度是O(nlogn);
分析:算法复杂度其实是跟partition分出的两个子集合是否平衡有关的。在最好的情况下,每次划分都是中值的话那么每次都能划分出(n-1)/2的子集合。在n>1的时候有T(n)=2T(n/2)+O(n),所以复杂度是O(nlogn).而如果已经是排序好的序列,那么会分割出0和n-1元素的子集合,此时在n>1的时候有T(n)=T(n-1)+O(n),所以复杂度是O(n^2)