数据结构_day02_08-30
1、绪论
1. 基本概念和术语
- 数据类型
一个值的集合和定义在这个值集上的一组操作的集合
高级语言中,显式或隐式规定在程序执行期间变量和表达的所有可能的取值范围
- 抽象数组类型(ADT)
抽象:抽取出实际问题的本质
形式定义:(D,S,P)三元组
D是数据对象
S是D的关系集
P是对D的基本操作集
定义格式:
ADT 抽象数据类型名{
数据对象: <数据对象的定义>
数据类型: <数据关系的定义>
基本操作: <基本操作的定义>
}ADT 抽象数据类型名
基本操作的定义格式:
基本操作名(参数表)
初始操作: <初始条件描述>
操作结果: <操作结果描述>
2. 抽象数据类型的表示与实现
以实现虚数抽象数据结构为例:
// 定义数据对象及其关系
struct Complex
{
float realpart;
float imagpart;
};
// 打印复数
void PrintComplex(struct Complex* p)
{
if (p->imagpart > 0)
{
printf("%.2f+%.2fi\n", p->realpart, p->imagpart);
}
else if (p->imagpart == 0)
{
printf("%.2f\n", p->realpart);
}
else
{
printf("%.2f%.2fi\n", p->realpart, p->imagpart);
}
}
// 声明基本操作
void Assign(struct Complex* p, float real, float imag);
void Add(struct Complex* p, float real, float imag);
void Minus(struct Complex* p, float real, float imag);
void Multiply(struct Complex* p, float real, float imag);
void Divide(struct Complex* p, float real, float imag);
int main()
{
struct Complex complex = { 1.0f, 1.0f };
//Add(&complex, 1.0f, -1.0f);
//Minus(&complex, 2.0f, 3.0f);
//Multiply(&complex, 3.0, 2.0);
Divide(&complex, 1.0f, 1.0f);
PrintComplex(&complex);
return 0;
}
// 实现基本操作
// 构造
void Assign(struct Complex* p, float real, float imag)
{
p->realpart = real;
p->imagpart = imag;
}
// 加
void Add(struct Complex* p, float real, float imag)
{
p->realpart += real;
p->imagpart += imag;
}
// 减
void Minus(struct Complex* p, float real, float imag)
{
p->realpart -= real;
p->imagpart -= imag;
}
// 乘
void Multiply(struct Complex* p, float real, float imag)
{
float tmp = p->realpart;
p->realpart = p->realpart * real - p->imagpart * imag;
p->imagpart = tmp * imag + p->imagpart * real;
}
// 除
void Divide(struct Complex* p, float real, float imag)
{
struct Complex tmp = { real, -1 * imag };
float fm = real * real + imag * imag;
Multiply(&tmp, p->realpart, p->imagpart);
p->realpart = tmp.realpart / fm;
p->imagpart = tmp.imagpart / fm;
}
3. 算法和算法分析
算法:解决特定问题的方法和步骤
算法的描述:
- 自然语言
- 流程图:传统流程图(框图)、NS流程图(盒图)
- 伪代码
- 程序代码
算法的特性:
- 有穷性:一个算法必须总是在执行有穷步骤之后结束,且每一步都在有穷时间内完成
- 确定性:每一条指令必须有确切的含义
- 可行性:算法描述的操作可以通过已经实现的基本操作执行有限次来实现
- 输入
- 输出
评价算法的标准:
- 正确性:在合理的数据输入下,在有限的运行时间内可以得到正确的结果
- 可读性:算法应易于人的理解
- 健壮性:当输入非法数据时,可以适当地做出正确反应或做出相应处理
- 高效性:消耗尽量少的时间和空间
4. 时间复杂度
算法时间效率的度量:
算法执行所消耗的时间
度量方法:
事前分析:估算
事后统计:实际运行程序测算
(由于事后统计需要实现算法,且较依赖于软硬件等环境因素,从而造成误差)
算法运行时间 = ∑(一个简单操作所需的时间 * 简单操作次数)
注:每条语句的执行次数也称为语句频度
由于计算机的软硬件环境会影响语句的执行时间,故可简化为只考虑语句频度
另外,可以再进行简化,即仅考虑其数量级,忽略其倍数
最终,可简化为T(n) = O(f(n)),称为算法的渐进时间复杂度,简称时间复杂度
其中,f(n)是T(n)的同数量级函数(时间增长率与fn增长率相同)
例:
T(n) = 2n^3 + 3n^2 + 2n + 1
当n->∞时,T(n) / n^3 -> 2,为非零常数,故T(n)与n^3是同数量级,该算法时间复杂度为O(n^3)
一般情况下,不必计算所有的执行次数,仅找到最大次数即为该算法的时间复杂度
时间复杂度的计算:
- 找出语句频度最大的那条语句作为基本语句
- 计算基本语句的频度得到问题规模n的某个函数f(n)
- 取其数量级用符号"O"表示