【算法图解】二分查找、选择排序、快速排序

前言

        算法是一组完成任务的指令。任何代码片段都可视为算法。本篇文章旨在快速搭建算法框架,为读者快速入门算法打下基础,故涉及算法知识但尽量不涉及复杂的语法知识。


一、二分查找

        假如你需要在一本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)。

未完待续......

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TJUTCM-策士之九尾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值