数据结构与算法概论
第一节 数据结构介绍
程序设计 = 数据结构 + 算法
数据结构包含: 逻辑结构与物理结构
逻辑结构:
数据对象中的数据元素间的相互关系
物理结构
数据的逻辑结构在计算机中的存储形式
四种逻辑结构:
- 集合结构
- 线性结构 元素关系:一对一
- 树形结构 元素关系:一对多 层次结构
- 图形结构 元素关系:多对多
两种存储结构
- 顺序存储
- 链式存储
第二节 算法介绍
算法的五个基本特征
-
输入 :算法有0个或多个输入。
-
输出 :算法有1个或多个输出。
-
有穷性 :算法在执行有限个步骤后,会自动结束。不会出现无限循环并且每一个步骤都在可接受的时间内完成。
-
确定性 :算法的每个步骤都有确定的含义,不会出现二义性。算法在一定条件下,只有一条执行路径,相同的输入,只能有唯一的输出结果。算法的每步都该被精确地定义而无歧义。
-
可行性 :每一步都能通过有限次执行完成。
算法不唯一
算法的设计要求
- 正确性:指算法至少且有输入、输出和加工处理。算法无歧义,能正确反应问题需求,得到问题的正确答案。
- 可读性:便于他人阅读修改。
- 健壮性:输入不合法数据可作出相关处理。
- 时间效率高,存储量低
算法效率的度量方法
影响算法效率的原因
- 算法采用的策略方案
- 编译产生代码的质量
- 问题的输入规模
- 机器执行指令的速度
用大写的O( ) 来体现算法时间复杂度的记法,称之为大O记法。
一般情况下,随着输入规模n的增长,T(n) 增长最慢的算法称之为最优算法。
第三节 推导大O阶的常用方法
-
用常数 1 取代运行时间中所有加法常数。
-
修改后运行次数函数中,只得保留最高次项。
-
若最高次项存在且不唯一,则去除与这项相乘的常数项。
推导常数阶:
常数阶只有O(1);
推导线性阶:
随着问题规模的扩大,对应计算次数呈直线增长 O(n)
推导平方阶:
嵌套循环求时间复杂度常用方法:
栗1:
int i,j,n=100;
for( i=0;i < n; i++)
{
for(j=0 ;j < n;j++)
{
printf("n");
}
}
解法:
两层嵌套循环,n=100;外层每执行一次,内层执行100次,即100*100,O(n²);
栗2:
int i,j,n=100;
for( i=0;i < n; i++)
{
for(j=i ;j < n;j++)
{
printf("n");
}
}
解法:
当i=0时,内循环执行了n次,
当i=1时,内循环则执行n-1次,
…
当i=n-1时,内循环执行1次,
所以总的执行次数应该是:
n+(n-1)+(n-2)+…+1 = n(n+1)/2(高斯算法)
对上式子进行化简:
n(n+1)/2 = n²/2 + n/2;
根据推导大O方法:
第一条忽略,因为没有常数相加。
第二条只保留最高项,所以n/2这项去掉。
第三条去除与最高项相乘的常数,最终得O(n²)。
推导对数阶:
栗1:
int i =1,n = 100;
while(i < n)
{
i = i*2;
}
由于每次i*2之后,就举例n更近一步,假设有X个2相乘后大于或等于n,则会退出循环。于是由2^x = n得到x = log(2)n,所以这个循环的时间复杂度为0(log n)。
常见时间复杂度
空间复杂度计算公式
S(n) = O(f(n));