绪论1
1.1 什么是数据结构的定义
1.1.1数据结构的定义
数据是描述客观事物的数和字符的集合。是所有能被输入能够输入到计算机中,且能被计算机处理的符号的集合。而数据结构中主要讨论结构化数据。示例,一张学生表:
学号 | 姓名 | 性别 | 班号 |
1 | 张三 | 男 | 1802 |
3 | 小明 | 男 | 1801 |
6 | 小红 | 女 | 1802 |
9 | 李四 | 男 | 1803 |
注:第1行称为数据项(用于描述数据元素),第2行到第5行称为数据元素。
数据元素:是数据集合中的一个“个体”,它是数据的基本单位。
数据项:数据项是用来描述数据元素的,它是数据的最小单位。
数据对象:具有相同性质的若干个数据元素的集合,如整数数据对象是所有整数的集合。默认情况下,数据结构讨论的数据都是数据对象。数据对象需要数据元素的类型都是相同,否则不能称之为数据对象。
数据结构:是指带结构的数据元素的结合。
数据元素之间的关系→结构,现实世界的结构是纷繁复杂的!例如微观世界——DNA结构,宏观世界——建筑物的结构。数据结构讨论的元素关系主要是相邻关系或邻接关系。数据结构的3个方面:逻辑结构,存储结构,数据运算。
数据结构=数据+结构。
(1) 数据的逻辑结构:由数据元素之间的逻辑关系构成。
(2) 数据的存储结构:数据元素及其关系在计算机存储器中的存储表示,也称为数据的物理结构。
(3) 数据的运算:施加在该数据上的操作。
1.1.2 逻辑结构
数据的逻辑结构是从数据元素的逻辑结构关系上描述数据的,是指数据元素之间的逻辑关系的整体,通常是从求解问题中提炼出来的。
(1) 图表表示,如上述的学生表。假设用“学号”唯一标识数据元素,数据表的逻辑结构图形表示如图:
①→③→⑥→⑨
(2) 二元组表示:B=(D,R),D={di|1≤i≤n,0≤n},R={ri|1≤i≤m,0≤m},对于r中的任意序偶<x,y>(x,y∈D),表示元素x和元素y之间是相邻的,x称为该序偶的第一元素,y称为该序偶的第二元素,而且x为y的直接前驱元素,y为x的直接后继元素。若某个元素没有前驱元素,则称该元素为开始元素;若某个元素没有后继元素,则称该元素为终端元素。对于对称序偶,可用圆括号代替尖括号,即(x,y)∈r。在用图形表示逻辑关系时,对称序偶用不带箭头的连线表示。
(3) 逻辑结构的类型:集合、线性结构、树形结构。
(4) 图形结构:元素之间存在多对多关系。与属性结构统称为“非线性结构”。
1.1.3 存储结构
数据逻辑结构在计算机存储器中的存储表示称为数据的存储结构(也称为映像),也就是逻辑结构在计算机中的存储实现。
(1) 顺序存储结构:数据元素之间的逻辑结构关系由存储单元地址间关系隐含表示。
(2) 链式存储结构:每个逻辑元素用一个内存结点存储,给每个结点附加指针域,用于存放相邻结点的存储地址。
(3) 索引存储结构:在存储数据元素信息的同时还建立附加的索引表。
(4) 哈希(或散列)存储结构:根据元素的关键字通过哈希(或散列)函数直接计算出一个值,并将这个值作为该元素的存储地址。
1.1.4 数据运算
数据运算是指数据实施的操作。
1.1.5 数据类型和抽象数据类型
(1) 数据类型:一组性质相同的值相同的值的集合和定义在此集合上的一组操作的总称,是某种程序设计语言中已实现的数据结构。C/C++常用的数据类型
① C/C++的基本数据类型:int,bool,float,double,char。int型可以有3个修饰符,short,long,unsigned。
② C/C++的指针类型:允许直接对存放变量的地址进行操作。
③ C/C++的数组类型:同一数据类型的数据元素的集合。
④ C/C++的结构体类型:由一组被称为结构体的成员的数据项组成的,每个结构体成员都有自己的表示符,也称为数据域。一个结构体类型中的所有成员的数据类型可以不相同。
⑤ C/C++语言中的共用体类型:把不同的成员组织为一个整体,它们在内存中共享一段存储单元,但不同成员以不同的方式被解释。
⑥ C/C++语言中的自定义类型:允许使用typedef关键字来指定新的数据类型。
(2) 存储空间的分配:定义变量就是使用内存空间。
① 静态存储空间分配方式:在程序编译期间分配固定的存储空间的方式,保持不变到程序结束。
② 动态存储空间分配方式:在程序运行期间根据需要动态地分配存储空间的方式。如 malloc()/free() 函数对。用 malloc() 函数为一个指针变量(如p指针)分配一片连续的空间,当不再需要时用 free() 函数释放 p 所指向的空间。
(3) 抽象数据类型,指用户进行软件系统设计时从问题的数学模型中抽象出来的逻辑数据结构和逻辑数据结构上的运算,而不考虑计算机的具体存储结构和运算的具体的实现算法。
1.2 算法及其描述
1.2.1 什么是算法
算法是对特定问题求解步骤的一种描述,它是指令的有限序列。(其中每一条指令表示计算机的一个或多个操作)
(1) 有穷性:任何不会终止的算法都是没有意义的。有穷步,每步花费有穷时间。
(2) 确定性:任何条件下算法都只有一条执行路径,即对于相同的输入只能得出相同的输出,不能有二义性。(?随机数)
(3) 可行性:算法中的每个动作能够被机械第执行。
(4) 有输入:有0个或多个输入,作为算法加工对象的量值。
(5) 有输出:一个算法有一个或多个输出。
1.2.2 算法设计的目的
(1) 正确性:要求算法能够正确执行预先规定的功能和性能要求。
(2) 可使用性:用户友好性。
(3) 可读性:算法的逻辑必须是清晰的、简单的和结构化的。
(4) 健壮性:要求算法具有很好的容错性,即提供异常处理,能够对不合理的数据进行检查。
(5) 高效率与第存储量需求:执行时间短,算法执行过程中所需的最大存储空间不大。
1.2.3 算法描述
算法描述的一般格式和设计步骤:
返回值 函数名 (参数列表){
定义临时变量
函数体
}
算法设计的一般步骤:
① 分析算法的功能。
② 确定输入与输出。
③ 设计函数体。
输出型参数的设计,示例:
void swap1(int x, int y){
int tmp;
tmp=x;x=y;y=tmp;
}
上述代码,由于形参x,y既是输入型参数,也是输出型参数,而swap1(x,y)中仅是将形参x,y作为输入型参数设计。
改正方法1:采用指针的方式来回传形参的值,
void swap2(int *x, int *y){
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
可读性较差,改正方法2:采用引用型形参,也就是将输出型形参设计为引用型形参。
void swap3(int &x, int &y){
int tmp = x;
x = y; y = tmp;
}
1.3 算法分析
1.3.1 算法分析概述
算法分析就是分析算法占用计算机资源的多少。占用CPU时间——时间性能分析;占用内存空间——空间性能分析。
1.3.2 算法时间性能分析
事后统计法,就是编写算法对应程序,统计其执行时间。
事前估计法,仅考虑算法本身,“运行工作量”只与问题规模有关。
(1) 计算算法的频度T(n),一个算法是由控制结构(顺序、分支和循环)和原操作(只固定数据类型的操作)构成的。
(2) T(n)用“O”表示,时间复杂度T(n)=O(f(n))。也称为渐进时间复杂度,它表示随问题规模n的增大,算法执行时间的增长,算法时间的增长率和f(n)的增长率相同。
O(1) < O(log2n) < O(n) < O(nlog2n) < O(n2) < <O(n3) < O(2n) < O(n!)
(3) 简化的算法时间复杂度分析,基本操作是最深层循环内的原操作。
(4) 时间复杂度的求和、求积定理:设T1(n)和T2(n)是程序段P1,P2的执行时间,并且T1(n)=O(f(n)),T2(n)=O(g(n)),那么先执行P1,再执行P2的总执行时间是T1(n)+T2(n)=O(MAX(f(n),g(n)))。求积定理:设T1(n)和T2(n)是程序段P1,P2的执行时间,并且T1(n)=O(f(n)),T2(n)=O(g(n)),那么先执行P1,再执行P2的总执行时间是T1(n)×T2(n)=O(f(n)×g(n))。
(5) 算法的平均时间复杂度:E(n)=ΣP(I)×T(I)。最好时间复杂度:B(n)=MIN{T(n)};最坏时间复杂度:B(n)=MAX{T(n)}。
(6) 递归算法时间复杂度分析:求解递推式。
1.3.3 算法空间性能分析
(1) 算法空间复杂度是对每一个算法在运行过程中临时占用的存储空间大小的量度。S(n)=O(g(n))。若所需时空间相对于问题规模来说是常数,则称此算法为原地工作算法或就地工作算法。
(2) 递归算法的空间复杂度分析:根据递归栈深度得到空间复杂度。
1.4 数据结构+算法=程序
1.4.1 程序和数据结构
程序就是在数据的某些特定的表示方法和结构的基础上对具体算法的具体描述。
1.4.2 算法和程序
算法是程序的“灵魂”。
1.4.3 算法和数据结构
不能离开数据结构抽象第考虑算法,也不能脱离算法去孤立地讨论数据结构。
(1) 存储结构的存储能力:往往存储能力是与所使用的空间大小成正比的。
(2) 存储结构应与所选择的算法相适应:存储结构是实现算法的基础。
1.4.4 数据结构的发展
Donald Knuth
C.A.R. Hoare
摘录于《数据结构教程》