1、数据结构
数据结构是相互之间存在一种或多种关系的数据的集合。
1.1 三要素
- 数据结构三要素是:1.数据的逻辑结构;2.数据的物理结构;3.数据的运算。
- 数据结构是相互之间存在一种或多种特定关系的数据元素的集合。
1.1.1 逻辑结构
分为线性结构和非线性结构,
- 线性结构:线性表、栈、队列
- 非线性结构:树、图、集合
1.1.2 存储结构
即物理结构,分四种(存储数据时不只要存储元素的值,还要存储数据元素间的关系)
- 顺序存储:存储位置在物理上连续
- 链接存储:链表形式(不同结点存储空间不一定连续,但是结点内存储单元地址必须连续)
- 索引存储:使用 1 个数组记录索引
- 散列存储:根据元素关键字计算该元素存储地址,如Hash存储
1.1.3 逻辑结构
- 集合结构:数据元素除了同属于一个集合之外,没有其他关系;
- 线性结构:数据元素之间是一对一的关系;
- 树形结构:数据元素之间存在一种多对多的层次关系;
- 图形结构:数据元素之间是多对多的关系;
1.2 数据类型
- 原子类型:不可再分的数据类型
- 结构类型:其值可以再分成若干成分的数据类型
- 抽象数据类型 (ADT):一个数学模型以及定义在该模型之上的一组操作,通常用数据对象、数据关系、基本运算操作集这样三元组表示
2、算法的度量
2.1 时间复杂度
时间复杂度就是程序逻辑执行的次数。通常在求解时间复杂度的时候,会对其进行简化。下面是推导大 O 阶的方法:
- 用常数1取代运行时间中的所有加法常数
- 在修改后的运行次数函数中,只保留最高阶项;
- 如果最高阶项存在且不是 1,则去除与这个项相乘的常数。
常见的时间复杂度:
2.2.1 常数阶
int num = 0, n = 100;
num = (1 + n) * n / 2;
printf(num);
主义上面的时间复杂度是常数阶 O(1),而不是 O(3).
2.2.2 线性阶
for(int i=0; i<n; i++) {
// 执行时间复杂度为O(1)的操作
}
上面的时间复杂度是 O(n).
2.2.3 对数阶
int cnt = 1;
while (cnt < n) {
cnt *= 2;
// 执行时间复杂度为O(1)的操作
}
上面的时间复杂度是 O(logn).
2.2.4 平方阶
int i, j;
for (int i=0;i<n;i++) }
for (int j=0;j<n;j++) {
// 执行时间复杂度为O(1)的操作
}
}
上面的计算的时间复杂度是 O(n2)
int i, j;
for (int i=0;i<n;i++) }
for (int j=0;j<m;j++) {
// 执行时间复杂度为O(1)的操作
}
}
上面的计算的时间复杂度是 O(nm)
下面的程序的时间复杂度也是 O(n2):
int i, j;
for (int i=0;i<n;i++) }
for (int j=i;j<n;j++) {
// 执行时间复杂度为O(1)的操作
}
}
执行的次数,O(f(n)),其中 f(n) 是执行的次数,表示执行时间与 f(n) 成正比
时间复杂度的大小关系:
O(1)<O(log2n)<O(n)<O(nLogn)<O(n^2)<O(n^3)<O(2^n)<O(n!)<O(nn)
2.2 空间复杂度
所需的物理存储空间
题目:算法
void fun(int n){
int i=1;
while(i<=n) {
i*=2;
}
}
的时间复杂度是?
思路:函数中运算次数最多的是 i*=2; 这一行,那么假设它执行了 t 次,t 次时 i=2^t。
因此,有:2^t<=n,于是得 t