Day1 绪论
1. 数据结构
1.1 数据结构是什么
什么是数据结构?
- 程序设计 = 数据结构 + 算法
- 数据结构: 数据元素相互之间存在的一种或多种特定关系的集合
传统上:数据结构 = 逻辑结构 + 物理结构
- 逻辑结构:数据对象中数据元素中的相互关系
- 物理结构:数据的逻辑结构在计算机中的存储形式。
1.2 逻辑结构
-
集合结构: 除了属于一个集合外,没有其它任何关系
-
线性结构:
-
树型结构:
-
图形关系:
1.3 物理结构
物理结构,研究的是,如何把数据元素存储到计算机的存储器中。
- 存储器主要是针对内存而言,外部存储器常用文件结构来描述。
- 数据元素存储形式有两种:顺序存储 和 链式存储
-
顺序存储结构: 把元素存储在地址连续的存储单元里,数据间的逻辑关系和物理单元是一致的。(下图是物理结构,表现为紧挨着)
-
链式存储结构: 数据元素存放在任意的存储单元里,然后在这一个数据元素上放一个指针,来记录下一个数据元素的地址。(因为存放了指针,所以更费空间)
2. 算法
算法就是解决问题的技巧和方式。
- 如何计算 1 + 2 + … + 99 + 100 的值?有的人可能会一个个加过去,有的人会一个个加过去,有的人会使用等差数列(这个算法是高斯在小学发明的)。
- 一个问题可以由多个算法解决,一个算法不可能有通解所有问题的能力。
2.1 算法的五个基本特征
- 输入
- 输出
- 有穷性
- 确定性
算法的每一条步骤都有确定的含义,不会出现二义性,不会有歧义。
算法在一定条件下,只有一条执行路径。相同的输入只能有一个输出的结果。 - 可行性
每一步都可以在当前环境下执行有限次数完成(算法可以注明自己需要的环境)
2.2 算法设计的要求
1. 正确性 (大致分为四层次)
- 算法程序没有语法错误
- 算法程序对于合法输入能够产生满足要求的输出
- 算法程序对于非法输入能够产生满足要求的说明
- 算法程序对于故意刁难的测试输入都有满足要求的输出结果
2. 可读性
- 算法设计的另一目的是为了便于阅读理解和交流
- 写代码的目的,一方面是为了让自己理解执行。另一方面是为了便于自己或他人阅读修改。
3. 时间效率高 & 存储量低
Day2~3 时间复杂度&空间复杂度
1. 学习前准备
如何计算算法效率呢?
1.1 两种计算方法
1.1.1 事后统计方法
需要事先编制好测试程序。利用计算机计时器对不同算法编制的运行时间做比较,从而确定算法效率的高低。
- 缺点:
- 编制测试程序需要花费时间和精力。
- 不同测试环境的差别还非常之大。
1.1.2 事前分析估算方法
在计算机重新编写前,依据统计方法对算法进行估算。
- 影响因素:
- 算法的策略,方案
- 编译参数的代码质量
- 问题的输入规模
- 机器执行指令的速度
由此可见: 除了软硬件之外,就是算法的好坏和问题的输入规模。
1.2 为什么只用高阶阶数
1.2.1 示例
计算1~100相加
- 算法1:
for(int i = 1, n = 100, sum = 0; i <= n; i++) {
// 执行 1+n+1 次
sum = sum + i; // 执行 n 次
}
- 初始化方法执行 1 次
- 条件判断执行 n+1 次(1次是判断不成功时跳出循环)
- 函数体执行n次
总共 2n + 2 次
- 算法2:
int sum = 0, n = 100; // 执行1次
sum = (1 + n) * n / 2; // 执行1次
总共 2 次
1.2.2 说明
- 不关心编写程序的语言是什么,也不关心程序跑在什么样的计算机上,只关心实现的算法。
- 最重要的是,把一系列的步骤抽象出来。
- 把基本操作的数量和输入模式关联起来。
所以上面的算法1和算法2的关系,是n和1的关系。
1.2.3 函数的渐进增长
给定两个函数f(n) 和 g(n),如果存在一个整数N,使得对于所有的n > N, f(n) 总是比g(n)大,那么,我们说f(n)的渐进增长快于g(n)。
- f(n) = 3n + 1
- g(n) = 2n + 3
- N = 2
- 存在n > N时,f(n) > g(n),所以f(n)的渐进增长快于g(n)
可以使用相关工具(如Excel或matlab),进行绘图。会发现,当n足够大时,似乎只与最高阶阶数相关,其它因素可以忽略不计。
判断一个算法效率时: 函数中的常数和次要项常常快于忽略,而更应该关注主项(最高项)的阶数。
2. 时间复杂度
2.1 大O表示法
在进行算法分析时,语句总的执行次数 T(n)是关于问题规模 n的函数,进而分析T(n)随n的变化情况并确定T(n)的数量级 。算法的时间复杂度,也就是时间量度,记做: T ( n ) = O ( f ( n ) ) T(n) = O(f(n)) T(n)=O(f(n))它表示随问题规模n的增大,算法执行时间的增长率和f(n)的增长率 相同,称作算法的渐进时间复杂度,简称为时间复杂度 。其中f(n)是问题规模n的某个函数。(意思是,看重潜力,而不是当前。)
- 用 O ( ) O() O()来体现算法时间复杂度的记法,被称为大O表示法 。
- 随着输入规模n的增大,T(n)增长最慢的算法,一般为最优算法。
- 1.2.2中,三条曲线算法的时间复杂度分别为 O ( 1 ) O(1) O(1), O ( n ) O(n) O(n), O ( n 2 ) O(n^2) O(n