数据结构(第一章)(绪论)
1.1基本概念和术语
-
数据(Data)
是能输入计算机且能被计算机处理的各种符号的集合
信息的载体,是对客观事物符号化的表示
能够被计算机识别、存储和加工
数值型的数据:整数、实数等
非数值型的数据:文字、图形、图像、声音等 -
数据元素(Data Element)
是组成数据的基本单位,在计算机程序中通常作为一个整体进行考虑和处理。
也简称元素,或称为记录、结点或顶点。
一个数据元素可由若干个数据项组成(DataItem) -
数据项(Data Item)
构成数据元素的不可分割的最小单位
数据>数据元素>数据项 -
数据对象(Data Object)
是性质相同的数据元素的集合,是数据的一个子集。
数据结构(Data Structure)
- 数据元素不是孤立存在的,它们之间存在着某种关系,数据元素相互之间的关系称为结构
- 是指相互之间存在一种或多种特定关系的数据元素集合
- 或者说,数据结构是带结构的数据元素的集合
- 数据元素之间的逻辑关系,也称为逻辑结构。
- 数据元素及其关系在计算机内存中的表示(又称为映像),称为数据的物理结构或者数据的存储结构
- 数据的运算和实现,即对数据元素可以施加的操作以及这些操作在相应的存储结构上的实现。
数据结构的两个层次
逻辑结构:
- 描述数据元素之间的逻辑关系
- 与数据的存储无关,独立于计算机
- 是从具体问题抽象出来的数学模型
物理结构(存储结构)
- 数据元素及其关系在计算机存储器中的结构(存储结构)
- 是数据结构在计算机中的表示
逻辑与存储结构的关系
- 存储结构是逻辑关系的映像与元素本身的映像。
- 逻辑结构是数据结构的抽象,存储结构是数据结构的实现
- 两者综合建立数据元素之间的结构关系。
逻辑结构的种类
划分方法一:
- 线性结构:
有且仅有一个开始和一个终端结点,并且所有结点都最多只有一个直接前驱和一个直接后继。
例如:线性表、栈、队列、串
一对一的关系 - 非线性结构(一对多、多对多)
一个结点可能有多个直接前驱和直接后继
例如:树、 图
划分方式二————四类基本逻辑结构
-
集合:结构中的数据元素之间除了同属于一个集合关系外,无任何其它关系。
-
线性:结构中的数据元素之间存在一对一的线性结构
-
树:结构中的数据元素之间存在一对多的层次关系
-
图或网状结构:结构中的数据元素之间存在多对多的任意关系
四种存储结构:
- 顺序存储结构
用一组连续的存储单元依次存储数据元素,数据元素之间的逻辑关系由存储位置来表示。
c语言中用数组来实现顺序存储结构 - 链式存储结构
用一组任意的存储单元存储数据元素,数据元素之间的逻辑关系用指针来表示。
C语言中用指针来实现链式存储结构。 - 索引存储结构
(1) 在存储结点信息的同时,还建立附加的索引表(INDEX)
(2)索引表中的每一项称为一个索引项
(3)索引的一般形式是(关键字,地址)
(4)关键字是能唯一标识一个结点的那些数据项
(5)若每一个结点的索引表中都有一个索引项,则该索引表称为稠密索引(Dense Index)。若一组结点在索引表中只对应一个索引项,则该索引表称之为稀疏索引 (Sqarse Index) - 散列存储结构
1.2抽象数据类型的表示与实现
- 在使用高级程序设计语言编写程序时,必须对程序中出现的每一个变量、或表达式,明确说明它们所属的数据类型
- 例如C语言中:
1.提供 int 、char 、 float 、double等基本数据类型
2.数组、结构、共用体、枚举等构造数据类型。
3.还有指针、空类型
4.用户也可用typedef自己定义数据类型
5.一些最基本数据结构可以用数据类型来实现,如数组、字符串等;
6.而另外一些常用的数据结构,如栈、队列、树、图等,不能直接用数据类型来表示。
7.高级语言中的数据类型明显地或隐含地规定了在程序执行期间变量和表达的所有可能的取值范围,以及在这些数值范围上所允许进行操作
抽象数据类型(Abstract Data Type ,ADT)
1.是指一个数学模型以及定义在此数学模型上得一组操作。
2.由用户定义,从问题抽象出**数据模型**(逻辑结构)
3.还包括定义在数据模型上的一组**抽象运算**(相关操作)
4.不考虑计算机内的具体存储结构与运算的具体实现算法。
抽象数据类型可用(D,S,P)三元组表示。
其中 D:数据对象;
S :是D上的关系集;
P:对D的基本操作集。
ADT 抽象数据类型名{
数据对象:<数据对象的定义>
数据关系:<数据关系的定义>
基本操作:<基本操作的定义>
}ADT 抽象数据类型名
- 数据对象、数据关系的定义用伪代码描述
- 基本操作的定义格式为:
基本操作名:(参数表)
初始条件:(初始化条件描述)
操作结果:(操作结果描述)
基本操作定义格式说明:
参数表:赋值参数只为操作提供输入值。
引用参数以&打头,除可提供输入值外,还将返回操作结果。
初始条件:描述操作执行之前数据结构和参数应满足的条件,若不满足,则操作失败,并返回相应出错信息。若初始化条件为空,则省略之。
操作结果:说明操作正常完成以后,数据结构的变化情况和应返回的结果
数据类型的作用:约束变量或常量的取值范围,约束变量或常量的操作
数据类型 = 值得集合 + 值集合上得一组操作
抽象数据类型的表示与实现
一个问题抽象为一个抽象数据类型后,仅是形式上的抽象定义,还没有达到问题解决的目的,要实现这个目标,就要把抽象的变成具体的,变为一个能用的具体的数据类型
数据类型(Data Type)
定义:数据类型是一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称
1.3算法和算法分析
算法的定义
- 对特定问题求解方法和步骤的一种描述,它是指令的有限序列其中每个指令表示一个或多个操作
算法就是解决问题的方法和步骤
算法与程序
- 算法是解决问题的一种方法或一个过程,考虑如何将输入转换成输出,一个问题可以有多种算法。
- 程序是用某种程序设计语言对算法的具体实现。
程序=数据结构+算法 - 数据结构通过算法实现操作
- 算法根据数据结构设计程序
算法和算法分析
算法特性:一个算法必须具备以下五个重要特性
- 有穷性: 一个算法必须总是在执行有穷步之后结束,且每一步都在有穷时间内完成。
- 确定性: 算法中的每一条指令必须有确切的含义,没有二义性,在任何条件下,只有唯一的一条执行路径,即对于相同的输入只能得到相同的输出。
- 可行性: 算法是可执行的,算法描述的操作可以通过已经实现的基本操作执行有限次来实现。
- 输入:一个算法有零个或多个输入。
- 输出:一个算法有一个或多个输出。
算法设计的要求
- 正确性(Correctness)
- 可读性(Readability)
- 健壮性(Robustness)
- 高效性(Efficiency)
算法的效率
- 一个好的算法首先要具备正确性,然后是健壮性,可读性,在几个方面都满足的情况下,主要考虑算法的效率,通过算法的效率高低来判断不同算法的优劣程度。
1.时间效率:指的是算法所消耗的相对时间。
- 空间效率:指的是算法执行过程中所小号的存储空间
3.时间效率和空间效率有时候是矛盾的.
算法时间效率的度量
- 算法时间效率可以用依据该算法编制的程序在计算机上执行所消耗的时间来度量
- 两种度量方法
1.事后统计
将算法实现,测算其时间和空间开销。
缺点:编写程序实现算法将花费较多的时间和精力;所获得实验结果依赖于计算机的软硬件等环境因素,掩盖算法本身的优势。
2.事前分析
对算法所消耗资源的一种估算方法。 - 一个算法的运行时间是指一个算法在计算机上运行所耗费的时间大致可以等于计算机执行一种简单的操作(如赋值、比较、移动等)所需要的时间与算法中进行的简单操作次数乘积
算法运行时间=一个简单操作所需要的时间x简单操作次数
也即算法中每条语句的执行时间之和
算法运行时间=Σ每条语句的执行次数(语句的频度)x该语句执行一次所需要的时间
每条语句执行一次所需要的时间,一般是随机器而异的。
取决于机器的指令性能、速度以及编译的代码质量。
是由机器本身软硬件环境决定的它与算法无关。
所以,我们假设执行每条语句所需要的时间为**单位时间**。此时对算法的运行时间的讨论就可转化为讨论该算法中所有语句的执行次数,即频度之和了。
算法时间复杂度的渐进表示法
- 为了便于比较不同算法的时间效率,我们仅比较它们的数量级
例如: 两个不同的算法,时间消耗分别是:
T(N) = 10n的平方 与 T(N)= 5n的三次方 - 若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为:不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n))为算法的渐进时间复杂度(O是数量级的符号),简称为时间复杂度
算法时间复杂度定义
算法中**基本语句重复执行的次数**是问题规模n的某个函数f(n),算法的时间量度记作:T(n) = O(f(n)) 它表示随着n的增大,算法执行的时间的增长率和f(n)的增长率相同,称为**渐进时间复杂度 **
- 算法中重复执行次数和算法的执行时间成正比的语句
- 对算法运行时间的贡献最大
- 执行次数最多
n越大算法的执行时间越长 - 排序:n为记录数
- 矩阵:n为矩阵的阶数
- 多项式:n为多项式的项数
- 集合:n为元素个数
- 树:n为树的结点个数
- 图:n为图的顶点或边数
分析算法时间复杂度的基本方法
- 找出语句频度最大的那条语句作为基本语句
- 计算基本语句的频度得到问题规模n的某个函数f(n)
- 取其数量级用符号"O"表示
x = 0; y = 0;
for(int k = 0;k<n; k++)//循环体是n+1次
x++; //语句执行次数为n次
for(int i = 0 ;i < n; i++)//循环体是n+1次
for(int j =0; j < n; j++)//执行次数n*(n+1)
y++; //n*n
时间复杂度是由嵌套最深层语句的频度决定的
算法时间复杂度
- 最坏时间复杂度:指在最坏情况下,算法的时间复杂度.
- 平均时间复杂度:指在所有可能输入实例在等概率出现的情况下,算法的期望运行时间。
- 最好时间复杂度:指在最好的情况下,算法的时间复杂度。
- 一般总是考虑在最坏情况下的时间复杂度,以保证算法的运行时间不会比它更长
算法时间复杂度
- 对于复杂的算法,可以将它分成几个容易估算的部分,然后利用大O加法法则和乘法法则,计算算法的时间复杂度:
1)加法规则
T(n) = T1(n)+T2(n)=O(f(n))+O(g(n))=O(max(f(n),g(n)))
2)乘法规则
T(n) = T1(n)T2(n)=O(f(n)) O(g(n)) = O(f(n)*g(n))
算法时间效率的比较
- 当n取得很大时,指数时间算法和多项式时间算法在所需时间上非常悬殊
| f(n) | f(nlogn) | f(nn) | f(nn*n) | f(2的n次幂) | f(n!) |
| ---- | -------- | ------ | -------- | -------- | -------- |
| 1 | 0 | 1 | 1 | 2 | 1 |
| 2 | 2 | 4 | 8 | 4 | 2 |
| 4 | 8 | 16 | 64 | 16 | 24 |
| 8 | 24 | 64 | 512 | 256 | 40320 |
| 16 | 64 | 256 | 4096 | 65536 | 2.09E+13 |
| 32 | 160 | 1024 | 32768 | 4.30E+09 | 2.63E+35 |
指数函数>K次方阶>立方阶>平方阶>幂函数>对数函数>常函数
渐进空间复杂度
- 空间复杂度:算法所需存储空间得度量
记作:S(n)=O(f(n))
其中n为问题得规模(或大小) - 算法要占据的空间
算法本身要占据的空间,输入/输出,指令,常数,变量等。
算法要使用的辅助空间