数据结构 与 算法
一、基本概念和术语
1.1 数据、数据结构
数据:是描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。比如整型等数值类型、字符、声音、视频、图像等。
数据结构:是互相之间存在一种或多种特定关系的数据元素的集合。
1.2 算法
算法:是解决特定问题求解步骤的描述,在计算机中表现为指令的有限序列,且每条指令表示一个或多个操作。
算法的特性:
- 输入输出:算法有零个输入或多个输入,至少有一个或多个输出
- 有穷性:执行有限的步骤后就会有结果,不会出现无限循环,每个步骤在可接受的时间内完成
- 确定性:算法的每一步都具有确定的含义,不会出现二义性
- 可行性:算法的每个步骤都是可行的,每一步都能得到正确的结果
算法的设计要求:
- 正确性:指算法至少应该具有输入输出和加工处理无歧义性、能正确反映问题的需求,能得到问题的正确答案
- 可读性:要便于阅读、理解和交流
- 健壮性:输入数据不合法时,也能做出相关处理,不产生异常或其他错误
- 时间/空间效率:时间效率高,存储空间低
二、时间复杂度(大O阶)
算法效率的度量有两种方式:一、事后统计:通过设计好的测试代码和数据,比较运行时间来确定算法效率的高低;二、事前估算:在写代码前,依据统计方法对算法进行估算。
第一种事后统计的方式有很多弊端,事后补救成本很高;所以一般会通过第二种事前估算的方式来统计算法的效率。
大O阶的时间复杂度就是事前分析统计。
2.1 时间复杂度
算法的时间复杂度,记作:T(n)= O(f(n))表示随着问题规模n的增加,算法执行时间增长率。一般随着n的增加,T(n)增长最慢的算法为最优算法。
一般使用大O阶来表示算法的时间复杂度,常见的算法复杂度如下:
2.2 大O阶的推导方法
1、用常数1取代所有加法常数
2、在修改后的运行次数函数中,只保留最高阶项
3、如果最高阶项存在且不是1,则去除与这个项相乘的常数得到的结果就是大O阶
2.2.1 常数阶
int sum = 0, n = 100;
sum = (n + 1) * n / 2;
System.out.println(sum);
这个算法的运行次数是f(n)= 3,依据上面的方法,用常数1取代所有加法常数3,然后没有高阶项,所以这个算法的时间复杂度就是常数阶O(1)。
2.2.2 线性阶
for (i = 0; i<n; i++) {
// 时间复杂度为O(1)的程序步骤序列
}
循环体中需要执行n次,因此时间复杂度是O(n)。
2.2.3 对数阶
while (i < n) {
i = i * 2;
// 时间复杂度为O(1)的程序步骤序列
}
,即,也就是要执行次,所以时间复杂度是O()。
2.2.4 平方阶
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
// 时间复杂度为O(1)的程序步骤序列
}
}
对于外部循环,是把内部时间复杂度为O(n)的代码,再执行 n 次。所以上面的时间复杂度是O()。
2.3 最坏情况与平均情况
比如我们在n个随机数中查找某个数,最好的情况是我们查找的第一个数就是这个数,时间复杂度就是O(1),若最后一个才是要找的数,那时间复杂度就是O(n),这是最坏的情况。
一般没有特别说明的,都是指的最坏时间复杂度。