本文是在阅读Aditya Bhargava先生算法图解一书所做的总结,文中部分代码引用了原文的代码,在此感谢Aditya Bhargava先生所作出的这么简单的事例,对基础算法感兴趣的朋友可以阅读原文。由于本人也是编程初学者,所以本书比较浅显易懂,所介绍的算法配上插图也十分易懂,这里只是介绍几种最基础的算法由浅入深以帮助理顺一些简单的思维逻辑。
算法简介算法是一组完成任务的指令。任何代码片段都可视为算法,我们这里讨论的算法要么速度快,要么能解决有趣的问题,要么兼而有之。
二分查找二分查找是一种算法,其输入是一个有序的元素列表,如果要 查找的元素包含在列表中,二分查找返回其位置;否则返回Null。
二分法很好理解,如果让你猜出100以内指定的某个值的话,怎样可以做到用最少的次数寻找到。可能有人觉得可能一次就可以找到,但是最糟可能要猜100次哦。
这种问题使用二分法就很简便了,每次取中间值以缩小查找范围,这样7步以内必定可以找到答案。
如果这个问题扩大到4亿的话,无疑二分法可要优秀的多。一般而言,对于包含n个元素的列表,用二分查找最多需要log2n步,而简单查找最多需要n步。
二分法的有点事查找速度快,但是仅当列表是有序的时候,二分查找才管用。
对于这个猜数字的游戏使用二分法思想完成的代码如下:
#二分法 def two(lists,item): low=0 high=len(lists)-1 while low<= high: mid=(low+high)//2 guess=lists[mid] if guess==item: return "guess is %s"%guess elif guess > item: high=mid-1 else: low=mid+1 return None lists=[1,2,4,6,8] print(two(lists,8)) print(two(lists,3)) 运行结果: guess is 8 None
大O表示法大O表示法是一种特殊的表示法,指出了算法的速度有多快。由于不同算法运行时间的增速不同,所以使用大O表示法来看时间增速更为科学直观。
例如假设列表包含n个元素。简单查找需要检查每个元素,因此需要执行n次操作。使用大O表示法,这个运行时间为O(n)。之所以称为大O表示法,是因为操作数前有个大O。。。这是真的。
简单查找的运行时间总是为O(n)。在电话簿查找Adit时,一次就找到了,这是最佳的情形,即O(1),但大O表示法说的是最糟的情形。因此,你可以说,在最糟情况下,必须查看电话簿中的每个条目,对应的运行时间为O(n)。
一些常见的大O运行时间 O(log n),也叫对数时间,这样的算法包括二分查找。
O(n),也叫线性时间,这样的算法包括简单查找。
O(n * log n),这样的算法包括快速排序。
O(n2 ),这样的算法包括选择排序。
O(n!),这样的算法包括接下来将介绍的旅行商问题的解决方案。
使用这几种算法绘制一个16格的网格需要的时间如下:
速度由快到慢,当然只是针对这个问题而言。
算法的速度指的并非时间,而是操作数的增速。
谈论算法的速度时,我们说的是随着输入的增加,其运行时间将以什么样的速度增加。
算法的运行时间用大O表示法表示。
O(log n)比O(n)快,当需要搜索的元素越多时,前者比后者快得越多。
旅行商问题这着实困扰着很多人,一位旅行商要去往5个城市,如何确保旅程最短,5个城市有120种不同的排列方式。涉及n个城市时,需要执行n!(n的阶乘)次操作才能计算出结果。因此运行时间为O(n!),即阶乘时间。
选择排序很多算法仅在数据经过排序后才管用。当然很多语言都内置了排序算法,因此你基本 上不用从头开始编写自己的版本。
数组与链表需要将数据存储到内存时,你请求计算机提供存储空间,计算机给你一个存储地址。需要存储多项数据时,有两种基本方式——数组和链表。
数组中的内存必须是相连的,这意味着增加元素的时候如果紧跟着的那个内存被占用了,那就只能重新寻找可容纳的连续地址,如果没有这么长的连续地址结果还存不了,所以计算机在存数组时还预留了空间,你只要三个内存,但是我给你十个。即使如此额外请求的位置可能根本用不上,这将浪费内存,你没有使用,别人也用不了。而且待办事项超过10个后,你还得转移。