数据结构基础知识补充
数据结构基础知识补充
- 参考文章:
https://blog.csdn.net/f553762019/article/details/107939161
1.定义
数据结构:是相互之间存在一种或多种特定关系的数据元素集合。
1.1 基本结构
- 集合
- 线性结构
- 树形结构
- 图状结构
- 网状结构
2.算法分析
2.1 算法
算法:是对特定 问题求解步骤的一种描述,它是指令的有限序列,其中每一条指令表示一个或多个操作。
- 一个算法还具有5个重要特性:
- 有穷性
- 确定性
- 可行性
- 输入
- 输出
2.2 算法设计的要求
- 正确性
- 可读性
- 健壮性
- 效率与低存储量需求
2.3算法效率的度量
- 事后统计法
- 事前分析估算法。
2.3.1时间复杂度
在如下所示的两个N*N
矩阵相乘的算法中,"乘法"运算是"矩阵相乘问题"的基本操作。整个算法执行时间与该基本操作(乘法)重复执行的次数 n3 成正比。记作T(n)=O(n3)。
// N*N矩阵相乘的算法
for(i=1;i<=n;++i){
for(j=1;j<=n;++j){
c[i][j]=0;
for(k=1;k<=n;++k){
c[i][j]+=a[i][j]*b[k][j];
}
}
}
一般情况下,算法中基本操作重复执行的次数是问题规模 n 的某个函数 f(n),算法的时间度量记作T(n)=O(n)
;
它表示虽问题规模 n 的增大,算法执行时间的增长率和 f(n) 的增长率相同,称做算法的渐进时间复杂度,简称时间复杂度;
-
常见的时间复杂度量级
- 常数阶O(1)
- 对数阶O(log N)
- 线性阶O(n)
- 线性对数阶O(n log N)
- 平方阶O(n2)
- 立方阶O(n3)
- K次方阶O(nk)
- 指数阶(2n)
-
常数阶O(1)
无论代码执行了多少行,只要是没有循环等复杂结构,那这个代码的时间复杂度就都是O(1),如:
int i = 1;
int j = 2;
++i;
j++;
int m = i + j;
上述代码在执行的时候,它消耗的时候并不随着某个变量的增长而增长,那么无论这类代码有多长,即使有几万几十万行,都可以用O(1)来表示它的时间复杂度。
-
线性阶O(n)
这个在最开始的代码示例中就讲解过了,如:
for(i=1; i<=n; ++i)
{
j = i;
j++;
}
-
这段代码,for循环里面的代码会执行n遍,因此它消耗的时间是随着n的变化而变化的,因此这类代码都可以用O(n)来表示它的时间复杂度。
-
对数阶O(log N)
int i = 1; while(i<n) { i = i * 2; }
- 从上面代码可以看到,在while循环里面,每次都将 i 乘以 2,乘完之后,i 距离 n 就越来越近了。我们试着求解一下,假设循环x次之后,i 就大于 2 了,此时这个循环就退出了,也就是说 2 的 x 次方等于 n,那么 x = log 2n。也就是说当循环 log 2n 次以后,这个代码就结束了。因此这个代码的时间复杂度为:O(log n)
-
线性对数阶O(n log N)
- 线性对数阶O(n log N) 其实非常容易理解,将时间复杂度为O(log n)的代码循环N遍的话,那么它的时间复杂度就是 n * O(log N),也就是了O(n log N)。
- 就拿上面的代码加一点修改来举例:
for(m=1; m<n; m++) { i = 1; while(i<n) { i = i * 2; } }
-
平方阶O(n2)
-
平方阶O(n²) 就更容易理解了,如果把 O(n) 的代码再嵌套循环一遍,它的时间复杂度就是 O(n²) 了。 举例:
-
for(x=1; i<=n; x++) { for(i=1; i<=n; i++) { j = i; j++; } }
-
这段代码其实就是嵌套了2层n循环,它的时间复杂度就是 O(n*n),即 O(n²)
如果将其中一层循环的n改成m,即: -
for(x=1; i<=m; x++) { for(i=1; i<=n; i++) { j = i; j++; } }
-
那它的时间复杂度就变成了 O(m*n)
-
-
立方阶O(n³)、K次方阶O(n^k)
- 参考上面的O(n²) 去理解就好了,O(n³)相当于三层n循环,其它的类似。
- 除此之外,其实还有 平均时间复杂度、均摊时间复杂度、最坏时间复杂度、最好时间复杂度 的分析方法,有点复杂,这里就不展开了。
2.3.2 空间复杂度
类似于算法的时间复杂度,本书中以空间复杂度,作为算法所需存储空间的量度,记作S(n)=O(f(n))
空间复杂度是对一个算法在运行过程中临时占用存储空间大小的一个量度,同样反映的是一个趋势,我们用 S(n) 来定义。
空间复杂度比较常用的有:O(1)、O(n)、O(n²),我们下面来看看:
-
空间复杂度O(1)
如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1)
举例:
int i = 1;
int j = 2;
++i;
j++;
int m = i + j;
代码中的 i、j、m 所分配的空间都不随着处理数据量变化,因此它的空间复杂度 S(n) = O(1)
-
空间复杂度O(n)
int[] m = new int[n] for(i=1; i<=n; ++i) { j = i; j++; }
这段代码中,第一行new了一个数组出来,这个数据占用的大小为n,这段代码的2-6行,虽然有循环,但没有再分配新的空间,因此,这段代码的空间复杂度主要看第一行即可,即 S(n) = O(n)