文章总结:
快速排序是20世纪最重要的10大算法思想之一,也是目前公认的最快的排序算法之一,其主要思想是递归与分治,把一个复杂的问题分成多个的相同或相似的子问题,再把子问题分成更小的子问题……直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并。本文介绍了经典的快速排序与及其两个改进:双路与三路快速排序。第一次尝试这种二次元风格希望大家多多支持:)
1.经典的快速排序算法
经典的快速排序算法的基本思想是:在序列中选定一个基准值,遍历序列,将序列分为两部分,一部分大于基准值,一部分小于基准值,再递归地对这两部分数据进行快速排序,直到整个序列有序。
如图一所示,随机从序列中选择一个值作为基准值并将其放到序列的开始位置l,声明索引j与k,以闭区间[l+1:j]表示比基准值小的元素,以闭区间[j+1:k-1]表示比基准值大的元素,k表示当前遍历到元素下标,起始时两个区间中应无元素,即初始化j=l,k=l+1,初始状态如图二所示。
之后以索引k遍历序列,如图三所示,如果array[k]<B,则交换索引j与索引k指向的元素,然后移动k指向下一个元素,否则如图四所示,不需要交换位置,直接移动k至下一个元素。
一次遍历结束后,得到的序列如图五所示,需要再将基准元素放到正确位置,则交换索引l与j指向位置的元素将基准元素放置在正确位置,之后再递归排序大于基准值与小于基准值的两部分至有序即可。
1. def partition(array, l, r):
2. random_index = random.randint( l, r )
3. array[l], array[random_index] = array[random_index], array[l]
4. basic = array[l]
5. j = l # < basic:[l,j]
6. k = l + 1 # > basic:[j+1,k-1]
7. for k in range( l + 1, r + 1 ):
8. if (array[k] < basic):
9. array[j + 1], array[k] = array[k], array[j + 1]
10. j += 1
11. array[l], array[j] = array[j], array[l]
12. return j
13.
14.
15. def quickSort(array, l, r):
16. if (l > r):
17. return;
18. j = partition( array, l, r )
19. quickSort( array, l, j - 1 )
20. quickSort( array, j + 1, r )
2.双路快速排序
在经典的快速排序使用过程中,人们也发现了一些问题,比如在面临有很多重复值的情况下,经典的快速排序算法会变得很慢,原因是以其中某个值作为基准值时,由于存在多个重复元素,导致分成的两部分大小不均衡,从而使得算法的复杂度接近O(N^2),为了解决这个问题,就有了双路快速排序,双路快速排序的基本思路是:在序列中选定一个基准值,建立两个遍历索引j和k,j从头遍历到尾,k从尾遍历到头,将<=基准值的元素保存在j索引的左边,将>=基准值的元素保存在k索引的右边,从而实现了将多个重复元素分散到两部分序列中,避免了两部分大小不均衡的问题。
初始化:j=l+1,k=r
操作:如果array[j]<=B,则j++,否则交换array[j]与array[k],k--,j++
如果array[k]>=B,则k--,否则交换array[j]与array[k],k--,j++
python 代码:
1. def partition(array, l, r):
2. random_index = random.randint( l, r )
3. array[l], array[random_index] = array[random_index], array[l]
4. basic = array[l]
5.
6. j = l + 1 # <= basic:[l+1,j-1]
7. k = r # >= basic:[k+1,r]
8. while True:
9. while j <= r and array[j] < basic:
10. j += 1
11. while k >= l + 1 and array[k] > basic:
12. k -= 1
13. if j > k:
14. break
15.
16. array[j], array[k] = array[k], array[j]
17. j += 1
18. k -= 1
19. array[k], array[l] = array[l], array[k]
20. return k
21.
22.
23. def quickSort(array, l, r):
24. if l > r:
25. return
26. j = partition( array, l, r )
27. quickSort( array, l, j - 1 )
28. quickSort( array, j + 1, r )
三路快速排序
三路快排同样用于处理重复值的问题,只是与双路快排中将序列分成两部分不同,在三路快排中,将序列分为大于基准值,小于基准值与等于基准值三部分,一次递归结束后,所有等于基准值的元素找到了其正确位置,之后只需要再递归处理小于基准值与大于基准值两部分即可。
区间:<B:[l+1,j] >B:[k,r] =B:[j+1,i-1]
初始化:j=l+1,i=l+1,k=r+1
操作:如果array[i]<B,则交换array[j+1]与array[i],j++,i++
如果array[i]>B,则交换array[k-1]与array[i],k--
如果array[i]=B,则i++
python代码:
1. def partition(array, l, r):
2. random_index = random.randint( l, r )
3. array[l], array[random_index] = array[random_index], array[l]
4. basic = array[l]
5. j = l # <basic:[l+1,j]
6. k = r + 1 # >basic:[k,r]
7. i = l + 1 # =basic:[j+1,i-1]
8.
9. while (i < k):
10. if (array[i] < basic):
11. array[i], array[j + 1] = array[j + 1], array[i]
12. j += 1
13. i += 1
14. elif (array[i] > basic):
15. array[i], array[k - 1] = array[k - 1], array[i]
16. k -= 1
17. else:
18. i += 1
19.
20. array[l], array[j] = array[j], array[l]
21. return j, k
22.
23.
24. def quickSort(array, l, r):
25. if l > r:
26. return;
27.
28. j, k = partition( array, l, r )
29. quickSort( array, l, j - 1 )
30. quickSort( array, k, r )