数据结构与算法基础1
只看一套算法还是不够的, 还是得来看看严本的数据结构, 找的b站推荐的青岛大学王卓老师的课, 顺带实现下代码.
我看的书是《数据结构C语言版》、《数据结构题集》和《数据结构算法解析》。
这是昨天写的笔记, 太长了. 电子笔记还是记录最基础的吧. 第一遍的笔记就写在书上了. 争取电子版的笔记只花10分钟, 其他实现不如用来实现代码, 这点东西我手快写冒烟了
第一章 绪论
1.1 数据结构的研究内容
数值运算 -> 非数值运算
1.2 基本概念和术语
1.2.1 数据 (Data)
- 数据: 能输入计算机且能被计算机处理的各种符号的集合.
- 数值型数据
- 非数值型数据
- 数据元素: 数据的基本单元, 在计算机程序中通常作为一个整体进行考虑和处理.
简称元素, 或记录 结点 顶点. - 数据项:构成数据元素的不可分割的最小单位.
数据 > 数据元素 > 数据项
- 数据对象:是性质相同的数据元素的集合, 是数据的一个子集.
- 数据元素-组成数据的基本单位
- 与数据的关系:是集合的个体.
- 数据对象-性质相同的数据元素的集合
- 与数据的关系:集合的子集.
- 数据元素-组成数据的基本单位
1.2.2 数据结构 (Data Structure)
-
数据结构: 数据结构之间存在着某种关系, 数据元素相互之间的关系称为 结构(Structure).
相互之间存在一种或多种特定关系的数据元素集合.
数据结构是带结构的数据元素的集合.- 数据结构包括三方面内容:
- 数据元素之间的逻辑关系, 称为逻辑结构.
- 数据元素及其关系在计算机内存中的表示 (映像), 称为数据的物理结构或数据的存储结构.
- 数据的运算和实现, 即对数据元素可以施加的操作以及这些擦欧总在相应的存储结构上实现.
- 数据结构包括三方面内容:
-
数据结构的两个层次
- 逻辑结构
- 描述数据元素之间的逻辑关系.
- 与数据的存储无关, 独立于计算机.
- 是从具体问题抽象出来的数学模型.
- 物理结构 (存储结构)
- 数据元素机器关系在计算机存储器中结构.
- 是数据结构在计算机中的表示.
- 逻辑结构与存储结构的关系
- 存储结构是逻辑关系的映像与元素本身的映像.
- 逻辑结构是数据结构的抽象, 存储结构是数据结构的实现.
- 两者综合起来建立了数据元素之间的结构关系.
- 逻辑结构
-
逻辑结构的种类
- 划分一
- 线性结构: 有且仅有一个开始和一个终端结点, 并且所有结点最多只有一个直接前驱和直接后继.
一对一关系线性表 栈 队列 串
- 非线性结构:一个结点可能有多个直接前驱和直接后继.
多对多 树 图
- 划分二 四种基本逻辑结构
- 集合结构:结构中的数据元素之间除了 同属于一个集合 的关系外, 无任何其他关系.
- 线性结构:结构中的数据元素之间存在这一对一的线性关系.
- 树形结构:结构中的数据元素之间存在着一对多的层次关系.
- 图状结构(网状结构):结构中的数据元素之间存在着多对多的任意关系.
- 划分一
-
存储结构的种类
- 四种基本存储结构
- 顺序存储结构
- 用一组连续的存储单元依次存储数据元素, 数据元素之间的逻辑关系由元素的存储位置来表示.
- C语言中用数组来实现顺序存储结构.
- 链式存储结构
- 用一组任意的存储单元存储数据元素, 数据元素之间的逻辑关系用指针表示.
- C语言中用指针来实现链式存储结构. (链表)
- 索引存储结构
- 在存储结点信息的同时, 建立附加的索引表(index)
- 散列存储结构
- 根据结点的关键字直接计算出该结点的存储地址.
- 顺序存储结构
- 四种基本存储结构
1.2.3 数据类型和抽象数据类型
- 使用高级程序设计语言, 必须对程序中出现的每个变量 常量或表达式, 明确说明他们所属的数据类型
- 一些最基本数据结构可以用数据类型来实现 例如 数组 字符串
- 另一些常用的数据结构 例如栈 队列 树 图等, 则不能直接用数据类型来表示
- 高级语言中的数据类型明显地或隐含的规定了程序执行期间变量和表达的所有可能的取值范围, 以及在这些数值范围上所允许进行的操作.
- 数据类型的作用
- 约束变量或常量的取值范围
- 约束变量或常量的操作
- 数据类型(Data Type):是一组性质相同的值的集合以及定义于这个值集合上的一组操作的总称.
- 数据类型 = 值的集合 + 值集合上的一组操作
- 抽象数据类型(Abstract Data Type, ADT):指一个数学模型以及定义在数学模型上的一组操作
- 由用户定义, 从问题抽象出数据模型(逻辑结构).
- 包括定义在数据模型上的一组抽象运算(相关操作).
- 不考虑计算机内部的具体存储结构与运算的具体实现算法
- 抽象数据类型的形式定义
- 抽象数据类型可用(D, S, P) 三元组 进行表示
Data 数据对象, S 是 D 上的关系集, P 是对 D 的基本操作集
ADT 抽象数据类型名 {
数据对象:<数据对象的定义>
数据关系:<数据关系的定义>
基本操作:<基本操作的定义>
} ADT 抽象数据类型名
基本操作定义格式:
基本操作名(参数表)
初始条件<初始条件描述>
操作结果<操作结果描述>
- 基本操作定义格式:
- 参数表:赋值参数 只为操作提供输入值
- 引用参数 以 & 打头, 除了可以提供输入值以外, 还将返回操作结果
- 初始条件:描述操作执行之前数据结构和参数应满足的条件, 若不满足, 则操作失败, 并返回相应出错信息. 初始条件为空, 则省略.
- 操作结果:操作正常完成后, 数据结构的变化状况和应返回的结果
- 参数表:赋值参数 只为操作提供输入值
1.3 抽象数据类型的表示与实现
- 抽象数据类型如何实现
- 抽象数据类型可以通过固有的数据类型来表示和实现
- 利用处理器中已存在的数据类型来说明新的结构, 用已经实现的操作来组合新的操作
- 抽象数据类型可以通过固有的数据类型来表示和实现
1.4 算法和算法分析
- 算法的定义
- 对特定问题求解方法和步骤的一种描述, 是指令的有限序列. 其中每个指令表示一个或多个操作.
- 算法的描述
- 自然语言: 中文, 英语
- 流程图: 传统流程图, NS流程图
- 伪代码: 类语言(类C)
- 程序代码
- 算法与程序
- 算法是解决问题的一种方法或一个过程, 考虑如何将输入转换成输出, 一个问题可以有多种算法.
- 程序是用某种程序设计语言对算法的具体实现.
程序 = 数据结构 + 算法
数据结构通过算法实现操作
算法根据数据结构设计程序 - 算法特性: 一个算法必须具备以下五个重要特性
- 有穷性: 一个算法必须总是在执行有穷步之后结束, 且每一步都在有穷时间内完成.
- 确定性: 算法中的每一条指令必须有确切的含义, 没有二义性, 在任何条件下, 只有唯一的一条执行路径, 即对于相同的输入只能得到相同的输出.
- 可行性: 算法是可执行的, 算法描述的操作可以通过已经实现的基本操作执行有限次来实现
- 输入: 一个算法有零个或多个输入
- 输出: 一个算法有一个或多个输出
- 算法设计的要求
- 正确性
- 可读性
- 健壮性
- 高效性
算法效率
- 时间效率: 算法所消耗的时间
- 空间效率: 算法执行过程中所耗费的存储空间
时间效率和空间效率有时候是矛盾的
-
算法时间效率的度量
- 算法时间效率可以用依据该算法编制的程序在计算机上执行所消耗的时间来度量
- 事后统计: 实机测试
- 事前分析: 大致估算
- 算法时间效率可以用依据该算法编制的程序在计算机上执行所消耗的时间来度量
-
事前分析法:
- 一个算法在计算机上运行所耗费的时间大致等于计算机执行一种简单操作所需的时间与算法中进行简单操作次数乘积.
算法运行时间 = 一个简单操作所需的时间 × 简单操作次数
- 也即算法中每条语句的执行时间之和
算法运行时间 = ∑每条语句的执行次数(语句频度) × 该语句执行一次所需的时间
算法运行时间 = ∑每条语句频度 × 该语句执行一次所需的时间(每条语句的执行一次所需时间, 一般是随机器而异的. 取决于机器的指令性能 速度以及编译的代码质量. 是由机器本身软硬件环境决定的, 与算法无关)
假设执行每条语句所需的时间均为单位时间. 此时对运算的运行时间的讨论就可转化为讨论该算法中所有语句的执行次数, 即频度之和. -
算法时间复杂度的渐进表示法
- 类似极限的"抓大放小"
- 大O表示法
-
时间复杂度定义
- 算法中基本语句重复执行的次数是问题规模n的某个函数 f(n), 算法的时间量度记作: T(n) = O(f(n))
表示随着 n 的增大, 算法执行的时间的增长率和 f(n) 的增长率相同, 称渐进时间复杂度
算法中重复执行次数和算法的执行时间成正比的语句
对算法运行时间的贡献最大
执行次数最多排序: n 为 记录数
矩阵: n 为矩阵的阶数
多项式: n 为 多项式的项数
集合: n 为 元素个数
树: n 为 树的结点个数
图: n 为 图的顶点数或边数 -
分析算法时间复杂度的基本方法
- 找出语句频度最大的语句作为基本语句
- 计算基本语句的频度得到问题规模n的某个函数f(n)
- 取数量级符号"O"表示.
-
算法时间复杂度不同
- 算法中基本操作重复执行的次数随着问题的输入数据集的不同而不同
-
算法时间复杂度
- 最坏时间复杂度: 最坏情况下, 算法的时间复杂度
- 平均时间复杂度: 所有可能的输入实例在等概率出现的情况下, 算法的期望运行时间
- 最好时间复杂度: 在最好情况下, 算法的时间复杂度.
-
一般总是考虑在最坏情况下的时间复杂度, 以保证算法的运行时间不会更长
-
计算时间复杂度
- 加法: Tn = T1 + T2 = O(MAX(T1, T2))
- 乘法: Tn = T1 × T2 = O(T1 × T2)
-
算法时间效率比较
- n 取值很大时, 指数时间算法和多项式时间算法在所需时间上非常悬殊
- 常数>对数>线性>线性对数>平方>立方>...>K次方>指数
-
渐进空间复杂度: 算法所需存储空间的度量
- S(n) = O(f(n))
-
算法要占据的空间
- 输入输出, 指令, 常数, 变量等
- 算法要使用的辅助空间
// 算法1
for (i-0; i<n; i++)
{
// f(t) = O(1)
// t为原地工作
t = a[i];
a[i] = a[n-i-1];
a[n-i-1] = t;
}
// 算法2
// b[i] 的交换经过了for
// S(n) = O(n)
for(i=0; i<n; i++)
{
b[i] = a[n-i-1];
}
for(i=0;i<n;i++)
{
a[i] = b[i];
}
- 设计好算法的过程
- 抽象数据类型 = 数据的逻辑结构 + 抽象运算(运算的功能描述)