一、数据结构研究内容
总结:
问题的共性都无法用数学公式或方程来描述,是一些“非数值计算”的程序设计问题
描述非数值计算问题的数学模型不是数学方程,而是表、树、图之类的具有逻辑关系的数据
数据结构是一门研究非数值计算的程序设计中计算机的操作对象以及它们之间的关系和操作的学科
二、基本概念和术语
数据
数据(Data):是能输入计算机并且能被计算机处理的**各种符号的集合**
是信息的载体
是对客观事物符号化的表示
是能够被计算机识别、存储和加工
分类:
数值型数据(可以进行加减乘除取余等操作):整数、实数
非数值型:文字、图像、图形、声音等
数据元素
数据元素(Data elment):是**数据的基本单位**,在程序中通常作为一个整体进行考虑和处理。
一个数据元素可由若干个数据项组成
别名:元素、记录、结点、顶点
数据项
数据项(Data Item):是构成数据元素的不可分割的最小单位
数据、数据元素、数据项三者之间的关系:
数据>数据元素>数据项
例:
学生表>个人记录>学号、姓名…
数据对象
数据对象(Data Object):是性质相同的数据元素的集合,是数据的一个子集
例如:
整数数据对象 N={0,-1,1,2,3,4…}
字母字符数据对象集合:{A,B,C… }
数据元素与数据对象
数据元素:是组成数据的基本单位
- 与数据的关系:是集合的个体
数据对象:是性质相同的数据元素的集合
- 与数据的关系是:集合的子集
数据结构
数据结构(Data Structure):
- 数据元素不是孤立存在的,它们之间存在着某种关系,数据元素相互之间的关系称为结构(Structure)
- 是指相互之间存在一种或者多种特定关系的数据元素集合
- 是带结构的数据元素的集合
数据结构包括三个方面的内容:
- 数据元素之间的逻辑关系,也称为逻辑结构
- 逻辑结构:
- 与数据的存储无关,独立于计算机
- 是从具体问题抽象出来的数学模型
- 数据元素及其关系在计算机内存中的表示(又称为映像),称为数据的物理结构或数据的存储结构
- 物理结构(存储结构):
- 数据元素以及关系在计算机存储器中的结构(存储方式)
- 是数据结构在计算机中的表示
- 逻辑结构和存储结构的关系:
- 存储结构是逻辑关系的映像与元素本身的映像
- 逻辑结构是数据结构的抽象,存储结构是数据结构的实现
- 两者综合起来建立了数据元素之间的结构关系
- 数据的运算和实现,即对数据元素可以施加的操作以及这些操作在相应的存储结构上的实现。
逻辑结构的种类
划分方式一:
线性结构:有且仅有一个开始和一个终端节点,并且中间节点之间存储位置是连续的。
例如(一对一);线性表、栈、队列、串
非线性结构:一个结点可能有多个直接前趋和直接后继
例如(一对多、多对多):树、图
划分方式二(四个基本逻辑结构):
- 集合结构:
- 结构中的数据元素之间除**同属于一个集合**的关系外,无无任何其他关系
- 线性结构:
- 结构中的元素之间存在**一对一**的线性关系
- 树形结构:
- 结构中的数据元素之间存在**一对多**的层次关系
- 图状结构或网状结构:
- 结构中的数据元素之间存在着**多对多**的任意顸
存储结构的种类
四种基本的存储结构:
- 顺序存储结构
- 用**连续的存储单元依次存储数据元素,数据元素之间的逻辑关系有元素的存储位置**表示
- 链式存储结构
- 用一组任意的存储单元存储数据元素,数据之间的逻辑关系用**指针**来表示。
- 索引存储结构
- 在存储结点信息的同时,还建立附加的**索引表**
- 例如:字典
- 散列存储结构
- 根据节点的关键字直接计算出该结点的存储地址。
数据类型和抽象数据类型
- 数据类型
数据类型的定义:
是一组性质相同的**值或集合以及定义与这个值集合上的一组操作**的总称。
通解:数据类型=值的集合+值集合上的一组操作
在使用高级程序设计语言编写程序时,必须对程序中出现的每个变量,常量或表达式,明确说它们所属的数据类型。
举例C语言:
- 基本数据类型:int char float double
- 构造数据类型:数组、结构、共用体、枚举
- 指针、空(void)类型
- 用户也可用typedef自己定义数据类型
数据类型的作用:
- 约束变量或常量的**取值范围**
- 约束变量或常量的**操作**
- 抽象数据类型
抽象数据类型(Abstract Data Type ADT):
定义:是指一个数学模型以及定义在此数学模型上的一组操作
抽象数据类型的形式定义:
可用(D、S、P)三元组表示:
- D是数据独享 - S是D上的关系集 - P是对D的基本操作集
抽象数据类型的定义格式:
- 例1:圆的定义
- 复数的定义
抽象数据类型的实现
- 复数乘除公式:
- 题目:
// test.h文件
#include <stdio.h>
struct complex{
double real;
double imag;
};
// 初始化
void init(struct complex* c1 ,double num1,double num2) ;
// 加法
void add(struct complex*c1,struct complex*c2,struct complex*c3);
// 减法
void sub(struct complex*c1,struct complex*c2,struct complex*c3) ;
// 乘法
void ride(struct complex*c1,struct complex*c2,struct complex*c3);
// 除法
void display(struct complex*c1,struct complex*c2,struct complex*c3);
// test.c文件
#include "test.h"
void init(struct complex* c1 ,double num1,double num2) {
c1->real = num1;
c1->imag = num2;
}
void add(struct complex*c1,struct complex*c2,struct complex*c3) {
c3->real = c1->real + c2->real;
c3->imag = c1->imag + c2->imag;
}
void ride(struct complex*c1,struct complex*c2,struct complex*c3) {
c3->real = (c1->real * c2->real) - (c1->imag * c2->imag);
c3->imag = c1->real * c2->imag + c2->real * c1->imag;
}
void sub(struct complex*c1,struct complex*c2,struct complex*c3) {
c3->real = c1->real - c2->real;
c3->imag = c1->imag - c2->imag;
}
void display(struct complex*c1,struct complex*c2,struct complex*c3) {
double denominator = c2->real * c2->real + c2->imag * c2->imag; // 计算分母
c3->real = (c1->real * c2->real + c1->imag * c2->imag) / denominator;
c3->imag = (c1->imag * c2->real - c1->real * c2->imag) / denominator;
}
// main.c文件
#include "test.h"
int main() {
struct complex c1,c2,c3,c4,z;
init(&c1,8.0,6.0);
init(&c2,4.0,3.0);
ride(&c1,&c2,&c3);
add(&c1,&c2,&c4);
display(&c3,&c4,&z);
printf("%.3f %.1f\n",z.real,z.imag);
return 0;
}
// 结果为:z=2.667+2.0i
概念小结
三、算法和算法分析
算法的定义
对特定问题求解方法和步骤的一种描述,他是**指令的有限序列**。其中每个指令表示一个或多个操作。
概况:算法就是解**决问题的方法和步骤**
算法的描述
- 自然语言:英语、中文
- 流程图:传统流程图、NS流程图
- 伪代码:类C语言
- 程序代码:C语言程序、JAVA语言程序
算法与程序
算法:
是解决问题的一种方法或一个过程,考虑如何将输入转换成输出,一个额问题可以有多种算法。
程序:
是用某种程序设计语言对算法的具体实现。
二者之间的关系:
程序=数据结构+算法
- 数据结构通过算法实现操作
- 算法根据数据结构设计程序
算法的五个重要特性
有穷性:算法执行步骤是有范围的,且每一个都在有穷时间内完成。
确定性:算法中的每一条指令都是有确切含义的。
可行性:算法可以执行。
输入:算法有零个或多个输入。
输出:算法有一个或多个输出。
算法设计的要求
4个要求:
- 正确性:没有语法错误,程序对于精心选择的、典型的、苛刻且带有刁难性的几组数据可以得到满意结果。
- 可读性:
- 健壮性:输入非法数据时,算法可以作出反应。
- 高效性:执行时间短,存储空间少
算法效率评判
算法效率通过两个方面进行考虑:
- 时间效率:是指算法所耗费的**时间**
- 空间效率:是指算法执行过程中所耗费的**存储空间**
算法时间效率的度量
根据算法在执行过程耗费的时间来度量。
两种度量方法:
- 事后统计:
- 将算法实现,测算其时间和空间的开销
- 缺点:需要花费时间编写程序;软硬件不同,得到的结果会不相同。
- 事前分析(主要使用):
- 对算法所消耗资源进行估算
- 分析方法:
- 算法运行时间=一个简单操作的所需时间*简单操作次数
通俗解释:
*算法运行时间=每条语句的执行次数(语句频度)该语句执行一次所需的时间
注意:我们可假设执行每条语句所需时间均为**单位时间,**此时:
算法的运行时间,只需要考虑算法中所有语句的执行次数即可。
- 时间复杂度例题1:两个NxN矩阵相乘算法
for循环的次数等于 N+1次,(+1是不满足条件的最后一次)
算法时间复杂度的渐进表示法
为了便于笔记不同算法的时间效率,我们仅不叫它们的**数量级**
例如:
a=n的三次方,b=n的5次方
结果:a好,b不好
算法时间复杂度定义
算法中基本语句重复执行的次数是问题规模N的某个函数f(n),算法的时间记作:T(n)=O(f(n))
基本语句重复执行的次数解释:
- 算法中重复执行次数和算法的执行时间成正比的语句
- 对算法运行时间的贡献最大
- 执行次数最多
问题规模n解释:
- n越大算法的执行时间越长
它表示随着n的增大,算法执行的时间的增长率和f(n)的增长相同,称:渐进时间复杂度
分析算法时间复杂度的基本方法
- 定理1
- 基本方法
步骤:
1 找到语句频度最大的那条语句作为基本语句
2 计算基本语句的频度得到问题规模n的某个函数f(n)
3 取其数量级用符号O表示
- 例1
- 例2
- 例3
- 例4
- 例5
理解:$ 2^4=log_216=4
$$ 2^x=log_2N=x
$
算法时间复杂度计算
注意点:有的情况下,算法中基本操作重复执行的次数还随问题的数据解不同而不同
考虑算法时间复杂度的三个方面:
- 最坏时间复杂度:指在最坏情况下,算法的执行时间
- 平均是时间复杂度:指在所有可能输入实例在等概率的情况下,算法的期望运行时间。
- 最好时间复杂度:指最好的情况下,算法的执行时间。
对于复杂的算法,可以将它分成几个容易估算的部分,然后利用大O加法法则和乘法法则,计算算法的时间复杂度:
- 加法规则:分为T1和T2,在求出大O后,比较T1和T2的值,取较大
- 乘法规则:分为T1和T2,求出大O后,T1和T2相乘
算法时间效率的比较
当n取得很大后,指数时间算法和多项式时间算法在所需时间上非常悬殊
口令:常对幂指阶
渐进空间复杂度
- 空间复杂度:算法所需存储空间的度量
记作:$ S(n)=O(f(n)) $
注意:其中n为问题的规模
- 算法要占据的空阿金
- 算法本身要占据的空间,输入/输出、指令、常数、变量等
- 算法要使用的辅助空间
- 案例:将一维数组a中的n个数逆序存放在原数组中