排序算法在算法界是一个怎么样的存在?就好像在学术界中数学的地位,说直接用好像用不上,可是不会做起事情来总会捉襟见肘,左支右绌。找工作的时候,有的面试官甚至会让我们手写排序算法。既然排序算法如此重要,就让我们一起去夯实基础,切切实实得掌握它吧。
前言
先讲两个重要的概念。
1.所谓稳定排序就是指数组中相等的元素在排序过后前后顺序不变。
2.排序算法的平均复杂度是有下限的,为nlog(n)。所以大家不要再想着能发明什么牛逼的算法可以达到线性增长的。至于这个定理的证明,比较复杂,我会在下篇文章中专门讲述。
二分查找法
def binary_search(l, item):
low = 0
high = len(l)-1
while low <= high:
mid = (low + high)//2
mid_data = l[mid]
if mid_data > item:
high = mid - 1
elif mid_data < item:
low = mid + 1
else:
return mid
return None
L = [2, 6, 4 ,5, 7]
index = binary_search(L, 9)
冒泡算法
运动前总要热身,防止拉伤,深入研究排序算法前,先给大家介绍一个最常见,算法思想最简单最粗暴的排序算法——冒泡排序。
重复地走访过要排序的数列,一次比较两个元素,如果它们的顺序错误就把它们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢“浮”到数列的顶端。
def bubble_sort(l):
length = len(l)
for i in range(1, length):
for j in range(0, length-i):
if l[j] > l[j+1]:
l[j], l[j+1] = l[j+1], l[j]
return l
print(bubble_sort([2, 4, 1, 4]))
image.png
对该算法进行复杂性分析。我首先取了100个数组,数组规模从1到1000个元素均匀递增,数组中每个数的大小在(1,10000),得到下图。横坐标是排序的数组规模大小,纵坐标是排序所用时间,单位为秒。以后的图纵横坐标都是如此。
image.png
能够看出来,随着数组元素规模越来越大,所耗费时间呈现螺旋式上升的趋势。不过波动较大,我们也看不太清楚它是个怎么样的曲线。为此我扩大了样本规模,请看下图。
image.png
从这张图中我们可以很清晰明了的看出,这是个二次曲线。这也符合实际情况,冒泡排序的算法复杂度是数组规模的平方。
冒泡排序可以说是最经典的,最稳定的一个算法,上算法课的同学们一定会接触它。因为它似乎是一把打开算法大门的钥匙,有了它,我们开始知道何为算法。但是,在实际应用中,我们并不用它。
插入排序
大家都有一个经验,打扑克的时候,我们都喜欢按大小顺序来