【数据结构】集合框架、时间复杂度和空间复杂度
0 前言
-
数据结构:本身是与语言无关的抽象概念;在代码中,组织大量的数据,高效得进行增删改查。
-
类 是 现实问题中,实物的抽象表示。
-
抽象:现实中的实物,信息是非常多的。
写代码的时候,往往只需要提取中其中自己关心的部分,其他的大部分信息都忽略了。
比如:一个真实的大学生,包含的属性/信息非常多。
根据问题需求的不同,只需要提取其中的关键信息即可:
(1)发奖学金:姓名,班级,成绩 (2)组织王者荣耀比赛:姓名,班级,段位 (3)举办单身派对:姓名,性别,是否单身
- 集合类:数据结构在Java中的具体表现形式。
Java 标准库中,提供了一些类,供程序员直接使用;
其中有些类(集合类),就是前人已经实现好了的数据结构;
直接使用这些集合类,方便管理很多的数据。
一、集合框架
Java中的集合类,就是 抽象的数据结构,对应的具体实现 。
- 顺序表 ——> ArrayList
- 链表 ——> LinkedList
- 栈 ——> Stack
- 队列 ——> Queue
- 二叉树 ——> TreeSet / TreeMap
- 哈希表 ——> HashSet / HashMap
- 优先级队列 / 堆 ——> PriorityQueue
二、衡量算法的标准
数据结构:需要管理很多数据,高效方便得进行增删改查。
高效:
(1)时间上的高效:算得块
(2)空间上的高效:消耗的空间少
这两者,只和一段代码本身的实现方式有关,和机器硬件性能水平无关。
三、时间复杂度
3.1 时间复杂度的概念
- 算法的时间复杂度是⼀个数学函数,它定量描述了该算法的运行时间。
- 算法中的基本操作的执行次数,为算法的时间复杂度。
3.2 大O的渐进表示法:时间复杂度
-
作用:用来评价某个代码 / 某个数据结构 / 某个操作的效率。
-
实例:
3.3 常见时间复杂度计算举例
- 时间复杂度 实例1:
2. 时间复杂度 实例2:
// 计算func3的时间复杂度?
void func3(int N, int M) {
int count = 0;
for (int k = 0; k < M; k++) {
count++;
}
for (int k = 0; k < N ; k++) {
count++;
}
System.out.println(count);
}
无法判断M、N的差距是大还是非常接近,所以此代码的时间复杂度为 O(M+N)
- 时间复杂度 实例3:
【总结】
- O(1)只能说明执行次数和问题规模无关。
O(1)和 O(1)之间,实际的执行时间,可能会差别很大;可能有的O(1)确实很快,有的O(1)也很慢。- 时间复杂度,衡量的是 问题规模和时间的趋势变化。
给两个代码,一个时间复杂度为O(1),另一个位O(N),O(N)一定比O(1)慢吗?
不一定,因为时间复杂度衡量的是问题规模与时间之间的变化趋势,不能决定时间的快慢。
- 时间复杂度 实例4:
5. 时间复杂度 实例5:
类似于上述每次区间砍半的情况,时间复杂度就是O(log N)
O(N)增长趋势比O(log N)快。
- 时间复杂度 实例6:
// 计算阶乘递归factorial的时间复杂度?
long factorial(int N) {
return N < 2 ? N : factorial(N-1) * N;
}
- 虽然没有循环,但是有递归(所有的递归,理论上都能转换成循环)。
- 假设N为1,执行次数为1;N为2,执行次数为2;N为3,执行次数为3。
- 所以时间复杂度为O(N)
- 时间复杂度 实例7:
【总结】在谈到时间复杂度的时候,涉及到三种时间复杂度:
- 最好的情况下:数组本身就是有序的,只要冒泡一次就可以完成排序,时间复杂度为O(N)
- 平均情况下:数组本身为一般有序,一半无序
- 最差情况下(考虑最多的情况):数组本身非常无序,需要完成所有的冒泡操作,时间复杂度为O(N^2)
四、空间复杂度
4.1 空间复杂度概念
衡量的是代码运行中消耗掉的临时空间是多少。
举例:
给一个数组,长度为N(这里要占据N份空间,非临时空间),在后续代码中,并没有创建任何的临时空间(变量);空间复杂度,就是常数级空间复杂度O(1)。
4.2 大O的渐进表示法: 空间复杂度
1、 实例1:冒泡排序的空间复杂度
O(1),因为它只需要固定的三份空间(创建end、sotred、i,开辟空间)。
2. 实例:循环版本 斐波那契数列的空间复杂度
其中此代码的空间复杂度 要看 临时空间new long[ ] 与 n 之间的关系:
- 实例3:递归版本的 斐波那契数列 空间复杂度
【总结】
空间复杂度判断要点:
当前代码 谁是临时空间,以及这个临时空间随着N的变化是如何增长的。
如果N怎么变,临时空间都是固定的,空间复杂度为O(1);
如果临时空间跟N是线性增长,空间复杂度为O(N);
如果是指数增长,则为O(N^2)。