快速排序采用了一种分治策略,它的基本思想是:
- 先从数组中选取一个数作为基准数。
- 对数组进行分区,将比基准数大的数放在它的右边,小的放在左边。
- 对左右区间重复执行第二步,直到只有一个数为止。
对数组进行分区,有三种方法:
- 暴力执行,遍历数组,将比基准数小的和大的分别都放进一个新的数组,再将数组与基准数进行拼接。
- 挖坑填数法。
- 交换顺序法。
暴力法
这个方法很简单,代码先不写了。
挖坑填数法
找出基准数,在这里需要将比基准数小的放在基准数左边,把基准数大的放在基准数右边,所以需要两个变量 i 和 j 分别找到这两个类型的数,再进行操作。
数组array:
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
21 | 32 | 15 | 42 | 9 | 18 | 27 | 50 |
基准数 temp = 21,把 array[0] 放在了 temp 中,可以理解为在 array[0] 处挖个坑,然后再将其他数据填进来;
变量 j = 7 负责从右到左遍历寻找比基准数小的数;
变量 i = 0 负责从左到右遍历寻找比基准数大的数;
从上面的数组可以看出,必须先将基准数与比它小的数交换位置,所以应该先从右开始遍历;
当 j = 5 的时候,array[5] 小于 temp,符合条件,所以将它挖出来填进array[0],即array[0] = array[5],i++;
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
18 | 32 | 15 | 42 | 9 | 18 | 27 | 50 |
然后形成了一个新的坑 array[5],所以就需要找一个新的数来填坑,移动 i ,这时候用 i 从左往右遍历寻找大于基准数的数填到 array[5] 中,当 i = 1的时候,array[1] = 32,大于temp,所以执行 array[5] = array[1],j--,此时 j = 4;
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
18 | 32 | 15 | 42 | 9 | 32 | 27 | 50 |
移动 j ,以此类推,将 array[4] 填入 array[1] 的坑,array[1] = array[4],i++,此时 i = 2;
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
18 | 9 | 15 | 42 | 9 | 32 | 27 | 50 |
移动 i ,当 i = 3 的时候,array[3]大于temp,所以将它填入array[4]的坑,j--,i = 3;
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
18 | 9 | 15 | 42 | 42 | 32 | 27 | 50 |
此时i = j = 3,则遍历结束,而 array[3] 是挖了还没填的坑,因此将 temp 填进去;
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
18 | 9 | 15 | 21 | 42 | 32 | 27 | 50 |
从而左边都是小于基准数的数,右边都大于基准数。最后采用分治策略,分别对左右两边的执行相同的操作。
代码如下:
def quick_sort(a, left, right):
if(left >= right):
return
i = left
j = right
temp = a[left]
while(i != j):
while(a[j] > temp and i < j):
j -= 1
if(i < j):
a[i] = a[j]
i += 1
while(a[i] < temp and i < j):
i += 1
if(i < j):
a[j] = a[i]
j -= 1
a[i] = temp
quick_sort(a, left, i-1)
quick_sort(a, i+1, right)
return a
#调用快速排序
list = [3, 2, 4, 6, 5, 1, 7]
sorted = quick_sort(list, 0, 6)
print(sorted)
交换顺序法
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
21 | 32 | 15 | 42 | 9 | 18 | 27 | 50 |
交换顺序法同样是设置变量 i 和 j ,分别从左和右开始遍历。
j 先移动;
j 从右遍历寻找小于基准数的值,找到后也停下来, j = 5;
i 从左遍历寻找大于基准数的值,找到后就停下来, i = 1;
交换数值。
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
21 | 18 | 15 | 42 | 9 | 32 | 27 | 50 |
继续遍历,i = 3, j = 4;
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
21 | 18 | 15 | 9 | 42 | 32 | 27 | 50 |
j 继续移动,j--, 此时 j = i = 3, 停止遍历;
将 array[3] 和 temp 交换位置;
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
9 | 18 | 15 | 21 | 42 | 32 | 27 | 50 |
关于为什么从右边开始遍历:
假如从左边开始遍历,进行最后一次交换之后,左边先开始往右移动,在上面倒数第二个表格中即 i = 4,此时的 i = j = 3,将array[4] 与temp交换的话,就无法实现正确的划分了。假如从右边开始遍历,会在 i = j 的时候指向比 temp 小的值,这时候将temp 与指向的数值进行交换,便能实现正确的划分。
代码如下:
def quick_sort1(a, low, high):
if(low >= high):
return
i = low
j = high
temp = a[low]
while(i != j):
while(i < j and a[j] >= temp):
j -= 1
while(i < j and a[i] <= temp):
i += 1
if(i < j):
t = a[i]
a[i] = a[j]
a[j] = t
a[low] = a[i]
a[i] = temp
quick_sort1(a, low, i-1)
quick_sort1(a, i+1, high)
return a
#调用快速排序
list = [3, 2, 4, 6, 5, 1, 7]
sorted = quick_sort1(list, 0, 6)
print(sorted)
参考链接:
https://blog.csdn.net/MoreWindows/article/details/6684558
http://wiki.jikexueyuan.com/project/easy-learn-algorithm/fast-sort.html