前言
算法是一组完成任务的指令。任何代码片段都可视为算法。本篇文章旨在快速搭建算法框架,为读者快速入门算法打下基础,故涉及算法知识但尽量不涉及复杂的语法知识。
一、二分查找
假如你需要在一本100页的书中查找所需要的某一页(如30页吧),我们可以从头开始翻页,一页一页地查找直到找到想找的那一页。但你可能不会这么做,因为你知道30页在全书的中部靠前的位置,所以你多半是先取到书的一半(50页)左右的位置,再向前翻。
那么,当我们登录一个网站(如CSDN),输入我们的用户名和密码时,CSDN数据库必须先得核实你是否注册过账号,于是它就在数据库中寻找你的用户名。假如你的用户名为TJUTCM,那么它可以从A打头的位置查找,但显然更明智的做法是从中间开始查找。
这种算法,普遍地被我们使用,我们称其为二分查找。
实例:如果我在1-100中选择一个数字让你来猜,你会怎么做呢?是从1一直顺序报数1,2,3,...这样到100?还是使用别的思路呢?显然,这里使用二分查找再合适不过了。
def binary_search(list,item): #这里的list为所查找的数字所在的有序数组,而item则为所查找的数字 low=0 high=len(list-1) #low和list用于跟踪要在其中查找的列表部分 #只要范围没有缩小到只包含一个元素,就检查中间的元素 while low<=high: mid=(low+high)/2 guess=list[mid] if guess==item: #找到了元素 return mid if guess>item: #猜的元素大了 high=mid-1 else: #猜的元素小了 low=mid+1 return None #没有要查找的元素
一般而言,对于包含n个元素的列表,用二分查找最多需要log2n(以2为底,n的对数)步,而简单查找最多需要n步。但需注意的是:仅当列表是有序的时候,二分查找才有用。
二、选择排序
假如你需要在教务系统查看本学期的课程所对应的学分排序,将查询到的课程按照学分从低到高排序,一种方法是遍历这个列表(课程和其对应的学分),找出学分占比最低的课程,并将该课程添加到一个新列表中;再次这样做,找出学分占比第二低的课程;继续这样做,你将得到一个有序列表。
O(n)时间意味着查看列表中的每个元素一次,我们对课程列表进行简单查找时,意味着每个课程都要查看一次,如此一来单趟就花费了O(n)的时间,而对于这种时间为O(n)的操作,你需要执行n次。
因此对于这种时间为O(n)的操作,你需要执行n次。而这种算法我们称其为选择排序。
#将数组元素按从小到大的顺序排列,先编写一个用于找到数组中最小元素的函数 def findSmallest(arr) smallest=arr[0] #存储最小的值 smallest_index #存储最小元素的索引 for i in range(1,len(arr)): if arr[i]<smallest: smallest=arr[i] smallest-index=i return smallest_index #现在可以用这个函数来实现选择排序算法了 def selectionSort(arr): #对数组进行排序 newArr=[] for i in range(len(arr)): smallest=findSmallest(arr) #找出数组中最小的元素,并将其假如到新数组中 newArr.append(arr.pop(smallest)) return newArr
随着排序的进行,我们发现:每次需要检查的元素数在逐渐减少,最后一次需要检查的元素只有一个。既然如此,运行时间怎么还是O(n^2)呢?
我们发现:第一次需要检查n个元素,但随后检查的元素个数依次为n-1,n-2,...,2和1。平均每次检查的元素数为n/2,因此运行时间为O(n^2/2),大O表示法省略诸如1/2这样的系数,故算法的时间复杂度为O(n^2)。
三、快速排序
如果老师要求统计班级学生的人数,而又不想自己一个个数人数。于是老师便想到了个好主意:指定两个班级负责人,一男一女,让着两人分别去统计男生和女生的人数。这两个同学也不想自己一个个数人数,于是再把男生和女生部分分别划分为不同的小组,再让小组长去统计小组的人数......
如此一样,人数统计问题便被人为地划分、简化为小问题,这些小问题又可以接着划分为更小的问题,直到问题不可划分。这时再一步步回退就能得出大问题的解了。我们将这种算法称为快速排序算法。
#使用快速排序算法的工作原理: #(1)找出简单的基线问题 #(2)确定如何缩小问题的规模,使其符合基线条件 #(基线条件:为空或只包含一个元素的数组是“有序的”,不需要再排序) def quicksort(array): if len(array)<2: return array else: pivot=array[0] #选择基准值 less=[i for i in array[1:] if i<=pivot] #由所有小于等于基准值的元素组成的数组 greater=[i for i in array[1:] if i>pivot] #由所有大于基准值的元素组成的数组 return quicksort(less)+[pivot]+quicksort(greater) print quicksort([1,4,3,2]) #这里为随机给的数组元素
快速排序算法将问题逐步分解,最终分解直至子问题达到基线条件(为空数组或只包含一个元素)。实现快速排序时,随机地选择用作基准值的元素,快速排序的平均运行时间为O(nlogn)。
未完待续......