本人已参与「新人创作礼」活动,一起开启掘金创作之路。
算法图解之Swift实践【第一章 算法简介】
算法定义
算法是一组完成任务的指令,任何代码片段都可视为算法。
二分法
定义与实现
二分法是一种查找算法,其输入是一个有序的元素列表。如果要查找的元素包含在列表中,二分查找返回其位置;否则返回null。 我们可以利用二分法解决简单的查找问题:从有序数组中查找某一个元素,如果存在则返回该元素的下标,否则返回-1。
使用Swift实现如下:
func binarySearch(_ list: [Int], item: Int) -> Int {
// 定义low和high用于跟踪要在其中查找的列表范围
// 初始值low为第一个元素下标,high为最后一个元素下标
var low = 0
var high = list.count - 1
while low <= high {
// 开启循环,条件:当范围的低位不大于高位(范围没有缩小到只包含一个元素)
let mid = (low + high) / 2 //检查位于中间(二分之一处)的元素
let guess = list[mid] // 检查中间元素
if guess == item { return mid } // 找到了
if guess > item { // 大了
high = mid - 1
} else { // 小了
low = mid + 1
}
}
return -1 // 列表中没有指定的元素
}
测试
let list = [1,4,5,6,8,9]
let indexOf8 = binarySearch(list, item: 8)
let indexOf3 = binarySearch(list, item: 3)
print(Index of 8:\(indexOf8))
print(Index of 3:\(indexOf3))
结果
Index of 8:4
Index of 3:-1
练习
1.1 假设有一个包含128个名字的有序列表,你要使用二分查找在其中查找一个名字,请问最多需要几步才能找到?
7步
log 128 = 7
1.2 上面列表的长度翻倍后,最多需要几步?
8步
log (128 * 2) = 8
大O表示法
概述
大O表示法指出的是最糟情况下的运行时间。 下面按从快到慢的顺序列出经常遇到的5种大O运行时间:
- O(log n) :对数时间,这样的算法包括二分查找。
- O(n):线性时间,这样的算法包括简单查找。
- O(n∗logn):这样的算法包括快速排序。
- O(n^2 ):这样的算法包括选择排序。
- O(n!):这样的算法包括旅行商问题的解决方案。 大O表示法让你能够比较操作数,它指出了算法运行时间的增速
小结
- 算法的速度指的并非时间,而是操作数的增速。
- 谈论算法的速度时,我们说的是随着输入的增加,其运行时间将以什么样的速度增加。
- 算法的运行时间用大O表示法表示。
- O(log n)比O(n)快,当需要搜索的元素越多时,前者比后者快得越多。
练习
使用大O表示法给出下述各种情形的运行时间。
1.3 在电话簿中根据名字查找电话号码。
O(log n)
1.4 在电话簿中根据电话号码找人。(提示:你必须查找整个电话簿。)
O(n)
1.5 阅读电话簿中每个人的电话号码。
O(n)
1.6 阅读电话簿中姓名以A打头的人的电话号码。这个问题比较棘手,它涉及第4章的概 念。答案可能让 你感到惊讶!
O(n)。
这里实际的情况是只需要对26个字母中的一个一次查找,因此运行时间应该为O(n/26),但是大O表示法往往不考虑常量,因此这里运行时间的正确的大O表示法应该是O(n)
总结
- 二分查找的速度比简单查找快得多。
- O(log n)比O(n)快。需要搜索的元素越多,前者比后者就快得越多。
- 算法运行时间并不以秒为单位。
- 算法运行时间是从其增速的角度度量的。