一、基本概念和术语
1、数据、数据元素、数据项和数据对象
- 数据:数据(Data)是客观事物的符号表示,是所有能输入到计算机中并被计算机程序处理的符号的总称
- 数据元素:数据元素(Data Element)是数据的基本单位,在计算机中通常作为一个整体进行考虑和处理
- 在有些情况下,数据元素也称为元素、记录等
- 数据项:数据项(Data Item)是组成数据元素的、有独立含义的、不可分割的最小单位
- 数据对象:数据对象(Data Object)是性质相同的数据元素的集合,是数据的一个子集
不论数据元素集合是无限集还是有限集,还有由多个数据项组成的复合数据元素的集合,只要集合内元素的性质均相同,都可称之为一个数据对象
2、数据结构
数据结构:数据结构(Data Structure)是相互之间存在一种或多种特定关系的数据元素的集合
数据结构是带 “结构”的数据元素的集合,“结构”就是指数据元素之间存在的关系
1)逻辑结构
数据的逻辑结构是从逻辑关系上描述数据,它与数据的存储无关,是独立于计算机的
数据的逻辑结构可以看作是从具体问题抽象出来的数学模型
同一逻辑结构采用不同的存储方法,可以得到不同的存储结构
数据的逻辑结构的要素
- 数据元素
- 关系
根据数据元素之间关系的不同特征,通常有四类基本结构(复杂程度依次递进):
- 集合结构
- 数据元素之间除了 “属于同一集合” 的关系外,别无其他关系
- 线性结构
- 数据元素之间存在一对一的关系
- 树结构
- 数据元素之间存在一对多的关系
- 图结构或网状结构
- 数据元素之间存在多对多的关系
其中集合结构、树结构和图结构或网状结构都属于非线性结构
- 线性结构:
- 线性表
- 栈和队列
- 字符串
- 数组
- 广义表
- 非线性结构:
- 树和二叉树
- 有向图和无向图
2)存储结构
数据对象在计算机中的存储表示称为数据的存储结构,也称为物理结构
Ⅰ、顺序存储结构
顺序存储结构是借助元素在存储器中的相对位置来表示数据元素之间的逻辑关系,通常借助程序设计语言的数组类型来描述
Ⅱ、链式存储结构
顺序存储结构要求所有的元素依次存放在一片连续的存储空间中,而链式存储结构,无需占用一整块存储空间
但为了表示结点之间的关系,需要给每个结点附加指针字段,用于存放后继元素的存储地址
链式存储结构通常借助于程序设计语言的指针类型来描述
3、数据类型和抽象数据类型
1)数据类型
数据类型:数据类型(Data Type)是一个值的集合和定义在这个值集上的一组操作的总称
2)抽象数据类型
抽象就是抽取出实际问题的本质
抽象数据类型:抽象数据类型(Abstract Data Type,ADT)一般指由用户定义的、表示应用问题的数学模型,以及定义在这个模型上的一组操作的名称
抽象数据类型包括三个部分:
- 数据对象
- 数据对象上关系的集合
- 对数据对象的基本操作的集合
抽象数据类型的定义格式:
ADT 抽象数据类型名{
数据对象:<数据对象的定义>
数据关系:<数据关系的定义>
基本操作:<基本操作的定义>
}ADT 抽象数据类型名
基本操作的定义格式:
基本操作名(参数表)
初始条件:<初始条件描述>
操作结果:<操作结果描述>
基本操作有两种参数:
- 赋值参数只为操作提供输入值
- 引用参数以 “&” 开头,除可提供输入值外,还将返回操作结果
初始条件描述了操作执行之前数据结构和参数应满足的条件,若初始条件为空,则省略操作结果说明了操作正常完成之后,数据结构的变化状况和应返回的结果
二、抽象数据类型的表示与实现
抽象数据类型的概念与面向对象方法的思想是一致的
抽象数据类型独立于具体实现,将数据和操作封装在一起,使得用户程序只能通过抽象数据类型定义的某些操作来访问其中的数据,从而实现了信息隐藏
- 表示部分
typedef struct{ // 复数类型
float Realpart; // 实部
float Imagepart; // 虚部
}Complex;
- 实现部分
void Create(&Complex C, float x, float y){
// 构造一个复数
C.Realpart=x;
C.Imagepart=y;
}
float GetReal(Complex C){
//取复数C=x+yi的实部
return C.Realpart;
}
float Getimag (Complex C){
//取复数C=x+yi的虚部
return C.Imagepart;
}
Complex Add(Complex Cl, Complex C2){
//求两个复数Cl和C2的和sum
Complex sum;
sum.Realpart = Cl.Realpart+C2.Realpart;
sum.Imagepart = Cl.Imagepart+C2.Imagepart;
return sum;
}
Complex Sub(Complex Cl, Complex C2){
//求两个复数Cl和C2的差difference
Complex difference;
difference.Realpart=Cl.Realpart-C2.Realpart;
difference.Imagepart=Cl.Imagepart-C2.Imagepart;
return difference;
}
三、算法与算法分析
1、算法的定义及特性
算法:算法(Algorithm)是为了解决某类问题而规定的一个有限长的操作序列
一个算法必须满足以下五个重要特征:
- 有穷性
- 一个算法必须总是在执行有穷步后结束,并且每一步都必须在有穷时间内完成
- 确定性
- 对每种情况下所对应执行的操作,在算法中都有确切的规定,不会产生二义性,使算法的执行者和阅读者都能明确其含义及如何操作
- 可行性
- 算法中的所有操作都可以通过已经实现的基本操作运算执行有限次实现
- 输入
- 一个算法有零个或多个输入
- 输出
- 一个算法有零个或多个输出
2、评论算法优劣的基本标准
- 正确性
- 在合理的数据输入下,能够在有限的运行时间内得到正确的结果
- 可读性
- 一个好的算法,首先应便于人们理解和相互交流,其次才是机器可执行性
- 健壮性
- 当输入的数据非法时,好的算法能适当地做出正确反应或进行相应处理,而不会产生一些莫名其妙的输出结果
- 高效性
- 高效性包括时间和空降两个方面
- 时间高效是指算法设计合理,执行效率高,可以用时间复杂度来度量
- 空间高效是指算法占用存储容量合理,可以用空间复杂度来度量
- 时间复杂度和空间复杂度是衡量算法的两个主要指标
- 高效性包括时间和空降两个方面
3、算法的时间复杂度
1)问题规模和语句频度
问题规模:问题规模是算法求解问题输入量的多少,是问题大小的本质表示,一般用整数 n 表示
一个算法的执行时间大致上等于其所有语句执行时间的总和
语句的执行时间则为该条语句的重复执行次数和执行一次所需时间的积
一条语句的重复执行次数称作语句频度(Frequency Count)
求两个 n 阶矩阵的乘积算法
for(i=1; i<=n; j++){ // 频度为 n+1
for(j=1; j<=n; j++){ // 频度为 n * (n+1)
c[i][j] = 0; // 频度为 n * n
for(k=1; k<=n; k++) // 频度为 n * n * (n+1)
c[i][j] = c[i][j] + a[i][k] * b[k][j]; // 频度为 n * n *n
}
}
该算法中所有语句频度之和,是矩阵阶树 n 的函数,用 f(n) 表示。即上述算法的执行时间于 f(n) 成正比
2)算法的时间复杂度定义
一般情况下, 算法中基本语句重复执行的次数是问题规模 n 的某个函数 f(n), 算法的时间量度记作
它 表示随问题规模 n 的增大, 算法执行时间的增长率 和 f(n) 的增长率相同, 称做算法的渐近时间复杂度, 简称时间复杂度(TimeComplexity)
3)算法的时间
常见的时间复杂度按数量级递增排列依次为:
常量阶 、对数阶
、线性阶
、线性对数阶
、平方阶
、立方阶
、……、K次方阶
、指数阶
等
一般情况下,随着 n 的增大, T(n) 的增长较慢的算法为较优的算法
4)最好、最坏和平均时间复杂度
算法在最好情况下的时间复杂度为最好时间复杂度,指的是算法计算量可能达到的最小值
算法在最坏情况下的时间复杂度为最坏时间复杂度,指的是算法计算量可能达到的最大值
算法的平均时间复杂度是指算法在所有可能情况下,按照输入实例以等概率出现时,算法计算量的加权平均值
4、算法的空间复杂度
渐近空间复杂度(Space Complexity)作为算法所需存储空间的量度,简称空间复杂度,它也是问题规模 n 的函数, 记作:
一般情况下,一个程序在机器上执行时,除了需要寄存本身所用的指令、 常数、变量和输入数据外,还需要一些对数据进行操作的辅助存储空间。其中,对千输入数据所占的具体存储量取 决千问题本身,与算法无关,这样只需分析该算法在实现时所需要的辅助空间就可以了。若算 法执行时所需要的辅助空间相对千输入数据量而言是个常数, 则称这个算法为原地工作
辅助空间为 O(1)
通常情况下, 鉴于运算空间较为充足, 人们都以算法的时间复杂度作为算法优劣的衡量指标
一 叶 知 秋,奥 妙 玄 心