快速排序
发表于:,更新于:,By Guodong
一个视频让你清晰了解快速排序的流程。
感谢博文提供的视频。
加个友情链接。http://blog.dinggangchui.cn/貌似有45秒广告,不过值得一看,过目难忘啊。
http://v.youku.com/v_show/id_XMzMyODk4NTQ4.html
算法介绍
数组为a,采用递归方式实现,子数组左右下标分别为left,right。
算法中没有讨论程序何时退出等边界条件。
- 如果left<right,选择数组关键元素key=a[left],设置两个游标i,j,初始时分别指向left和right;否则退出;
- while(a[i]>key&&i<j)j–;
- if (i < j) a[i++] = a[j];
- while (a[i] <= key && i < j) i++;
- if (i < j) a[j–] = a[i];
- 如何i<j,返回2,否则进入7;
- 最终将key元素放入a[i],也就是a[j];
- 在数组的left,i-1和数组的i+1,right区间上,重复进行1至7的递归操作。
代码实现
1 | public static void quickSort(int[] a) { |
算法精妙之处
上面的可以不看,下面的建议看看。
可能很少有人想过为什么要分别从数组的左右两端与选取的key做比较。这是一种比较难理解的方式,很多人可能为了记住算法直接把代码背下来了,但是很快忘掉。
其实比较好理解的方式是这样的:
假设我们对快排做一点修改,在元素对比的过程中,不是从左右两端分别进行对比,而是从左端开始对比,比key小的元素左移,大的元素右移,这样扫描一次数组,所有比目标元素小的都在key的坐标,反之都在右边。
这样说起来有问题吗?有。
假设数组为[5,4,3,6,7,0]。
按照上诉算法,
第1次比较后4左移[4,5,3,6,7,0],注意,是左移,不是交换。
第2次比较后3左移[4,3,5,6,7,0]。
第3次比较后6位置不变[4,3,5,6,7,0]。
第4次比较后7位置不变[4,3,5,6,7,0]。
问题来了,第5次比较时,发现0比key小,0要左移到key的左侧。由于是数组,非链表。此移动过程,需要将5,6,7右移,0放在5的位置。
如果真这样设计了,快排的时间复杂度平均起来还是o(nlogn),但是对比最开始提到的两端比较的方式,免不了多做了很多次的数组移动,这样在真是的时间消耗上,o(nlogn)前面要加上一个大大的常量系数。