快速排序采用的分治法的思想,在数据量大的时候效率极高,所以在许多情景下都能能使用到,是必须掌握的排序方法。
快速排序的基本思想是:
- 先从数列中取出一个数作为基准数(我更喜欢叫标兵)
- 进行分区,将比标兵大的数放到它右边,小于等于的数放到它的左边
- 对两个分区重复第二步,直到各分区只剩一个数时退出
在网上看的一篇博客用的是分治法加填坑法,讲的通俗易懂!将快速排序法理解为挖坑填坑的操作。假如对下面数组进行快速排序,我们来分析一下排序的过程。
0 | 1 | 2 | 3 | 4 | 5 | 6 |
65 | 23 | 88 | 12 | 77 | 69 | 26 |
首先,取第一个数为标兵,这时left=0,right=6,refer=arr[0]=65
这时refer缓存的是65,可以理解为在a[0]那里挖了个坑,后面就是填坑的操作。排序开始,right开始从后往前移动直到找到比refer小于等于的数,把这个数填到arr[0]那里,当right=6时,符合条件,于是arr[0]=arr[6],left++。这里left++是因为此时arr[left]肯定是小于refer的数了,下次就继续从下一个数开始,避免重复操作。这时arr[6]又产生了一个坑,下次轮到left从前往后找比refer(65)大的数,当left=2时,符合条件,把这个数填到arr[6]那个坑那里,arr[6]=arr[2],right--,这时arr[2]又产生一个坑。refer为65还不会变。这时left=3,right=5,不满足跳出循环的条件,继续下一轮。
0 | 1 | 2 | 3 | 4 | 5 | 6 |
26 | 23 | 88 | 12 | 77 | 69 | 88 |
现在坑在arr[2]那里,refer=65,left=3,right=5,right继续从5那里right--找比65小的数,当right=3时,符合条件,于是arr[2]=arr[3],left++。这时新坑arr[3]出现啦,但是现在left(4)>right(3),符合条件跳出了循环,arr[3]的坑还没填,于是把标兵refer的值放在arr[3]那里(标兵归位),数组变为:
0 | 1 | 2 | 3 | 4 | 5 | 6 |
26 | 23 | 12 | 65 | 77 | 69 | 88 |
这就保证arr[3]=refer=65那里,左边是比它小的数,右边是比它大的数,至此一轮排序完成。后面就继续递归调用本函数对arr[0…2]和arr[4…6]这两个子区间重复上述步骤就可以了。
对挖坑填数进行总结
- left =start; right = end; 将标兵挖出形成第一个坑arr[left]。
- right--由后向前找比它小的数,找到后挖出此数填前一个坑arr[left]中。
- left++由前向后找比它大的数,找到后也挖出此数填到前一个坑arr[right]中。
- 再重复执行b,c二步,直到left>=right,将标兵填入arr[left]中。
以下是实现代码: