走进数据结构之排序(四)---快速排序

xiaoxiao2021-02-27  315

一、快速排序算法分析

升序算法描述:在数据序列中选择第一个元素作为基准值,每趟从数据序列的两端开始交替进行,将小于基准值的元素交换到序列前端,将大于基准值的元素交换到序列后端,介于两者之间的位置则成为基准值的最终位置,同时,序列被划分成两个子序例,再分别对两个子序列进行快速排序,直到子序列长度为1,则完成排序。

降序,我就不多介绍了,就改改关键字眼,代码实现有降序,可以看看代码!

二、代码实现

package top.einino.swapsort;

public class QuickSort { //默认快速排序为升序状态 public static void quickSort(int[] keys){ quickSort(keys, 0, keys.length-1, true); }

//asc为true表示升序,asc为false表示升序 public static void quickSort(int[] keys, boolean asc){ quickSort(keys, 0, keys.length-1, asc); } //对存于keys数组begin-end之间的子序列进行一趟排序,递归算法。 private static void quickSort(int[] keys, int begin, int end, boolean asc) { //序列有效 if(begin>=0 && begin<keys.length && end>=0 && end<keys.length && begin<end){ //i,j下标分别从子序列的前后两端开始  int i = begin, j = end; //子序列第一个值作为基准值             int vot = keys[i]; while(i != j){ //升序(降序)是从最后一步一步向前寻找较小值(较大值),都是不移动与基准值相等元素,         while(i<j && (asc? keys[j]>=vot : keys[j]<=vot)){                     j--;                 } //子序列将后端较小元素(较大元素)向前移动,第一次移动是移动到子序列的第一个位置  if(i<j){                     keys[i++] = keys[j];                 } //升序(降序)第一次移动从子序列的第二个位置这个前方位置一步步向后寻找较大值(较小值),不移动与基准值相等元素      while(i<j &&  (asc? keys[i]<=vot : keys[i]>=vot)){                     i++;                 }

//升序(降序)第一次移动是将基准值与子序列倒着数比基准值还小(大)的位置作为替换。子序列前端较大(小)元素向后移动         if(i<j){                     keys[j--] = keys[i];                 } } //基准值到达最终位置         keys[i] = vot; System.out.print(begin + ".." + end + ", vot=" + vot + " "); print(keys); //经过一趟排序,基准值已然落到i的位置 //升序(降序)前端子序列都比基准值小(大),后端子序列都比基准值大(小) //但是两个子序列是处于无序状态 //所以得递归调用,让其成为有序,并让其各自的子序列都有序 //而且此趟的基准值也不用再参与排序。 //前端子序列再排序,递归调用      quickSort(keys, begin, i-1, asc); //后端子序列再排序,递归调到        quickSort(keys, i+1, end, asc); } }

//输出排序数组 private static void print(int[] keys) { for(int key : keys){ System.out.print(key+" "); } System.out.println(); }

public static void main(String[] args) { int[] keys = {38, 38, 97, 75, 61, 19, 26, 49}; //测试快速排序升序 quickSort(keys); int[] keys2 = {38, 38, 97, 75, 61, 19, 26, 49}; //测试快速排序降序 quickSort(keys2, false); }

三、形象的小例子

体育老师的课就是多。又来排队伍了。

初始队伍:A学生138、B学生138、C学生197、D学生175、E学生161、F学生119、G学生126、H学生149

老师开始进行排序(升序)了

首先老师把A学生拉出队伍,与后面的H学生进行比较,结果A<H,所以不改变H学生的位置

接着,与后面的G学生进行比较,结果A>H,所以老师把G学生排到A学生的位置,这时G学生的位置就空出来了

再着,与前面B学生进行比较,结果A=B,所以不改变B学生的位置

与前面C学生再进行比较,结果A<C学生,所以老师把C学生放到G学生的位置,这时C学生的位置就空出来了,此时原来C学生的后一位置并不是G学生原来的位置,所以还要继续排序

接着与后面的F学生进行比较,结果A>F,所以把F学生放到C学生原来的位置上,此时F学生的位置就空出来了

接着与前面的D学生进行比较,结果A<D,所以把D学生放到F学生原来的位置上,此时D学生的位置就空出来了

此时D学生原来的位置的后一位置还不是F学生原来的位置,还需要继续进行排序

与后面的E学生进行比较,结果A<E,所以不改变E学生的位置,继续比较

但在这时会发现,现在只能与前面D学生原来的位置被空出来的位置进行比较了,而且D学生原来的位置的接下来的位置也刚好是刚好排好序的E学生,所以就可以把基准值放到D学生原来的位置,结束排序了

最后的序列是G学生126、B学生138、F学生119、A学生138、E学生161、D学生175、C学生197、H学生149

老师接着进行前端子序列1(G学生126、B学生138、F学生119)与后端子序列2(E学生161、D学生175、C学生197、H学生149)的排序

进行前端子序列1(G学生126、B学生138、F学生119):

把G学生拉出队伍,与后面的F学生进行比较,结果G>F,所以把F学生放到G学生的位置,F学生的位置也空出来了

再与B学生进行比较,结果G<B,所以把B学生放到 原来F学生的位置,

这时会发现B学生接下来的位置就是F学生,所以就不用进行比较了,把G学生放到B学生的位置

结果前端子序列1为F学生119、G学生126、B学生138

接着进行前端子序列1的两个子序列的排序:分别是前端子序列11:F学生119、后端子序列12:B学生138,因为两个子序列的长度都只为1,所以就不用进行排序了

老师开始后端子序列2的排序(E学生161、D学生175、C学生197、H学生149):

首先把E学生拉出队伍,与H学生进行比较,结果E>H,所以把H学生放到E学生的位置,这时H学生的位置就空出来了

再与D学生进行比较,结果E<D,就把D学生放到H学生的位置,这时D学生的位置就空出来了

再与C学生进行比较,结果E<C,就不更改C学生的位置

这时由于D学生空出来的位置的下一个刚好是C学生的位置,所以就不用再进行排序了,直接把E学生放到D学生原来的位置上

结果后端子序列2的顺序为H学生149、E学生161、C学生197、D学生175

接着进行后端子序列2的两个子序列的排序,分别是:

前端子序列21:H学生149

后端子序列22:C学生197、D学生175

因为前端子序列21只有一个人,就不用再进行排序了

进行后端子序列22的排序

将C学生拉出队伍,与D学生进行比较,结果C>D,所以老师把D学生排到C学生的位置,这时发现C学生原来的位置的接下来的位置就是D学生原来的位置,所以就不用再进行排序了,把C学生放到D学生的位置,最后后端子序列22的顺序为:D学生175、C学生197

最后后端子序列2的顺序为:H学生149、E学生161、D学生175、C学生197

最后整个的排序为:

F学生119、G学生126、B学生138、A学生138、H学生149、E学生161、D学生175、C学生197

四、快速排序的时间复杂度

1、最好情况,每趟排序将序列分成长度相近的两个子序列,时间复杂度为O(n*log2(n))(log2(n)表示以2为底的n的对数,以下涉及到是一样的表示形式)

2、最坏情况,每趟排序列分成长度差异很大的两个子序列,时间复杂度为O(n^2)

五、快速排序的空间复杂度

快速排序在执行递归函数过程中花费一定的时间和空间,使用栈保存参数,栈所占用的空间与递归调用的次数有关,空间复杂度为O(log2(n)~O(n)

六、稳定性

在快速排序算法中,会错过关键字相等的比较,比如上面的例子A学生138、B学生138、但是A学生138在排序过程中,直接与后面的G学生126进行比较,直接把A学生的位置跳到B学生位置的后面,即使再遇到与B学生的比较,也不会再跳回B学生的前面了,导致关键字相等的元素在最后的结果发生的顺序的改变,所以快速算法是不稳定的。

七、小结

本博文从快速排序算法分析,升序和降序代码实现,老师排队的例子讲演,时间复杂度的2种情况,空间复杂度以及稳定性介绍了快速排序的方方面面。

如果有疑问或者对该博文有何看法或建议或有问题的,欢迎评论,恳请指正!

转载请注明原文地址: https://www.6miu.com/read-3472.html

最新回复(0)