美文网首页
swift 数据结构与算法一

swift 数据结构与算法一

作者: _浅墨_ | 来源:发表于2018-06-06 21:35 被阅读22次

algorithms and data structures 系列笔记一

1. 线性搜索(Linear Search)

线性搜索的目的是在数组中找到特定的值。

一个存储有某个类型对象的数组,你迭代遍历它,使其每个对象和你要找到的对象进行对比,如果两个对象相同,停止查找并返回当前 index,如果不相同,继续迭代查找。

例如数组 [5, 2, 4, 7],存有 numbers 对象,你想确定该数组是否包含数字 2 。

你拿第一个数字 5 与 2 相比,不相等,则继续查找。

下一个 2 和要查找的数字相同,查找成功,停止迭代,返回 index 1 ,index 1 代表数组中下标为第二个元素,第一个下标为 0。

示例代码:

func linearSearch<T: Equatable>(_ array: [T], _ object: T) -> Int? {
  for (index, obj) in array.enumerated() where obj == object {
    return index
  }
  return nil
}

在 playground 键入代码,效果如下:

let array = [5, 2, 4, 7]
linearSearch(array, 2)  // This will return 1

2. 线性搜索性能 Linear Search Performance

Linear search 时间复杂度为 O(n) 。它将需要查找的对象和数组中每个对象对比,因此它的时间取决于数组的长度。在最坏的情况,需要遍历数组中所有对象才能确定数组中是否包含要查找的对象。在最好的情况,你只要对比一次就能确定了,比如第一个就是要查找的对象。最好的时间复杂度是 O(1) ,但是这很罕见,在一个随机分配的数组中,这个概率是 1:n 。平均而言,线性搜索需要查看数组中一半的对象。

3. 时间复杂度 O 符号介绍

A note on Big-O notation

大 O 符号可以粗略地显示算法的运行时间和它所使用的内存空间。当有人说, “这个算法最坏情况运行时间的O(n ^ 2),并使用O(n)空间” ,他们说这是有点缓慢但不需要很多额外的内存。

各个时间复杂度对比:

Big-O 算法数量级 描述
O(1) 常量 最好的算法。无论要测试的数据量多大,该算法总是返回相同的时间。例如,数组中根据其 index 查找某个对象 。
O(log n) 对数 较好的算法。如果测试数据为100,大概查询7次,如果数据量1000,大概查询10次。这种算法,要查找的数据量越大,表现效果越好。
O(n) 线性 性能优良。 测试数据量100,需要查询100次,测试数据量1ooo,需要查找1000次。例如,顺序查找。
O(n log n) linearithmic 性能良好。表现差于 linear 算法,但是也不是太坏。
O(n^2) 二次方的 查找速度慢。如果你有100个对象,需要查询 100^2 = 10,000 次
O(n^3) 三次方的 查找速度更慢。如果你有100个对象,需要查询 100^3 = 1000,000 次
O(2^n) 指数 查找速度非常慢。应当尽量避免这种算法,但是有时又没得选择,例如 traveling salesperson problem
O(n!) 阶乘 无法忍受的慢。百万年做不了一件事的那种慢。

以下为各个算法的一个示例:

O(1)
let value = array[5]

O(1) 的另一一个例子就是入栈出栈。

O(log n)
var j = 1
while j < n {
  // do constant time stuff
  j *= 2
}
O(n)
for i in stride(from: 0, to: n, by: 1) {
  print(array[i])
}
O(n log n)
for i in stride(from: 0, to: n, by: 1) {
var j = 1
  while j < n {
    j *= 2
    // do constant time stuff
  }
}

或者

for i in stride(from: 0, to: n, by: 1) {
  func index(after i: Int) -> Int? { // multiplies `i` by 2 until `i` >= `n`
    return i < n ? i * 2 : nil
  }
  for j in sequence(first: 1, next: index(after:)) {
    // do constant time stuff
  }
}
O(n^2)
for i  in stride(from: 0, to: n, by: 1) {
  for j in stride(from: 1, to: n, by: 1) {
    // do constant time stuff
  }
}
O(n^3)
for i in stride(from: 0, to: n, by: 1) {
  for j in stride(from: 1, to: n, by: 1) {
    for k in stride(from: 1, to: n, by: 1) {
      // do constant time stuff
    }
  }
}
O(2^n)
func solveHanoi(n: Int, from: String, to: String, spare: String) {
  guard n >= 1 else { return }
  if n > 1 {
    solveHanoi(n: n - 1, from: from, to: spare, spare: to)
  } else {
    solveHanoi(n: n - 1, from: spare, to: to, spare: from)
  }
}
O(n!)
func nFactFunc(n: Int) {
  for i in stride(from: 0, to: n, by: 1) {
    nFactFunc(n: n - 1)
  }
}

参考:

  1. Implementing Linear Search
  2. Big-O Notation

相关文章

网友评论

      本文标题:swift 数据结构与算法一

      本文链接:https://www.haomeiwen.com/subject/xssbsftx.html