基本概念
前面用大O开头,于是叫大O表示法。!!!∑(゚Д゚ノ)ノ
用于表示算法所运行的速度,用于分析算法的复杂性。英语:Big O notation
通俗一点:随着程序循环次数的增加,距离得到结果的时间如何增加。
表示方法:O(表达示)
大O表示法以最糟糕的情况来表示
作用
我们经常使用别人所编写的算法,如果我们知道算法的运行速度,对我们如何使用也大有帮助。
以Java为例,比如我们要实现一个容器,有以下两种选择
- ArrayList:基于数组的数据结构
- LinkedList:基于链表的数据结构
对于数组和链表的概念,这里就不讲了,需要的同学请自行baiduφ(>ω<*)
如果们需要经常随机查找,我们经常会选择ArrayList,因为我们知道他随机查找快。如果我们经常添加数据我们常常选择旋转LinkedList,因为链表添加数据快。
用大O表示法来表示它们的话。
- ArrayList在随机查找方面可表示为O(1),因为数组通过下标直接返回值;在添加数据方面可表示为O(n),在这里假设ArrayList内的数组已满,就需要一个更大的数组,再拷贝一次所有的元素到这个更大的数组,n可看做数组的长度。
- LinkedList在随机查找可表示为O(n),因为每次查找都需要从头开始查找,如果查找的元素在末尾,则最多需要查找n次,而数组不管什么情况都是一次。在添加数据方面可表示为O(1),因为链表每次添加数据就会记录下个一元素的地址,所以添加元素时可直接知道需要存放的位置。
容器 | 算法 | 用途 | 大O表示法 |
---|---|---|---|
ArrayList | 数组 | 随机查找 | O(1) |
LinkedList | 链表 | 随机查找 | O(n) |
ArrayList | 数组 | 添加元素 | O(n) |
LinkedList | 链表 | 添加元素 | O(1) |
通过大O表示法,我们就能直观的知道什么时候该选择什么算法。
例子
算法案例
我们来看一个有序数组查找一个值的算法
- 简单查找:从第一个开始查找判断是否等于预期值直到最后一个元素,如果长度为n,最糟糕情况则是n次。大O表示法:O(n)
- 二分查找:每次都从数组中间开始查找,判断是大于还是小于预期值。如果大于排除后半数据,如果小于排除前半数据。每次能排除一半的数。如果长度为n的数组,最糟糕情况则是log₂n次(算法试刀-二分法查找)。用大O表示法(log就是log₂):O(logn)
常见大O运行时间
从快到慢的顺序列出了经常遇到的5种大O运行时间
大O表示法 | 名称 | 描述 |
---|---|---|
O(1) | 常数时间 | 如数组取值 |
O(log n) | 对数时间 | 包括二分法查找的这类算法 |
O(n) | 线性时间 | 包括简单查找的这类算法 |
O(n * log n) | 线性对数时间 | 如快速排序(一种较快的排序算法) |
O(n²) | 平方时间 | 如选择排序(一种较慢的排序算法) |
O(n!) | 阶乘时间 | 如旅行商问题(一种非常慢的算法) |
总结
注意事项
- 算法的速度指的并非时间,而是操作数的增速。
- 谈论算法的速度时,我们说的是随着输入的增加,其运行时间将以什么样的速度增加。
- 算法的运行时间用大O表示法表示。
- O(log n)比O(n)快,当需要搜索元素越多时,前者比后者越快的多。
参照网格图
大致画了一下上面几种算法随着输入次数增加,其运行时间的增加的递增图。
参考
- 算法图解
如何错误的地方欢迎指正哦