整体知识框架
1.1 基本概念和术语
1.1.1 数据、 数据元素、 数据项和数据对象
数据 (Data) 是客观事物的符号表示,是所有能输入到计算机中并被计算机程序处理的符号 的总称
。如数学计算中用到的整数和实数,文本编辑中用到的字符串,多媒体程序处理的图形、 图像、声音及动画等通过特殊编码定义后的数据。
数据元素(Data Element)是数据的基本单位,在计算机中通常作为一个整体进行考虑和处理。 在有些情况下,数据元素也称为元素、记录等。
数据元素用于完整地描述一个对象,如图中的一名学生记录,树中棋盘的一个格局(状态),以及图中的一个顶点等。
数据项 (Data Item) 是组成数据元素的、有独立含义的、不可分割的最小单位。例如,学生 基本信息表中的学号、姓名、性别等都是数据项。
数据对象 (Data Object) 是性质相同的数据元素的集合,是数据的一个子集。
数据元素与数据对象的区别:
1.1.2 数据结构
数据结构 (Data Structure) 是相互之间存在一种或多种特定关系的数据元素的集合。换句话 说,数据结构是带 “结构” 的数据元素
的集合, “结构” 就是指数据元素之间存在的关系
。
数据结构包括逻辑结构和存储结构两个层次。
1、数据元素及其关系在计算机内存中的表示(又称为映像),称为数据的物理结构或存储结构
2、数据元素之间的逻辑关系,称为逻辑结构
逻辑结构和存储结构之间的关系是:逻辑结构定义了数据之间的逻辑关系,而存储结构则实现了这种逻辑关系在内存中的存储方式。
逻辑结构的种类
划分方法一:
划分方式二:
(1) 集合结构
数据元素之间除了 “属于同一集合” 的关系外,别无其他关系。例如,确定一名学生是否为 班级成员, 只需将班级看做一个集合结构。
(2) 线性结构
数据元素之间存在一对一的关系。例如,将学生信息数据按照其入学报到的时间先后顺序进 行排列,将组成一个线性结构。
(3) 树结构
数据元素之间存在一对多的关系。例如,在班级的管理体系中,班长管理多个组长,每位组 长管理多名组员,从而构成树形结构。
(4) 图结构或网状结构
数据元素之间存在多对多的关系。例如,多位同学之间的朋友关系, 任何两位同学都可以是 朋友,从而构成图状结构或网状结构。
存储结构的种类
(1)顺序存储结构
用一组连续的存储单元
依次存储数据元素,数据元素之间的逻辑关系由元素的存储位置来表示. 比如:数组
(2)链接存储结构
用一组任意的存储单元存储数据元素,数据元素之间的逻辑关系用指针
来表示, 每一个元素不仅存储它本身的数据,还要存储下一个元素的地址, 例如:链表
(3)索引存储结构
在存储节点信息的同时,还建立附加的索引表。索引表中的每一项称为一个索引项,一般形式为:(关键字,地址)
(4)散列存储
根据节点的关键字直接计算出该节点的地址
1.1.3 数据类型和抽象数据类型
**数据类型 (Data Type) **
在使用高级程序设计语言编写程序时,必须对程序中出现的每个变量常量或表达式,明确说明它们所属的数据类型
例如: Java语言中的 int、long、short等八种基本数据类型
而另一些常用的数据结构,如栈、队列、树、图
等,不能直接用数据类型来表示。
类型明显或隐含地规定了数 据的取值范围、存储方式以及允许进行的运算,数据类型是一个值的集合和定义在这个值集上的 一组操作的总称.
例如: int类型代表整数,其范围 -2,147,483,648到2,147,483,647
抽象数据类型(Abstract Data Type, ADT)
抽象数据类型 (Abstract Data Type, ADT) 一般指由用户定义的、表示应用问题的数学模型,以及定义在这个模型上的一组操作的总称,具体包括三部分:数据对象
、数据对象上关系的集合
以及对数据对象的基本操作的集合
。
ADT抽象数据类型名(
数据对象:(数据对象的定义〉
数据关系:(数据关系的定义〉
基本操作:(基本操作的定义〉
}ADT抽象数据类型名
其中,数据对象和数据关系的定义采用数学符号和自然语言描述,基本操作的定义格式为:
基本操作名(参数表)
初始条件:(初始条件描述〉
操作结果:(操作结果描述〉
基本操作有两种参数: '赋值参数只为操作提供输入值;引用参数 以 “&” ·打头,除可提供输 入值外,还将返回操作结果。
“初始条件” 描述了操作执行之前数据结构和参数应满足的条件,若 初始条件 为空,则省略。
“操作结果” 说明了操作正常完成之后,数据结构的变化状况和应返回的结果。
1.2 抽象数据类型的表示与实现
使用 Java 实现抽象数据类型 “复数” 的实现:
public class ComplexNumber {
private double real; // 实部
private double imaginary; // 虚部
// 构造函数
public ComplexNumber(double real, double imaginary) {
this.real = real;
this.imaginary = imaginary;
}
// 获取实部
public double getReal() {
return real;
}
// 获取虚部
public double getImaginary() {
return imaginary;
}
// 加法
public ComplexNumber add(ComplexNumber other) {
double newReal = this.real + other.real;
double newImaginary = this.imaginary + other.imaginary;
return new ComplexNumber(newReal, newImaginary);
}
// 减法
public ComplexNumber subtract(ComplexNumber other) {
double newReal = this.real - other.real;
double newImaginary = this.imaginary - other.imaginary;
return new ComplexNumber(newReal, newImaginary);
}
// 乘法
public ComplexNumber multiply(ComplexNumber other) {
double newReal = this.real * other.real - this.imaginary * other.imaginary;
double newImaginary = this.real * other.imaginary + this.imaginary * other.real;
return new ComplexNumber(newReal, newImaginary);
}
// 转换为字符串形式
@Override
public String toString() {
if (imaginary >= 0) {
return real + " + " + imaginary + "i";
} else {
// 数学函数,取绝对值
return real + " - " + Math.abs(imaginary) + "i";
}
}
}
1.3 算法与算法分析(1)
算法的定义
算法 (Algorithm) 是为了解决某类问题而规定的一个有限长的操作序列。
算法的描述
- 自然语言:英语、中文
- 流程图:传统流程图、NS流程图
- 伪代码:类语言:类C语言
- 程序代码:C、Java
算法与程序
- 算法是解决问题的一种方法或一个过程,考虑如何
将输入转换成输出
一个问题可以有多种算法 - 程序是用某种程序设计语言对算法的具体实现。
算法的特性
(1)有穷性。一个算法必须总是在执行有穷步后结束,且每一步都必须在有穷时间内完成。【比如:不能陷入死循环
】
(2) 确定性。对于每种情况下所应执行的操作,在算法中都有确切的规定,不会产生二义性, 使算法的执行者或阅读者都能明确其含义及如何执行。【比如对于同一个输入而出现不同的结果,这就是不确定性
】
(3) 可行性。算法中的所有操作都可以通过已经实现的基本操作运算执行有限次来实现。
(4) 输入。一个算法有零个或多个输入
。当用函数描述算法时,输入往往是通过形参表示的, 在它们被调用时,从主调函数获得输入值。
(5) 输出。一个算法有一个或多个输出
,它们是算法进行信息加工后得到的结果,无输出的 算法没有任何意义。当用函数描述算法时,输出多用返回值或引用类型的形参表示。
算法设计的要求
- 正确性
- 可读性
- 健壮性
- 高效性
1.4 算法与算法分析(2)
通常来说一个问题,往往有好几种算法可以实现,我们如何区分算法的好坏、优劣。
那么好的算法首先应该具备正确性,然后是健壮性、可读性。在几个方面都满足的情况下,主要考虑算法的效率, 通过算法效率的高度评判不同算法的优劣程度。
算法效率通常考虑以下俩个方面:
- 时间效率:指的是算法所耗费的时间
- 空间效率:指的是算法执行过程中所耗费的存储空间
这俩者之前往往是矛盾的,鱼和熊掌不可兼得~
算法时间效率的度量
算法时间效率可以用依据该算法编制的程序在计算机上执行所消耗的时间来度量。
俩种度量方法:
- 事后统计:将算法实现,实际测算其时间和空间的开销
-
事前分析:对算法的一种估算方法(一般采用此方法)
- 算法运行时间 = 一个简单操作所需的时间*简单操作次数
等价于
每条语句执行一次所需的时间,一般是随机器而异的。取决于机器的指令性能、速度以及编译的代码质量。是由机器本身软硬件环境决定的它与算法无关。
所以,我们可假设执行每条语句所需的时间均为单位时间。此时对算法的运行时间的讨论就可转化为讨论该算法中所有语句的执行次数,即频度之和了。
例如:俩个 n*n 矩阵相乘的算法可描述为:
我们把算法所消耗的时间定义为 该算法中每条语句的频度之和,则上述算法的时间消耗 Tn为:
以上这种方式进行统计太麻烦,为了方便比较不同算法的时间效率,仅仅比较他们之间的数量级。
若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数
,则称f(n)是T(n)的同数量级函数。记作**T(n)=O(f(n))**称O(f(n))为算法的渐进时间复杂度
(O是数量级的符号),简称时间复杂度
对于上面矩阵问题的,消耗的时间为:
n -> ∞ ∞ ∞ 时,T (n)/n3 = 2,这表示n充分大时,T(n)与n3是同阶或同数量级,引入大“O”记号,则T(n)可记作:
因此,在我们求时间复杂度的时候,只需要找到算法中基本语句重复执行的次数。
什么是基本语句:
- 算法中重复执行次数和算法的执行时间成正比的语句
- 对算法运行时间的贡献最大
- 执行次数最多
基本语句的重复次数(时间复杂度)是问题规模n的某个函数f(n),算法的时间量度即为: T(n) = O(f(n))
- n越大算法的执行时间越长
- 排序: n为记录数
- 矩阵:n为短阵的阶数
- 多项式: n为多项式的项数
- 集合:n为元素个数
- 树: n为树的结点个数
- 图: n为图的顶点数或边数
1.5 算法与算法分析(3)
分析算法事件复杂度的基本方法:
忽略是所有低次幂项
和最高次幂系数
,体现出增长率的含义。
步骤:
-
找出
语句频度最大
的那条语句作为基本语句(执行次数最多的语句) -
计算基本语句的频度得到
问题规模 n
的某个函数fn -
取其数量级用符号“O”表示
举例:
x = 0: V =0
for ( int k = 0; k < n; k ++)
X ++·
for ( int i = 0;i < n;i++ )
for ( int j = 0;j < n;j++ )
y + +
找出语句频度最大的: 第一个for循环频度为:n+1,第二个for循环为 n+1,第三层循环为 n * (n+1) 【条件判断也看做是一次执行次数】
T n = O ( n ∗ ( n + 1 ) ) Tn = O( n*(n+1)) Tn=O(n∗(n+1))
忽略最高次幂项系数、低次幂项,最终:Tn = O( n2)
举例:
分析以下时间复杂度
i = 1; (1)
while(i<=n)
i=i*2; (2)
若循环执行1次: i=1*2=2
若循环执行2次: i=2*2=22
若循环执行3次: i=2*2=23
若循环执行x次: i =2x
设语句(2)执行次数为x次,由循环条件 i<= n, 推出 2x< =n x<=log2n
即 f(n) <=log2n , 取最大值 f(n) = log2n
因此该程序段的时间复杂度 Tn = O( log2n) = O( lgn)
1.6 算法与算法分析(4)
前面介绍了如何计算时间复杂度,但是在有的情况下,算法中基本操作重复执行的次数还随问题的输入数据集不同而不同
。
最好情况:1次
最坏情况: n
平均时间复杂度为/O(n)
最坏时间复杂度: 指在最坏情况下,算法的时间复杂度
平均时间复杂度: 指在所有可能输入实例在等概率出现的情况下,算法的期望运行时间。
最好时间复杂度: 指在最好情况下,算法的时间复杂度
- 一般情况下是考虑最坏时间复杂度,以保证算法的运行时间最坏不会比它更长
对于复杂的算法,可以将它分成几个容易估算的部分,然后利用大O加法法则和乘法法则,计算算法的时间复杂度。
算法时间效率的比较
当n取得很大时,指数时间算法和多项式时间算法在所需时间上非常悬殊
尽量设计复杂度低的算法:
渐进空间复杂度
空间复杂度:算法所需存储空间的度量,记作:S(n) = O(f(n))
,其中 n 为问题的规模
算法要占用的空间包括:
- 算法本身占据的空间、输入、输出、指令、变量、常数等
- 算法使用的辅助空间
例子: 将一维数组a中的n个数逆序存放到原数组中。文章来源:https://www.toymoban.com/news/detail-618270.html
文章来源地址https://www.toymoban.com/news/detail-618270.html
到了这里,关于数据结构基础知识、名词概述的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!