算法图解
第一章 算法简介
1.1 引言
算法是一组完成任务的指令。任何代码片段都可视为算法。
1.2 二分查找
对数
你可能不记得什么是对数了,但很可能记得什么是幂。\(\lg100\) 相当于问“将多少个10相乘的结果是100”。答案是两个:\(10 * 10 = 100\)。因此,\(\lg100\) = 2。
对数运算是幂运算的逆运算。
\[10^2 = 100 \iff lg100 = 2\\ 10^3 = 1000 \iff lg1000 = 3\\ 2^3 = 8 \iff log_2 8 = 3\\ 2^4 = 16 \iff log_2 16 = 4\\ 2^5 = 32 \iff log_2 32 = 5\\ 对数是幂运算的逆运算 \]
本书使用的大O表示法讨论运行时间时,log指的都是\(log_2\)。使用简单查找法查找元素是,在最糟糕的情况下需要查看每一个元素。因此,如果列表包含8个数字,你最多需要检查8个数字。而使用二分查找时,最多需要检查\(log_2 n\)个元素。如果列表包含8个元素,你最多需要检查3个元素,因为\(log_2 8 = 3 \iff (2^3 = 8)\) 。如果列表包含1024个元素,你最多需要检查10个元素,因为\(log_2 1024 = 10 \iff (2^{10}) = 1024)\)。
仅当列表是有序的时候,二分查找才管用。
def binary_search(list, item):
low = 0 # low和high用于追踪要在其中查找的列表部分
high = len(list) - 1
while low <= high: # 只要范围没有缩小到只包含一个元素
mid = (low + high) / 2 # 就检查中间元素
guess = list[mid]
if guess == item: # 找到了元素
return mid
if guess > item: # 猜的数字大了
high = mid - 1
if guess < item: # 猜的数字小了
low = mid + 1
return None # 没有指定的元素
my_list = [1,3,5,7,9] # 来测试一下
print binary_search(my_list, 3) # => 1
print binary_search(my_list, -1) # => None
# 在Python中,None表示空,它意味着没有找到指定的元素
练习
- 假设有一个包含128个名字的有序列表,你要使用二分查找在其中查找一个名字,请问最多需要几步才能找到?
答:最多需要7步,因为\(log_2{128} = 7 \iff 2^{7} = 128\)
- 上面列表的长度翻倍后,最多需要几步?
答:最多需要8步,因为\(log_2 {256} = 8 \iff 2^{256} = 8\)
运行时间
每次介绍算法时,我们都将讨论起运行时间。一般而言,应选择效率最高的算法,以最大限度地减少运行时间或占用空间。
简单查找逐个地检查数字,如果列表包含100个数字,最多需要猜100次。如果列表包含40亿个数字,最多需要猜40亿次。换言之,最多需要猜测的次数与列表的长度相同,这被称为线性时间(linear time)
1.3 大O表示法
算法的运行时间以不同的速度增加。
大O表示法指出了算法有多快。例如,假设列表包含n个元素。简单查找需要检查每个元素,因此需要执行n次操作。使用大O表示法,这个运行时间为O(n)
。单位秒呢?——大O表示法指的并非以秒为单位的速度。大O表示法让你能够比较操作数,它指出了算法运行时间的增速。
大O表示法指出了最糟糕情况下的运行时间。
一些常见的大O运行时间
下面按从快到慢的顺序列出了你经常会遇到的5种大O运行时间。
- O(log n),也叫对数时间,这样的算法包括二分查找。
- O(n),也叫线性时间,这样的算法包括简单查找。
- O(n*log n),这样的算法包括快速排序——一种速度较快的排序算法。
- O(\(n^2\)),这样的算法包括选择排序——一种速度较慢的排序算法。
- \(O(n!)\),这样的算法包括旅行商问题的解决方案——一种非常慢的算法。
大O表示法,我们获得的主要启示如下:
- 算法的速度指的并非时间,而是操作数的增速。
- 谈论算法的速度时,我们说的是随着输入的增加,其运行时间以什么样的速度增加。
- 算法的运行时间用大O表示法表示。
- \(O(log_2 n) 比O(n)快\),当需要搜索的元素越多时,前者比后者快得越多。
练习
使用大O表示法给出下述各种情形的运行时间。
-
在电话簿中根据名字查找电话号码。
答:\(O(log_2 n)\)
-
在电话簿中根据电话号码找人。(提示:你必须查找正个电话簿。)
答:\(O(n)\)
-
阅读电话簿中每个人的电话号码。
答:\(O(n)\)
-
阅读电话簿中姓名以A打头的人的电话号码。这个问题比较棘手,它涉及第四章的概念。答案可能让你惊讶!
答:\(O(n)\)
你可能认为,我只对26个字母中的一个这样做,因此运行时间应为\(O(n/26)\)。需要牢记的一条简单规则是,大O表示法不考虑乘以、除以、加上或减去的数字。下面这些都不是正确的大O运行时间:\(O(n+26)、O(n-26)、O(n*26)、O(n/26)\),它们都应表示为\(O(n)\)!
1.4 小结
- 二分查找的速度比简单查找快得多。
- \(O(log_2 n)比O(n)快\)。需要搜索的元素越多,前者比后者就越快得多。
- 算法运行时间并不以秒为单位。
- 算法的运行时间是从其增速的角度度量的。
- 算法的运行时间用大O表示法表示。
标签:log,iff,笔记,表示法,算法,查找,图解,运行 来源: https://www.cnblogs.com/Night-Watch/p/13526787.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。