一般通常用
N
N
N 表示未知数,但
M
M
M ,
K
K
K 等等也行。
Example 2
void Func2(int N) {
int count = 0;
for (int k = 0; k < 100; ++ k) {
++count;
}
printf("%d\n", count);
}
本题的运行次数是常数次,不管该常数多大,时间复杂度都是
O
(
1
)
O(1)
O(1) 。
Example 3
void BubbleSort(int\* a, int n) {
assert(a);
for (size\_t end = n; end > 0; --end) {
int exchange = 0;
for (size\_t i = 1; i < end; ++i) {
if (a[i - 1] > a[i]) {
Swap(&a[i - 1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
break;
}
}
有的算法会有最好情况,最坏情况。对于复杂度的计算我们通常采用最坏的情况作悲观预期。很少有算法会看平均情况。
冒泡排序就是其中之一,我们对其最差的情况分析。相邻两数相比,第一趟交换
N
−
1
N-1
N−1 次,第二趟交换
N
−
2
N-2
N−2 次,……,第
i
i
i 趟交换
N
−
i
N-i
N−i 次。故精确的算法次数应为
F
(
N
)
=
N
−
1
N
−
2
.
.
.
N
−
i
.
.
.
1
0
=
N
×
(
N
−
1
)
/
2
F(N)=N-1+N-2+…+N-i+…+1+0=N×(N-1)/2
F(N)=N−1+N−2+…+N−i+…+1+0=N×(N−1)/2 。故复杂度为
O
(
N
2
)
O(N^2)
O(N2) 。
也可以看比较的次数,由于每趟最后一次只比较不交换,所以每趟比较的次数都比交换的次数多一次。但是并不影响其的复杂度。
Example 4
int BinarySearch(int\* a, int n, int x) {
assert(a);
int begin = 0;
int end = n - 1;
while (begin < end) {
int mid = begin + ((end - begin) >> 1);
if (a[mid] < x)
begin = mid + 1;
else if (a[mid] > x)
end = mid;
else
return mid;
}
return -1;
}
计算算法的复杂度不可仅看循环的层数,还要看算法的思想。 二分查找同样具有最好情况和最坏情况,仍然要对其最坏情况(找不到)进行分析。
对于这样的每次折半的情况,可以形象的用“折纸法”理解,一张纸对折一次去掉一半再对折再舍弃,假设一共折了
x
x
x 次,就找到了该数字。也就是
2
x
=
N
2^x=N
2x=N,所以次数
x
=
l
o
g
2
N
x=log_2N
x=log2N 。
对数阶
O
(
l
o
g
2
N
)
O(log_2N)
O(log2N),也可以省略底数写成
O
(
l
o
g
N
)
O(logN)
O(logN)。二分查找这个对数阶是非常优秀的算法,
20
=
l
o
g
2
(
1000000
)
20=log_2(1000000)
20=log2(1000000),一百万个数仅需查找20次。
Example 5
long Factorial(size\_t N)
{
if (0 == N)
return 1;
return Fac(N - 1) \* N;
}
递归算法的复杂度取决于两个因素:递归深度和每次递归调用次数。
递归深度即是一共递归的层数,也就是创建栈帧的次数。每次递归调用次数是递归函数内调用自身的次数。
显然本题的深度是
O
(
N
)
O(N)
O(N),调用次数是
1
1
1,故复杂度是
O
(
N
)
O(N)
O(N) 。
Example 6
long Fibonacci(size\_t N)
{
if(N < 3)
return 1;
return Fib(N-1) + Fib(N-2);
}
斐波那契递归的思想是类似于二叉树的,但是后面缺少了一部分,如图所示:
如果没有缺失的话就是完整二叉树,将缺少的部分设为
X
X
X,精确次数就是
F
(
N
)
=
2
0
2
1
2
2
.
.
.
2
N
−
1
−
X
=
2
N
−
1
−
X
F(N)=20+21+22+…+2{N-1}-X=2^N-1-X
F(N)=20+21+22+…+2N−1−X=2N−1−X,由于
X
X
X远小于
2
N
−
1
2^N-1
2N−1,故算法复杂度为
O
(
N
)
=
2
N
O(N)=2^N
O(N)=2N。
空间复杂度
空间复杂度定义
空间复杂度也是数学表达式,度量算法运行时临时额外占存空间的大小。同样空间复杂度不是无意义的实际占用的字节数,空间复杂度计算临时开辟变量的个数。基本规则规则和时间复杂度类似,也采用大O渐进表示法。
Example 1
void BubbleSort(int\* a, int n) {
assert(a);
for (size\_t end = n; end > 0; --end) {
int exchange = 0;
for (size\_t i = 1; i < end; ++i) {
if (a[i - 1] > a[i]) {
Swap(&a[i - 1], &a[i]);
exchange = 1;
}
}
if (exchange == 0)
break;
}
}
冒泡排序算法仅创建了常数个变量,所以空间复杂度是
O
(
1
)
O(1)
O(1)。
虽然变量
end
,i
每次循环都创建一次,但其实从内存角度看,每次所占空间并不会发生变化,一般都开辟在同一块空间。
Example 2
long long\* Fibonacci(size\_t n) {
if (n == 0)
return NULL;
long long\* fibArray = (long long\*)malloc((n + 1) \* sizeof(long long));
fibArray[0] = 0;
fibArray[1] = 1;
for (int i = 2; i <= n; ++i) {
fibArray[i] = fibArray[i - 1] + fibArray[i - 2];
}
return fibArray;
}
包括循环变量和该斐波那契数组,开辟量级为
N
N
N个的变量。故空间复杂度为
O
(
N
)
O(N)
O(N) 。
Example 3
long long Factorial(size\_t N)
{
if(N == 0)
return 1;
return Fac(N - 1) \* N;
}
每次递归创建一个栈帧,每个栈帧中都是常数个变量,
N
N
N次递归的空间复杂度为
O
(
N
)
O(N)
O(N) 。
递归的空间复杂度与递归深度有关。
Example 4
long Fibonacci(size\_t N)
{
if(N < 3)
return 1;
return Fib(N-1) + Fib(N-2);
}
斐波那契每次递归同样创建常数个变量,从斐波那契栈帧创建图中可以看出,递归中会有重复的项,这些重复的栈帧创建又销毁。空间不同于时间是可以重复利用的,所以这些重复的栈帧仅占用一次的空间。所以
F
i
b
(
N
)
Fib(N)
Fib(N),
F
i
b
(
N
−
1
)
Fib(N-1)
Fib(N−1),…,
F
i
b
(
1
)
Fib(1)
Fib(1)这些栈帧都分配一次的空间足矣。故时间复杂度为
O
(
N
)
O(N)
O(N) 。
常见复杂度
常见的算法复杂度如下表,复杂度由上到下依次递增:
简称 | 大O表示 | 示例 |
---|---|---|
常数阶 |
O
(
1
)
O(1)
O(1) |
k
k
k |
| 对数阶 |
O
(
l
o
g
n
)
O(logn)
O(logn) |
k
l
o
g
2
n
klog_2n
klog2n |
| 线性阶 |
O
(
n
)
O(n)
O(n) |
k
n
kn
kn |
| 对数阶 |
O
(
n
l
o
g
n
)
O(nlogn)
一、网安学习成长路线图
网安所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。
二、网安视频合集
观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
三、精品网安学习书籍
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、网络安全源码合集+工具包
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
img.cn/aa7be04dc8684d7ea43acc0151aebbf1.png)
二、网安视频合集
观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
三、精品网安学习书籍
当我学到一定基础,有自己的理解能力的时候,会去阅读一些前辈整理的书籍或者手写的笔记资料,这些笔记详细记载了他们对一些技术点的理解,这些理解是比较独到,可以学到不一样的思路。
四、网络安全源码合集+工具包
光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数网络安全工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年网络安全全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
[外链图片转存中…(img-6qhY16DQ-1715715071688)]
[外链图片转存中…(img-vsnAF0ik-1715715071689)]
[外链图片转存中…(img-Zgmwuuv5-1715715071689)]
[外链图片转存中…(img-F7fTGTt2-1715715071689)]
[外链图片转存中…(img-6LKaY7eX-1715715071690)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上网络安全知识点!真正的体系化!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!