算法图解之Swift实践【第一章 算法简介】

132 阅读3分钟

本人已参与「新人创作礼」活动,一起开启掘金创作之路。

算法图解之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表示法让你能够比较操作数,它指出了算法运行时间的增速

小结

  1. 算法的速度指的并非时间,而是操作数的增速。
  2. 谈论算法的速度时,我们说的是随着输入的增加,其运行时间将以什么样的速度增加。
  3. 算法的运行时间用大O表示法表示。
  4. 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)快。需要搜索的元素越多,前者比后者就快得越多。
  • 算法运行时间并不以秒为单位。
  • 算法运行时间是从其增速的角度度量的。