时间复杂度
算法的时间复杂度是算法的基石,那么到底什么是时间复杂度呢?
顾名思义,就是描述程序运行时间的一种指标,只不过,我们在程序中都是使用大O表示法,没错也就是你经常看到的O(n)之类的表示方法,即 T(n) = O(f(n))。
先来看一段例子:
for(int i = 0;i < n;i++)
{
std::cout<<"aaa"<<endl;
}
比如这样的它的时间复杂度就是O(n)
再比如:
for(int i = 0;i < n;i++)
{
for(int j = 0;j < n;j++)
{
std::cout<<"aaa"<<endl;
}
}
这样的就是O(n2)。
那应该怎么算呢,其实就是数代码运行的次数。
常用的时间复杂度有:
-
常数阶O(1)
-
对数阶O(logN)
-
线性阶O(n)
-
线性对数阶O(nlogN)
-
平方阶O(n²)
-
立方阶O(n³)
-
K次方阶O(n^k)
-
指数阶(2^n)
注意一点,当你算出一个复杂度的时候,要有数学上的极限思想,比如n+1那就取n,n2+n+1就取n2,总之就是取高阶项,连系数也是忽略的。
空间复杂度
空间复杂度 O(n)算法在计算机存储器上占用的空间包括三个部分。
- 输入输出
算法的输入输出数据所占用的存储空间是由要解决的问题决定的,是通过参数表由调用函数传递而来的,它不会随算法的不同而改变。这不是我们需要考虑的部分。
- 算法本身
存储算法本身所占用的存储空间与算法书写的长短成正比,要压缩这部分存储空间,就必须编写出较短的算法。然而,算法想要实际应用需要根据需求采取不同的编程语言来实现,不同编程语言实现的代码长短差别很大,然而存储空间都在可接受范围之内(通常不同编程语言的效率更受关注)。
- 运行临时占用
根据算法在运行过程中临时占用存储空间的不同,可以将算法分为两类。
-
原地算法(in-placealgorithm):只需要占用少量的临时工作单元,而且不随问题规模的大小而改变,我们称这种算法是“就地”进行的,是节省存储的算法。
-
非原地算法(not-in-place):需要占用的临时工作单元数与解决问题的规模n有关,它随着n的增大而增大,当n较大时,将占用较多的存储单元。
算法临时占用空间是考虑算法空间复杂度时主要考虑的部分。相比于随着问题输入规模扩大而扩大的非原地算法,原地算法是更加简洁高效的算法(仅考虑空间复杂度时)。
int[] m = new int[n]
for(i=1; i<=n; ++i)
{
j = i;
j++;
}
这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)