什么是快速排序
同冒泡排序(上篇博文)一样,快速排序也属于交换排序,通过元素之间的比较与交换位置来达到排序的目的。
不同的是,冒泡排序在每一轮中只是把1个元素冒泡到数组的一端,而快速排序是:每一轮挑选一个基准元素,让比基准元素大的元素移动到数组的一边,比基准元素小的移动到数组的另外一端,从而把数组拆解成两部分。
举例说明一下,假设有如下的数组:
5 | 8 | 6 | 3 | 9 |
---|
第一轮:
1.设定基准元素: 假设以第一个元素5为基准元素
5 | 8 | 6 | 3 | 9 |
---|
2.比较: 蓝色元素为比基准元素5大的元素,绿色的为比基准元素小的元素。
5 | 8 | 6 | 3 | 9 |
---|
3.交换位置: 默认升序,比基准元素大的放左边,比基准元素小的放右边
3 | 5 | 8 | 6 | 9 |
---|
第一轮分析:
第一轮以基准元素5为界,将数组分为比5小的子集(A),和比5大的子集(B),所以接下来继续按照这样的步骤将A、B两部分子集排好就好了!!
子集A:
3 |
---|
基准元素:
5 |
---|
子集B:
8 | 6 | 9 |
---|
第二轮:
由于子集A只有一个元素,不用再排序了,子集B有三个元素,接着用上面的步骤排序:
1.设定基准元素: 假设以第一个元素8为基准元素
8 | 6 | 9 |
---|
2.比较: 蓝色元素为比基准元素8大的元素,绿色的为比基准元素小的元素。
8 | 6 | 9 |
---|
3.交换位置: 默认升序,比基准元素大的放左边,比基准元素小的放右边
6 | 8 | 9 |
---|
第二轮分析:
由于子集A只用一个元素,不用再做排序,故第二轮主要是对子集B做排序,排序结果如上图,子集B排序后,左右元素各一个,也不用再做排序,故到此为止!!!
算法复杂度
通过上面的举例可以看出,快速排序采用的是分治法的思想,这种思想的好处是什么呢?
假如我们有8个元素的数组,如果用冒泡排序的话,需要比较7轮,每一轮的把一个元素移动到数组的一端,这样的时间复杂度是O(n^2)。
而快排采用分治的思想,初始数组在每一轮都被拆成两部分,每一部分在下一轮又分别被拆成两部分,直到不可拆为止,拆分方式就如二叉树一般。
每一轮的比较和交换,需要把数组的全部元素都遍历一遍,时间复杂度是O(n),而大约需要logn轮(默认以2为底),因此快速排序算法的平均时间复杂度是O(nlogn)
代码实现(递归)
class Solution:
def quick_sort(self,data):
if len(data) >= 2: # 如果数组长度大于等于2,则进行比较
pivot = data[0] # 选取第一个元素为基准,当然随机选取最好
left, right = [], [] # 定义基准值左右两侧的列表
data.remove(pivot) # 从初始数组中移除基准值
for i in data: # 遍历
if i >= pivot: # 大于基准值的元素,放进right数组中
right.append(i)
else:
left.append(i) # 小于基准值的元素,放进left数组中
return quick_sort(left) + [pivot] + quick_sort(right) # 递归
else:
return data
if __name__== "__main__":
#验证
solution = Solution()
test = [5,8,6,3,9,2,1,7]
solution.quick_sort(test )
输出:
[1, 2, 3, 5, 6, 7, 8, 9]
代码实现(非递归)
按照算法导论中的思想:
# 算法导论里的思想,i表示[l,i]都比pivot小的元素下标, j 依次遍历元素
def quick_sort_other(array, left, right):
if left >= right:
return array
stack = [left,right]
while stack:
low = stack.pop(0)
high = stack.pop(0)
if high <= low:
continue
pivot = array[high]
i = low - 1
for j in range(low,high+1):
if array[j] <= pivot:
i += 1
array[i],array[j] = array[j],array[i]
stack.extend([low, i-1, i + 1, high])
return array
验证
输入:
array = [6,1,4,2,3,9,5]
quick_sort_other(array,0,len(array)-1)
输出:
[1, 2, 3, 4, 5, 6, 9]