~~~~ 在计算机科学中,算法的时间复杂度是一个函数,他定性描述该算法的运行时间。这是一个代表算法输入值的字符串的长度函数。时间复杂度常用大 O O O符号表述,不包括这个函数的低阶项和首项系数。使用这种方式时,时间复杂度可被称为是渐近的,亦即考察输入值大小趋近无穷时的情况。
常数时间
~~~~
若对于一个算法,
T
(
n
)
T(n)
T(n)的上界与输入大小无关,则称其具有常数时间,记作
O
(
1
)
O(1)
O(1)时间。一个例子是访问数组中的单个元素,因为访问它只需要一条指令。但是,找到无序数组中的最小元素则不是,因为这需要遍历所有元素来找出最小值。这是一项线性时间的操作,或称为
O
(
n
)
O(n)
O(n)时间。如果预先知道元素的数量并假设数量保持不变,则改操作也可以称为具有常数时间。
~~~~
虽然被称为“常数时间”,运行时间本身并不必须与问题规模无关,但它的上界必须是与问题规模无关的确定值。举例,“如果a>b则交换a、b的值”这项操作,尽管具体时间会取决于条件“a>b”是否满足,但它依然是常数时间,因为存在一个常量t使得所需时间不超过t。
以下是一个常数时间的代码片段:
int index = 5;
int item = list[index];
if (condition){
// 固定时间操作
fun1_fixed_time()
}
else{
// 不固定时间的操作
fun2_not_fixed_time()
}
for i = 1 to 100
for j = 1 to 200
{
// 固定时间操作
fun2_fixed_time()
}
~~~~ 如果 T ( n ) = O ( c ) T(n) = O(c) T(n)=O(c),其中c是一个常数,这记法等价于标准记法 T ( n ) = O ( 1 ) T(n)=O(1) T(n)=O(1)。
对数时间
~~~~
若算法的
T
(
n
)
=
O
(
l
o
g
n
)
T(n) = O(log~n)
T(n)=O(log n),则称其具有对数时间。计算机使用二进制的计数系统,对数常常以2为底(即
l
o
g
2
n
log_{2}n
log2n,有时写作
l
g
n
lg~n
lg n)。然而,由对数的换底公式,
l
o
g
a
n
log_an
logan和
l
o
g
b
n
log_bn
logbn只有一个常数因子不同,这个因子在大
O
O
O记法中被丢失。因此记作
O
(
l
o
g
n
)
O(log~n)
O(log n),而不论对数的底是多少,是对数时间算法的标准记法。
~~~~
常见的具体对数时间的算法有二叉树的相关操作和二分搜索。
~~~~
对数时间的算法非常有效的,因为每增加一个输入,其所需的额外计算时间会变小。
~~~~
递归地将字符串砍半并且输出是这个类别函数的一个简单例子。它需要
O
(
l
o
g
n
)
O(log~n)
O(log n)的时间因为每次输出之前我们都将字符串砍半。这意味着,如果我们想增加输出次数,我们需要将字符串长度加倍。
// 递归输出一个字符串的右半部分
var right = function(str)
{
var length = str.length;
// 辅助函数
var help = function(index)
{
// 递归情况:输出右半部分
if(index < length){
// 输出从index到数组末尾的部分
console.log(str.substring(index, length));
// 递归调用:调用辅助函数,将右半部分作为参数传入
help(Math.ceil((length + index)/2));
}
// 基本情况:什么也不做
}
help(0);
}
幂对数时间
~~~~
对于某个常数k,若算法的
T
(
n
)
=
O
(
(
l
o
g
n
)
k
)
T(n)=O((log~n)^k)
T(n)=O((log n)k),则称其具有幂对数时间。例如,矩阵链排序可以通过一个PRAM模型在幂对数时间内解决。
~~~~
PRAM模型:它假设有对其容量大小没有限制的一个共享存储器,并且有多个功能相同的处理器,在任意时刻处理器可以访问共享存储单元。
次线性时间
~~~~
对于一个算法,若其符合
T
(
n
)
=
o
(
n
)
T(n)=o(n)
T(n)=o(n),则其时间复杂度为次线性时间。实际上除了符合以上定义的算法,其他一些算法也拥有次线性时间的算法复杂度。例如有
O
(
n
1
/
2
)
O(n^{1/2})
O(n1/2)的Grover算法(葛罗佛算法)。
~~~~
常见的非合次线性时间算法都采用了诸如平行处理、非古典处理,又或者选择性地对有保证的输入结构做出假设。不过,一般情况,例如在头
l
o
g
(
n
)
log(n)
log(n)比特中每个字符串有一个比特作为索引的字符串组就可能依赖输入的每个比特,但又符合次线性时间的条件。
~~~~
“次线性时间算法”通常指那些不符合前一段的描述的算法。它们通常运行于传统电脑架构系列并且不容许任何对输入的事先假设。但是它们可以是随机化算法,并且必须是真随机算法除了特殊情况。
线性时间
~~~~ 如果一个算法的时间复杂度为 O ( n ) O(n) O(n),则称这个算法具有线性时间,或 O ( n ) O(n) O(n)时间。非正式地说,这意味着对于足够大的输入,运行时间增加的大小与输入成线性关系。例如,一个计算列表所有元素的和的程序,需要的时间与列表的长度成正比。这个描述是稍微不准确的,因为运行时间可能显著偏离一个精确的比例,尤其是对于较小的n。
线性对数(准线性)时间
~~~~ 若一个算法时间复杂度 T ( n ) = O ( n l o g n ) T(n)=O(n~log~n) T(n)=O(n log n),则称这个算法具有线性对数时间,因此从表达式我们也可以看到,线性对数时间增长得比线性时间要快,但是对于任何含有n,且n的幂指数大于1的多项式时间来说,线性对数时间却增长得慢。
还有几个没看懂,就不写上去了
资源来源,维基百科:时间复杂度