持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第8天,点击查看活动详情
1、写在前面
大家好,我是翼同学。今天文章的内容是:
- 时间复杂度
2、内容
2.1、什么是时间复杂度?
所谓算法时间复杂度就是算法运行的时间度量,是其所求解问题规模的函数,我们不考虑具体的运行时间函数,只考虑时间函数的数量级,这称为算法的渐进时间复杂度,简称时间复杂度。记为,称作大表示法。
时间复杂度是一个函数,它定性描述该算法的运行时间。
因此所谓的时间复杂度就是指最坏情况下,估算算法执行时间的一个上界。
2.2、大O表示法
大表示法取时间函数的主项,而忽略中的常数和低次项。
大表示法给出了时间复杂度的上界,作为算法的最坏情况运行时间的上界,即对任意数据输入的运行时间的上界。
举个例子:
假设某算法的时间函数为,此时让我们计算该算法的时间复杂度。利用大表示法中的简化思想:
- 去掉运行时间中的常数项:
- 去掉常数系数:
- 只保留最高项:
因此我们说,该算法的时间复杂度为。
小结:
算法的运行时间取决于原操作(核心操作)在算法中重复执行的次数,也就是语句频度。
2.3、常见的时间复杂度
常见的时间复杂度及其关系如下:
<<<<<<...<<...
简单举例如下:
(1) 常量阶
for(int i = 0; i<10000; ++i) {
++x;
s+=x;
}
上述例子中,++x;的语句频度为10000,则其时间复杂度为,即常量阶。
(2) 对数阶
for(int i = 1; i <= n; i*=2) {
++x;
}
上述例子中,++x;的语句频度为,则其时间复杂度为,即对数阶。
(3) 线性阶
for(int i = 1; i <= 2*n; ++i) {
++x;
s+=x;
}
上述例子中,++x;的语句频度为,则其时间复杂度为,即线性阶。
(4) 线性对数阶
for(int i = 1; i <= n; i*=2) {
for(int j = 1; j <= n; ++j) {
++x;
s+=x;
}
}
上述例子中,++x;的语句频度为,则其时间复杂度为,即线性阶。
(5) 平方阶
for(int i = 1; i <= n; ++i) {
for(int j = 1; j < n/2; ++j) {
++x;
s+=x;
}
}
上述例子中,++x;的语句频度为,则其时间复杂度为,即平方阶。
(6) 立方阶
for(int i = 1; i<=n; i++) {
for(int j = 1; j<=n; j++) {
c[i][j] = 0;
for(int k = 1; k<=n; k++) {
c[i][j] = c[i][j] + a[i][k] * b[k][j];
}
}
}
上述例子中,c[i][j] = c[i][j] + a[i][k] * b[k][j];的语句频度为,则其时间复杂度为,即立方阶。
2.4、空间复杂度
另外,记录一下空间复杂度。
一个算法所占用的存储空间包括三个方面:
- 算法本身所占用的存储空间
- 算法的输入输出所占用的存储空间
- 算法在运行过程中临时占用的存储空间
类似算法的时间复杂度,我们采用空间复杂度来度量算法所需存储空间的多少。记为.
一般来说,算法执行时间的节省都是以增加空间存储为代价的。
另外,空间复杂度一般是考虑程序运行时占用内存的大小,而不是可执行文件的大小。
举两个例子:
int x = 0;
for (int i = 0; i < n; i++) {
++x;
}
在上述例子中,程序所需的内存空间并不会随着的变化而变化。因此该算法的空间复杂度为常量阶,记为。
int* p = new int(n);
for (int i = 0; i < n; i++) {
p[i] = i;
}
在上述例子中,程序消耗的内存空间随着参数的增长而增长,呈线性增长,此时该算法的空间复杂度就记作。
3、写在最后
好了,今天的笔记就到这里。