快速排序本质上是一种分治算法。
- 不稳定排序:相同元素的相对次序在排序后会发生变化(swap这个动作)
其基本流程如下:
- 确定分界点:一般是中间点(l + r) / 2、(l + r + 1) / 2,或随机值。
- 调整区间:小于分界点x的在左边,大于分界点y的在右边。
- 递归处理左右两段。
整体程序如下:
|
|
- 分界点和递归左右两段的选择
分界点取中间(l + r) / 2时,递归处理左右两段应该是[l, j]和[j+1, r]
分界点取中间(l + r + 1) / 2时,递归处理左右两段应该是[l, i-1]和[i, r]
比如一下样例:
|
|
对于第一种情况:
分界点:(l + r) / 2 = (0 + 1) / 2 = 0
第一次调用完 quick_sort
后(调整区间[0, 1]),i = 0,j = 0
若是递归的区间为[l, i-1]和[i, r],则是[0, -1]和[0, 1];此时将永远按[0, 1]递归下去。
若是递归的区间为[l, j]和[j+1, r],则是[0, 0]和[1, 1];此时将碰到递归的终止条件。
对于第二种情况:
分界点:(l + r + 1) / 2 = (0 + 1 + 1) / 2 = 1
第一次调用完 quick_sort
后(调整区间[0, 1]),i = 1,j = 1
若是递归的区间为[l, i-1]和[i, r],则是[0, 0]和[1, 1];此时将碰到递归的终止条件。
若是递归的区间为[l, j]和[j+1, r],则是[0, 1]和[2, 1];此时将永远按[0, 1]递归下去。
综上,快排最难的还是避免无限递归,需要牢牢记住:
分界点取中间(l + r) / 2时,递归处理左右两段应该是[l, j]和[j+1, r]
分界点取中间(l + r + 1) / 2时,递归处理左右两段应该是[l, i-1]和[i, r]