第 1 章 一大波数正在靠近——排序.
最快最简单的排序——桶排序:
这个算法就好比有 11 个桶,编号从 0~10。每出现一个数,就在对应编号的桶中放一个
小旗子,最后只要数数每个桶中有几个小旗子就 OK 了。eg. 2 号桶中有 1 个小旗子,表示
2 出现了一次(还是看图最好解释O(∩_∩)O~)
![](https://i-blog.csdnimg.cn/blog_migrate/867dd1aae95250ac46cd8ae31bd4be1b.png)
最终,桶排序的时间复杂度为
O(M+N)。
def bucket_sort(lst):
buckets = [0] * ((max(lst) - min(lst))+1)
for i in range(len(lst)):
buckets[lst[i]-min(lst)] += 1
res=[]
for i in range(len(buckets)):
if buckets[i] != 0:
res += [i+min(lst)]*buckets[i]
return res
bucket_sort(lst)
邻居好说话——冒泡排序:
冒泡排序的基本思想是:每次比较两个相邻的元素,如果它们的顺序错误就把它们交换
过来。
冒泡排序每两个依次比较,直到最后一个尚未归位的数,已经归位的数则无需再进行比较(已经归位的数你还比较个啥,浪费表情)。
冒泡排序的时间复杂度是 O(N
²)
def bubble_sort(lists):
# 冒泡排序
count = len(lists)
for i in range(0, count):
for j in range(i + 1, count):
if lists[i] > lists[j]:
lists[i], lists[j] = lists[j], lists[i]
return lists
最常用的排序——快速排序:
冒泡排序解决了桶排序浪费空间的问题,但在算法的执行效率上却牺牲了很多,那有没有既不浪费空间又可以快一点的排序算法呢?那就是“快速排序”啦!
基本思想:快速排序的每一轮处理其实就是将这一轮的
基准数
归位,直到所有的数都归位为止,排序就结束了。
eg.给出 6 1 2 7 9 3 4 5 10 8,第一轮选择基准数6,如图:
![](https://i-blog.csdnimg.cn/blog_migrate/896559446bdb214ceecf2563bb0e8884.png)
![](https://i-blog.csdnimg.cn/blog_migrate/3252c0c8db8ec927485e0abacef59523.png)
![](https://i-blog.csdnimg.cn/blog_migrate/fb43e5ce748332ac23531e5187c1c1f2.png)
![](https://i-blog.csdnimg.cn/blog_migrate/a55655b2cef4192178d4f7836061635c.png)
直到3,i、j相遇,说明此次“探测”结束,交换3和基准数6,
![](https://i-blog.csdnimg.cn/blog_migrate/225332e5568c7a5b2013eb5d62def1a7.png)
到此,第一轮快速排序结束。同理,继续分别处理基准数左边和右边的。
快速排序之所以比较快,是因为相比冒泡排序,每次交换是跳跃式的。其实快速排序是基于一种叫做“二分”的思想。
def quick_sort(lists, left, right):
# 快速排序
if left >= right:
return lists
key = lists[left] # 把最左边的数赋值给k,当做基准数,
low = left
high = right
while left < right:
while left < right and lists[right] >= key:
right -= 1
lists[left] = lists[right] #把找到的比基准数小的数赋给lists[left]
while left < right and lists[left] <= key:
left += 1
lists[right] = lists[left] #此时的找到的比基准数大的数给lists[right]
lists[right] = key #直到相遇,把之前存好的基准数给这个地方
quick_sort(lists, low, left - 1) #对基准数左边的数继续排序
quick_sort(lists, left + 1, high) #对基准数右边的数继续排序
return lists