算法基础:时间、空间复杂度

215 阅读3分钟

基本概念:

Time complexity时间复杂度:

时间复杂度是指当输入大小增加时,运行算法所需的时间。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度(O是数量级的符号 ),简称时间复杂度。

几种常见的时间复杂度:

T(n) = O(1)恒定时间

//MARK: Constant time恒定时间  T(n) = O(1)
// 恒定时间算法是一个不在乎输入大小但运行时间相同
**func** constantTimeAlgorithm(names: [String]) -> Void {

    // if let fisrt = names.first 语句执行1次
    if let first = names.first {
        // print函数属性1次
        print(first)
        // else执行1次 通常else不进入统计 因为else后面不需要接任何我们书写的代码
    } else {
        // print函数执行1次
        print("Not value")
    }
// 得到的总次数是3 T(n) = O(3) 根据同数量级函数的定义化简为 T(n) = O(1)
}

T(n) = O(n)线性时间

//MARK: Linear time线性时间 T(n) = O(n)
// 随着数量的增加循环的迭代次数也会相应的增加

func linearTimeAlgorithm(names:[String]) -> Void {
    // for name in names执行 names.count次数 次数可变设为n
   for name in names {
        // print函数执行names.count次数 次数可变设为n
        print(name)
    }// 得到的总次数就是2n 根据同数量级函数 T(n) = O(n)  因为2n/n = 2 所以O(2n)化简为O(n)
}

T(n) = O(n^2)二次平方时间

//MARK: Quedratic time二次平方时间 T(n) = O(n^2)
// 通俗说就是循环嵌套循环,算法时间复杂度大约就是输入大小的平方
func quadraticTime(names:[String]) {
    // 外层的遍历执行n次 这里n代表names.count-1
    for _ in names {
   // 外层每遍历1次 这里就是n次,所以总共算下来内部for name in names就执行了n^2
   for name in names {
    // print函数也是执行了n^2次
       print(name)
        }
    }
// 总共执行了n + n^2 + n^2 = 2n^2 + n 同数量级化简之后 T(n) = O(n^2)
}

T(n) = O(log2(n))对数时间

//MARK: Logarthmic time (对数) T(n) = O(log2(n))**
/**
    展示对数时间复杂度的算法形式
     - **parameter** value: 需要匹配的值
     - **parameter** array: 一个无需数组
 */
func logarithmicTime(_ value: Int, in array:[Int]) -> Bool {
    // 执行1次
    if array.isEmpty {
    // 执行1次或者0次
     return false
    }
    // 数组从大到小排列 执行1次
    let sortedArr = array.sorted(by: >)
    //各1次
    var startedIndex = 0
    var endIndex = array.count - 1
    var middleIndex = (startedIndex + endIndex)/2
    repeat {
      if sortedArr[middleIndex] > value {
          startedIndex = middleIndex + 1
         // middleIndex = (startedIndex + endIndex)/2
         // 使用位移表示除以2
          middleIndex = (startedIndex + endIndex)>>1
        }
       else if sortedArr[middleIndex] < value {
            endIndex = middleIndex - 1
            middleIndex = (startedIndex + endIndex)/2
        }
      else {
       // 相等
    print("find the element in sorted array and index is\(middleIndex)")
       return true
        }
    }while (startedIndex <= endIndex)
    //最多会执行t次 其中 startedIndex* 2^t = endIndex => t = log2(endIndex/startedIndex)
repeat中的执行总数和while相同 所以最后的结果化简后就是O(log2(n))
    return false
}

T(n) = O(n*log2(n))拟线性时间

//**MARK: Quasilinear time 拟线性时间 T(n) = O(n*log2(n))**
/**
展示拟线性算法,内部调用了对数时间复杂的二分查找算法
- **parameter** sourcaArray: 源数组 。查找该数组中的每个元素是否·存在于destinationArray
 */

func qualilinearTime(source sourceArray:[Int], destination destinationArray:[Int])-> Bool {

   //destination排序 从大到小
  let sortedArr = destinationArray.sorted(by: >)
  // 外层循环执行n次 其中n = sourceArray.count
  for outsideIndex in 0..<sourceArray.count {
        // 此函数一共执行n*log2(n)次
        logarithmicTime(sortedArr[outsideIndex], in: destinationArray)
    }

       //执行1次
       // 最后总的时间复杂度就是T(n) = O(n*log2(n))
      return false
}

space complexity空间复杂度:

时间复杂度算法帮助预测扩展性,但他不是唯一的衡量标准 空间复杂度是衡量算法运行时所需的资源。对于计算机来说算法资源就是内存。

//MARK: 线性空间复杂度 O(n)
func printSorted(_ array:[Int]) {
    let sorted = array.sorted()
 //这里实际上创建了n个element对象 所以空间复杂度是O(n)
    for element in sorted {
        print(element)
      }
}
// 其余均类似于时间复杂度的统计方式 创建一个变量就统计一次。其余标准空间复杂度不再赘述