数据结构的知识点总结归纳
这个是自己看着王道课程做的,考研这个科目是肯定会考的,所以记录下来,学精学细致一点。这也仅仅是第一轮建立框架的复习,到第二年暑假我会再复习一遍,会将漏掉的内容补上,因为是找来的课程,所以缺了B树、B+树和散列表。
转载请注明出处,花了近一个月的时间,请尊重私人创作。
绪论
- 数据结构的基本概念
- 基本概念和术语
- 数据:描述客观事物的属性的数,符号的集合
- 数据对象:具有相同性质的数据元素集合,数据的子集
- 数据元素:数据的基本单位
- 数据项:构成数据元素的不可分割的最小单位
- 数据类型(集合+操作)
- 原子类型
- 值得集合+操作:int char float
- 结构类型
- 结构的集合+操作:list map set
- 抽象数据类型ADT
- 数据对象+数据关系+操作:所有可以抽象出得模型
- 原子类型
- 数据结构的三要素
- 数据不是孤立的,他们存在着某种关系,这种相互关系我们叫做结构
- 数据结构是相互之间存在一种或多种特定关系的数据元素的集合
- 三要素
- 逻辑结构
- 线性结构
- 排队买票,排序……
- 非线性结构
- 集合
- 树形结构
- 图状结构
- 线性结构
- 存储结构(物理结构)
- 顺序存储
- 数组
- 链式存储
- 链表
- 索引存储
- 关键字找到地址找到对应存储数据
- 散列存储
- 哈希存储:将关键字进行函数运算得到地址
- 顺序存储
- 数据的运算
- 运算的定义针对逻辑结构
- 运算的实现针对存储结构
- 逻辑结构
- 基本概念和术语
- 算法和算法评价
- 算法的基本概念
- 对特定问题求解步骤的一种描述
- 特性
- 有穷性
- 可行性
- 确定性
- 输入
- 输出
- 算法效率的度量
- 正确性
- 可读性
- 健壮性:输入非法数据时,算法能适应的做出反应or进行处理
- 效率与存储量:效率时算法执行时间,存储量需求时值算法执行过程中所需最大存储时间
- 时间复杂度
- 语句频度
- T(n)所有语句的频度之和,其中n为问题的规模
- 时间复杂度:T(n)=O(f(n)),其中O表示T(n)与f(n)在n->正无穷时为同阶无穷大
- 加法规则:取最大
- 乘法规则:就是乘
- 最坏时间复杂度、最好时间复杂度、平均时间复杂度
- 空间复杂度
- 记S(n)=O(g(n))
- 除本身所用的指令、常数、变量、和输入数据外,还需要一些对数据进行操作的工作单元和存储为实现算法所需的一些信息的辅助空间
- 算法原地工作时所需辅助空间为常量,O(1)
- 时间复杂度
- 算法的基本概念
- 数据结构的基本概念
线性表
- 线性表的定义和基本操作
- 线性表的顺序表示
- 顺序表的定义
- 顺序表的基本操作
- 线性表的链式表示
- 单链表的定义
- 相同类型的n个元素的有限序列,n为表长,n>=0,n=0为空表
- 特点
- 个数有限
- 先后次序
- 每个元素都是数据元素
- 数据类型都相同
- 具有抽象性
- 是一种逻辑结构
- 单链表的基本操作
- 初始化表
- 销毁操作
- 按值查找(关键字值)
- 按位查找(按位置)
- 插入(默认前插)
- 删除
- 输出操作
- 判空操作
- 求表长
- 顺序表
- 定义
- 逻辑顺序和物理顺序是相同的
- 动态分配
- 静态分配
- 插入操作
- 时间复杂度
- 最好:在末尾插入 O(1)
- 平均:O(n),把每一个可能插入的位置概率乘以该插入所要进行的次数的总和得出T(n)
- 最差:O(n)
- 空间复杂度
- 时间复杂度
- 删除操作(不能像链表一样操作,需要循环向前移动)
- 时间复杂度
- 最好:同插入
- 平均:同插入
- 最差:同插入
- 空间复杂度
- 时间复杂度
- 按值查找
- 时间复杂度
- 最好:同插入
- 平均:同插入
- 最差:同插入
- 时间复杂度
- 定义
- 几种常用的链表
- 双链表
- 循环链表
- 静态链表
- 单链表的定义
栈和队列
栈
- 基本概念
- 基本操作
- 初始化空栈
- 判断是否为空
- 进栈
- 出栈
- 返回栈顶元素
- 销毁栈
- 基本操作
- 存储结构
- 顺序存储
- 共享栈:两个top
- 链式存储
- 顺序存储
- 非连续输入和输出(规定了输入序列,输出序列是满足)
- 出栈序列中 每一个元素后面所有比它小的元素 组成一个递减序列
- 会求个数,有几种那个合法序列
- 栈的应用
- 括号匹配
- 初始一个空栈,顺序读入括号。
- 若是右括号,则与栈顶元素进行匹配
- 若匹配,则弹出栈顶元素并进行下一元素
- 若不匹配,则该序列不合法
- 若是左括号,则压入栈中
- 若全部元素遍历完毕,栈中非空则序列不合法
- 表达式求值
- 前缀表达式
- +AB
- 中缀表达式
- A+B
- 人类直观常用
- 后缀表达式
- AB+
- 算法思想
- 若为(,入栈
- 若为),则依次把栈中的运算符加入后缀表达式,直到出现(并从栈中删除(
- 若为 + - * /
- 栈空,入栈
- 栈顶元素为(,入栈
- 高于栈顶元素优先级,入栈
- 否则依次弹出栈顶运算符,直到一个优先级比它低的运算符或(为止
- 遍历完成,若栈非空则依次弹出所有元素
- 前缀表达式
- 递归
- 递归的精髓在于能否将原始问题转换为属性相同但规模较小的问题
- 会产生的问题
- 在递归调用过程中,系统为每一层的返回点,局部变量,传入实参等开辟了递归工作栈来进行数据存储,递归次数过多容易造成栈溢出
- 通常情况下递归的效率并不高
- 递归算法转换为非递归算法,往往要借助栈来进行
- 括号匹配
- 基本概念
队列
- 基本概念
- 基本操作
- 初始化队列
- 判队列空
- 入队
- 出队
- 读队头元素
- 销毁队列
- 存储结构
- 顺序存储
- 需要两个int型数据做指针
- 改成循环队列去存储
- 判断队满和队空的解决办法
- 牺牲一个存储单元
- 增加一个Size变量记录存入的大小
- 增加tag标识
- 判断队满和队空的解决办法
- 链式存储
- 顺序存储
- 队列的应用
- 层次遍历
- 计算机系统
- 双端队列
- 输入受限的双端队列
- 输出受限的双端队列
数组
数组的定义
- 数组维度和维界不可变,所以数组除了初始化和销毁以外,只有存取和修改元素的操作
数组的存储结构
- 连续存放
- 按行优先存储or按列优先存储进行寻找的考察
矩阵的压缩存储
按行优先(存储顺序,当行遍历结束才会遍历列)
对称矩阵
aij=aji
会考某个数值存放在内存什么地方
三角矩阵
下三角矩阵
下三角矩阵
三对角矩阵压缩
稀疏矩阵
- 矩阵元素个数s相对于矩阵中非零元素的个数t来说非常多,即s>>t的矩阵为稀疏矩阵。
- 三元组存放
- (行标、列表、值)记住行标和列标从开始
- 即使用三元组表的顺序存储结构,存取下标为i和j的元素时,要扫描三元组表,下标不同的元素,存取时间也不同。最好情况下存取时间为O(1),最差情况下是O(n),因此也失去了随机存取功能。因为无法通过所存的标号去直接索引所需要存取的值,只能通过扫描。
树与二叉树
二叉树
概念
- 每个结点最多有两个孩子结点
性质
- 非空二叉树上的叶子结点数等于度为2的结点数加1,即n0=n2+1
- 非空二叉树上的第k层上至多有2^(k-1)个结点 (k>=1)
- 高度为h的二叉树至多有2^(h-1)个结点
- 完全二叉树的性质
- 结点i所在的层次为[log2 i]+1(取下界)
- 具有n个结点的完全二叉树高度为[log2 n]+1(取下界)或[log2(n+1)](取上界)
二叉树和度为2有序树结点区别
- 二叉树可以为空
- 二叉树的孩子结点始终有左右之分而度为2的有序树孩子节点次序是相对的
满二叉树
- 对于编号为i的结点,若存在,其双亲的编号为i/2,左孩子为2i,右孩子为2i+1(编号顺序为BFS)
完全二叉树
- 当且仅当每个结点与高度为h的满二叉树中编号1~n的结点一一对应时,称为完全二叉树(BFS的顺序一直生成)
- 有n个结点的二叉树,若i<n/2,则结点i为分支结点,否则为叶子结点
- 叶子只可能在层次最大两层上出现
- 度为1的结点若存在则只可能有一个且一定是左节点,编号也是最大的分支结点
二叉排序树
- 对于任意结点存在左子树or右子树,则其左子树上的所有结点的关键字均小于该节点,右子树上的所有结点的关键字均大于该结点
平衡二叉树
- 树上任意结点的左子树和右子树的深度之差不超过1
二叉树的顺序存储
- 用一组存储单元自上而下,自左至右。
- 完全二叉树直接存放
- 非完全二叉树,需要补空结点
- 但是如果全是右孩子则浪费很多空间
二叉树的链式存储
- 结构体:data lchild rchild
- 含有n个结点的二叉链表中,有n+1个空链域
- 2n-(n-1)
二叉树的遍历
先序遍历
- 访问根节点
- 先序遍历左子树
- 先序遍历后字数
中序遍历
中序遍历左子数
访问根节点
中序遍历右子树
中序遍历非递归算法1
中序遍历非递归算法2
后序遍历
- 后序遍历左子树
- 后续遍历右子树
- 访问根节点
先(或后)序遍历序列和中序遍历序列可以确定一颗二叉树,而后序遍历序列和先序遍历序列不可以确定一颗二叉树
线索二叉树
线索化
- 若无左子树,则将做指针指向其前驱结点
- 若无右子树,则将右指针指向后继结点
线索二叉树结点结构
- 在结点含data,lchild,rchild的前提下增加了ltag、rtag。
- 若tag为0则指示节点的孩子
- 若tag为1则知识结点的前驱or后继
中序线索二叉树
平衡而二叉树
AVL,任意结点的平衡因子的绝对值不超过1
左子树高度-右子树高度高度为h的最小平衡二叉树的结点数Nh
- Nh=N(h-1)+N(h-2)+1
平衡二叉树的判断
利用后序遍历递归判断
- 判断左子树是一棵平衡二叉树
- 判断右子树是一棵平衡二叉树判断
- 以该节点为根的二叉树为平衡二叉树
判断条件,左子树and右子树均为平衡二叉树,且左子树于右子树高度差的绝对值小于等于1,且平衡
平衡二叉树的插入
先插入再调整、每次调整最小不平衡子树
LL平衡旋转(右单旋转)
RR
LR
RL
树和森林
树的基本概念
定义及特点
树是n个节点的有限集合,n=0时,称为空树。
而任意非空树应满足:
- 有且仅有一个特定为根的结点
- 当n>1时,其余结点可分为m(m>0)个互不相交的结合,其中每一个集合本身又是一棵树,称为根的子树
特点
n个结点的树中只有n-1条边
度
- 树中一个几点的子节点的个数成为该结点的度
- 树中最大度数为树的度
- 度大于0的结点称为分支结点
- 度为0的结点称为叶子结点
高度深度
- 结点的深度是从根结点往下数
- 结点的高度是从叶子结点往上数
- 树的高度(深度)是树中结点的最大层数
路径
- 路径是从出发的结点至上而下的,是由两个结点之间所经过的结点序列构成的
- 路径长度指路径上所经历的边的个数
森林
- m棵互不相交的树的集合
树中的节点数等于所有结点的度数+1
度为m的树中第i层上至多有m^(i-1)个结点
高度为h的m叉树至多有(m^h-1)/(m-1)个结点(等比数列求和)
具有n个结点的m叉树的最小高度为(上一个的变形)
二叉树的存储结构
树的存储结构
- 双亲表示法
- 采用一组连续的存储空间来存储每个结点,同时在每个节点中增设一个伪指针,指示双亲结点在数组中的位置。根结点的下标为0,其伪指针域为-1
- 顺序存储
- 优点
- 寻找结点的双亲结点效率高
- 缺点
- 寻找结点的孩子结点效率低
- 孩子表示法
- 将每个结点的孩子结点都用单链表连接起来形成一个线性结构,n个结点有n个孩子链表
- 顺序存储,孩子用链表存储
- 优点
- 寻找结点的孩子结点效率高
- 缺点
- 寻找结点的双亲结点效率低
- 孩子兄弟表示法
- 以二叉链表作为树的存储结构,又称二叉树表示法
- 左孩子右兄弟
- 优点
- 寻找结点的孩子效率高,方便实现树转换为二叉树
- 缺点
- 寻找结点的双亲结点效率低
- 双亲表示法
树和森林的遍历
按照啊某种方式访问树的每个结点,且仅访问一次
树的遍历
- 先根遍历
- 若树非空,则先访问根节点,再从左到右的顺序遍历根结点的每颗子树
- 树的先根遍历序列与这棵树对于的二叉树的先序遍历序列相同
- 后根遍历
- 若树非空,则先从左到右的顺序遍历根结点的每颗子树,再访问根节点
- 树的后根遍历序列与这棵树对于的二叉树的中序遍历序列相同
- 层次遍历
- BFS标号一样
- 先根遍历
森林的遍历
- 先序遍历
- 一颗一颗树的访问,访树先根遍历访问
- 先序遍历与二叉树先序遍历序列相同
- 中序遍历
- 一颗一颗访问,访问的树后根遍历
- 先序遍历
树和森林及二叉树的转换
- 左孩子右兄弟
- 树的根节点为兄弟
树的应用>>>并查集
一种简单的集合表示
通常用树的双亲表示法作为并查集的存储结构
三个操作
树的应用
二叉排序树 BST 也称二叉查找树
- 若左子树非空时,则左子树上的所有结点关键子值均小于根结点的关键字
- 若右子树非空时,则右子树上的所有结点关键子值均大于于根结点的关键字
- 左、右子树本身也分别是一棵二叉排序树
- 中序遍历序列:从小到大
- 操作
- 查找
- 二叉树非空时,查找根节点,若相等则成功
- 若不等,则当小于根节点值时,查找左子树;当大于根节点的值时,查找右子树。
- 当查找到叶结点仍没有查找到相应的值,则查找失败
- 插入
- 若二叉排序树为空则直接插入结点
- 若二叉排序树非空,当值小于根节点时,插入左子树;当值大于根节点时,插入右子树;当值等于根节点时不插入
- 构造
- 读入一个元素并建立结点,若二叉树为空将其作为根节点
- 若二叉排序树非空,当值小于根节点时,,插入左子树,当值大于根节点时,插入右子树;当值等于根节点时不进行插入
- 删除
- 若被删除的结点z时叶结点,则直接删除
- 若被删除结点z时只有一棵子树,则让z的子树成为z父节点的子树,代替z结点
- 若被删除结点z时有两棵子树,则让z的中序序列直接后继代替z,并删除直接后继结点
- 查找
- 在二叉排序树中删除后再插入某结点,得到的而二叉树不一定会和原二叉树一样
- 平均查找长度(ASL)取决于树的高度
树的带权路径长度 WPL
- 树中所有叶节点的带权路径长度之和
哈夫曼树
不唯一,因为左右子树可以互换,所以每个字符对应的哈夫曼编码也不唯一,单带权路径长度相同且最优
最优二叉树,含有n个带权叶子结点带权路径长度最小的二叉树
构造算法
性质
- 每个初始节点都会成为叶节点,双支结点都为新生成的结点
- 权值越大离根结点越近,反之权值越小离根节点越远
- 哈夫曼树没有结点的度为1
- n个叶子结点的哈夫曼树的结点总数为2n-1,其中度为2的结点数为n-1
编码问题
通过哈夫曼树编码
左边的边0为右边的边为1
图
相关概念
- 图G有顶点集V和边集E组成,记为G=(V,E),图不能空,图的点集不能为空
- 无向图,(v,w)=(w,v)
- 有向图,<v,w>!=<w,v>
- 简单图,无重复的边,不存在结点到自身的边
- 多重图,存在重复边,或存在结点到自身的边
- 无向完全图,任意两个顶点都存在边
- n个顶点有n(n-1)/2边
- 有向完全图,任意两个顶点都存在方向相反的弧
- n个顶点有n(n-1)边
- 子图,点是点的子集,边是边的子集,则图是图的子图
- 当原图和子图的点集相同,则子图成为原图的生成子图
- 边集可以为空但是点集不能为空
- 无向图
- 顶点v的度为以v为端点的边的个数记为,TD(v)
- n顶点,e条边的无向图中度的总数为2e
- 连通
- 路径和边不一样
- 若顶点v到顶点w有路径存在,则称v和w是连通的
- 连通图
- 任意两个结点之间都是连通的
- n个顶点的连通图最少有n-1条边
- 连通分量
- 称为极大连通子图
- 对于G的一个连通子图G’,如果不存在G的另一个连通子图G’’,使得G’属于G’’,则称为G’为G的连通分量
- 顶点v的度为以v为端点的边的个数记为,TD(v)
- 有向图
- 出度:以v为起点的有向边的条数,记OD(v)
- 入度:以v为起点的有向边的条数,记ID(v)
- 顶点的度:TD(v)=OD(v)+ID(v)
- n顶点,e条边的有向图中出度、入读为e
- 强连通
- 路径和边不一样
- 若从顶点v到顶点w和顶点w到顶点v都有路径存在,则称为v和w是强连通
- 强连通图
- 任意两个结点之间都是强连通的
- n个顶点的强连通图最少有n条边
- 强连通分量
- 称为极大强连通子图
- 对于G的一个强连通子图G’,如果不存在G的另一个强连通子图G’’,使得G’属于G’’,则称为G’为G的强连通分量
- 生成树、生成森林
- 生成树概念
- 连通图包含全部顶点的一个极小连通子图
- n个顶点的生成树有n-1条边
- 生成森林概念
- 非连通图所有的连通分量的生成树组成生成森林
- 极小连通子图
- 连通子图且包含的边最少
- 生成树概念
- 有向树
- 一个顶点入度为0、其余顶点的入度为1的有向图
- 和树不一样的!!!
- 树的度仅仅只是孩子,而有向树的度是图中的度,入度也算
- 网
- 每个边有权值
- 稠密图&稀疏图
- 稀疏稠密的界定:|E|<|V|log|V|
- 路径
- 图中顶点v到顶点w的顶点序列,序列中顶点不重复的路径称为简单路径
- 路径长度
- 路径上的边的数目,若该路径最短则称其为距离
- 回路
- 第一个顶点和最后一个顶点相同的路径
- 除了第一个顶点和最后一个顶点重复之外,其他顶点不重复,称为简单回路
存储结构
一维数组存放结点
二维数组存放边
邻接矩阵法
- 空间复杂度O(n^2),适用于稠密图
- 无向图邻接矩阵为对称矩阵
- A^n[i][j]表示从顶点Vi到顶点Vj长度为n的路径的条数
邻接表法
有向图
无向图
适用于稀疏图
为每一个顶点建立了一个单链表存放与它相邻的边
定点表
- 采用顺序存储,为每个数组元素存放顶点的数据和边表的头指针
边表(出边表)
- 采用链式存储,单链表中存放与一个顶点相邻的所有边,一个链表结点表示一条从该顶点到链表结点顶点的边
若G为无向图,存储空间为O(|V|+2|E|)
若G为有向图,存储空间为O(|V|+|E|)
若G为无向图,则结点的度为该节点边表的长度
若G为有向图,则节点的出度为该节点边表的长度,计算入度则需要遍历整个邻接表
邻接表不唯一
邻接表法VS邻接矩阵法
- 邻接表
- 稀疏图
- 顺序存储+链式存储
- 判断该边是否存在效率低
- 找出某顶点相邻的边效率高
- 邻接矩阵
- 稠密图
- 顺序存储
- 判断该边是否存在效率高
- 找出某顶点相邻的边效率低
- 邻接表
十字链表
有向图的一种链式存储结构
因为找入边难,所以引出了十字链表
定点表
- 存放数据、出边指针、入边指针
边表
- 存放弧尾的端点,存放弧头的端点、存放弧头相同的指针,存放弧尾相同的指针、若该边有权重则记录权值
邻接多重表
无向图的一种链式存储结构
顶点表
- 数据、第一个结点的指针
边表结点
- 该边的第一个端点、与该端点相邻的下一个边的边表结点的指针、该边的第二个端点,与该端点相邻的下一个边的边表结点的指针、有权重加权值、有标记加标记
十字链表&邻接多重表
- 十字链表存放有向图,邻接多重表存放无向图
基本操作
- Adjacent(G,x,y)
- 判断图G是否存在边<x,y>or(x,y)
- 邻接矩阵vs邻接矩阵
- 邻接矩阵效率高
- Neighbors(G,x)
- 列出与结点x邻接的边
- 邻接矩阵vs邻接矩阵
- 邻接表效率高(无向图,因为有向图要遍历全部)
- 邻接矩阵效率高(有向图!!!!)
- InsertVertex(G,x)
- 插入点
- DeleteVertex(G,x)
- 删除点
- AddEdge(G,x,y)
- 若无向边or有向边不存在,则向图G中添加该边
- RemoveEdge(G,x,y)
- 若边存在则删除
- 邻接矩阵vs邻接矩阵
- 邻接矩阵效率高
- FirstNeighbor(G,x)
- 求图G中顶点x的第一个邻接点
- NextNeighbor(G,x)
- 假设图G中顶点y是顶点x的一个邻接点,返回除y之外顶点x下一个邻接点的顶点号,若y是x的最后一个邻接点,则返回-1
- 获取边权值操作and设置边权值操作
- Adjacent(G,x,y)
图的遍历
BFS
- 类似于树的层次遍历
- 队列+辅助标记数组
- 小心非连通图
- 空间复杂度
- O(|V|)
- 时间复杂度
- 邻接矩阵法
- O(|V^2|)
- 邻接表法
- O(|V|+|E|)
- 邻接矩阵法
- 无权图 单源 最短 路径问题
- BFS遍历的都是先路径最短的点,所以正好可以解决
- 广度优先生成树
- 在广度遍历过程中,我们可以得到一棵遍历树,称为广度优先生成树(生成森林)
- 邻接矩阵法的广度优先生成树唯一,邻接表法的不唯一
DFS
- 递归(栈)+辅助标记数组
- 小心无入度的结点
- 邻接矩阵法的深度优先序列唯一,邻接表法的不唯一
- 空间复杂度
- O(|V|)(工作栈)
- 时间复杂度
- 邻接矩阵法
- O(|V^2|)
- 邻接表法
- O(|V|+|E|)
- 邻接矩阵法
- 深度优先生成树
- 类同BFS概念
- 邻接矩阵法的深度优先生成树唯一,邻接表法的不唯一
遍历与连通性问题
- 在无向图当中,在任意结点出发进行一次遍历(调用一次BFSorDFS),若能访问全部结点,说明该无向图是联通的
- 在无向图当中,调用遍历函数(调用一次BFSorDFS)的次数为连通分量的个数
图的应用
最小生成树
对于带权无向连通图G=(V,E),G的所有生成树当中边的权值之和最小的生成树为G的最小生成树(MST)。
不一定唯一
一定唯一的情况
- 当每一个边的权值都不相同
- N个顶点只有N-1条边的时候
最小生成树的权值是唯一的
Prim算法
一个点一个点地加入
算法实现
时间复杂度
- O(V^2)
- 所以适用于稠密图,因为只与顶点有关
Kruskal算法
一条边一条边地加入
堆排序Sort()+并查集
算法实现
时间复杂度
- O(|E|log|E|)
- 所以适用于稀疏图,因为只与边有关
最短路径问题
两个顶点之间带权路径长度最短的路径为最短路径
Dijkstra算法
算法实现
算法流程
辅助数组
- s[]:标记已经计算完成的顶点
- 数组中的值全部初始化为0。源点下标的值初始化为1。
- dist[]:记录从源点到其他各顶点当前的最短路径长度。
- 数组中的值初始化为源点到各个顶点边的权值,即dist[i]=arcs[0][i]。
- path[]:记录从最短路径中顶点的前驱顶点,即path[i]为v到vi最短路径上vi的前驱顶点。
- 数组中的值初始化
- 若源点v0到该顶点vi有一条有向边(无向边),则另path[i]=0;否则path[i]=1;
- s[]:标记已经计算完成的顶点
时间复杂度
- O(|V|^2)
不适用于含有负权边的图
Floyd算法
算法思想(动态规划)
算法流程
时间复杂度
- O(|V|^3)
Dijkstra算法不比Floyd快,因为Dijkstra算法仅仅找出来了一个点到其他所有点的最短路径,而Floyd找到的是所有的点到其他的点的最短路径,所以循环V次Dijkstra算法,时间复杂度就一样了,所以具体情况具体分析,Dijkstra算法有针对性,但是不适用于含有负权边的图
拓扑排序
有向无环图
- 不存在环的有向图,简称DAG图
AOV网
- 若用一个DAG图表示一个工程,其顶点表示活动,,用有向边<vi,vj>表示活动vi先于活动vj进行的传递关系,则将这种DAG称为顶点表示活动网络,记为AOV网。
拓扑排序
- 对DAG所有顶点的一种排序,使若存在一条从顶点A到顶点B的路径,在排序中B排在A的后面
算法思想
算法结束时没有访问所有顶点,则存在以剩下项点组成的环
拓扑排序结果不一定唯一
时间复杂度
- O(|V|+|E|)
若邻接矩阵为三角矩阵,则存在拓扑排序;反之不一定成立。
关键路径
AOE网
- 在有向带权图中,以顶点表示事件,以有向边表示活动,以边上权值表示完成该活动的开销(如完成活动所需要的时间),则称这种有向图为用边表示活动的网络,简称AOE网。
- 有且只有一个源点,有且只有一个汇点
- 当入边所有活动都结束时才进行出边
- 从源点到汇点最大路径长度的路径称为关键路径,关键路径上的活动为关键活动
- 事件Vk的最早发生时间Ve(K),即最长路径长度
算法思想
最早发生时间
最迟发生时间(在不推迟工程的前提前)
活动最早开始的时间
活动最迟的开始时间(在不推迟工程的前提前)
活动的差额
关键路径{a2,a5,a7}
缩短关键活动时间可以加快整个工程,但缩短到一定大小时关键路径会发生改变
关键路径不一定唯一,当不唯一的时候,只有加快关键活动或关键活动组合包括在所有的关键路径上才能缩短工期
查找
查找定义
- 在数据集合中寻找满足某种条件的数据元素的过程
查找表定义
- 用于查找的数据集合,由同一种数据类型(或记录)的组成,可以是一个数组或链表等数据类型
查找操作
- 查询某个特定元素是否在查找表中
- 检索满足条件的某个特定的数据元素的各种属性
- 在查找表中插入一个数据元素
- 在查找表中删除一个数据元素
关键字
- 数据元素中唯一标识元素的某个数据项的值,使用基于关键字的查找,查找结果应该是唯一的
平均查找长度(ASL)
查找时,关键字比较次数的平均值
查找公式
查找
顺序查找
又称线性查找,主要用于在线性表中进行查找
无序线性表的顺序查找
实现方式
对无序线性表进行顺序查找,查找失败时要遍历整个线性表
有序线性表的顺序查找
实现方式(这个失败查找的ASL是相对于失败的来说的)
对有序线性表进行顺序查找,查找失败时不一定要遍历整个线性表
判定树
描述查找过程的二叉排序树
折半查找
又称为二分查找,仅适用于有序的顺序表
算法思想
判定树根接近平衡二叉树,所以效率高
时间复杂度
- 查找成功O(log2n)
顺序存储vs链式存储
- 顺序查找适用于顺序存储和链式存储,序列有序无序皆可;折半查找只适用于顺序存储,且要求序列一定有序
分块查找
又称为索引顺序查找,它吸取了顺序查找和折半查找各自的优点,既有动态结构,又适与快速查找
如何分块
- 将查找表分为若干子块。块内的元素可以无序,但块间是有序的,即对于所有块有第i块的最大关键字小于第i+1块的所有记录的关键字
- 建立索引表,索引表中的每个元素含有各块的最大关键字和各块中的第一个元素的地址,索引表按关键字有序排列
- 块间有序,块内无序
如何查找
- 在索引表中确定待查记录所在的块,可以顺序查找或折半查找索引表
- 在块内进行顺序查找
平均查找长度
分为索引查找和块内查找
B树
B+树
散列表
串
- 基本概念
- 模式匹配
排序
基本概念
- 排序定义
- 重新排列表中的元素,使表中的元素满足按关键字递增或递减
- 时空复杂度
- 决定内部排序算法的性能
- 稳定性
- 若待排序表中有两个元素Ri和Rj,其对应的关键字ki=kj,且在排序前Ri在Rj前面,若使用某排序算法后,Ri仍在Rj前面。则称这个排序算法是稳定的,否则排序算法不稳定。
- 但是,算法的稳定性仅仅是算法的性质,并不能衡量一个算法的优劣
- 排序定义
内部排序
概念
- 指在排序期间元素全部存放在内存中的排序
插入排序
概念
- 每次将一个待排序的序列插入到一个前面已拍好序的子序列当中
直接插入排序
算法实现
时间复杂度
- 最好
- O(n)
- 最坏
- O(n^2)
- 平均
- O(n^2)
- 最好
空间复杂度
- O(1)
适用于链式存储、顺序存储
稳定!
折半插入排序
算法实现
时间复杂度
- O(n^2)
空间复杂度
- O(1)
只适用于顺序存储
稳定!
希尔排序
又称缩小增量排序
实现算法
时间复杂度
- 最坏
- O(n^2)
- 大多情况下
- O(n^1.3)
- 最坏
空间复杂度
- O(1)
适用于顺序存储
不稳定!
交换排序
冒泡排序
算法实现
一个冒泡会将一个元素放置到它最终的位置上
时间复杂度
- 最好
- O(n)
- 平均
- O(n^2)
- 最坏
- O(n^2)
- 最好
空间复杂度
- O(1)
适用于顺序存储和链式存储
稳定!
快速排序(递归、分治法)
算法思想(每个学校不一样!)
- 一次划分会将一个元素放置到它最终的位置上
划分的时间复杂度
- O(high-low+1)
时间复杂度
- 最好、平均时间复杂度
- O(nlog2 n)
- 最坏
- O(n^2)
- 最好、平均时间复杂度
空间复杂度
- 最好、平均空间复杂度
- O(log2 n)
- 最坏
- O(n)
- 最好、平均空间复杂度
初始基本有序或逆序会成为最坏情况
适用于顺序存储(也可以改指针成为链式存储,公司面试可能会考)
不稳定!
选择排序
简单选择排序
算法思想
- 一次划分会将一个元素放置到它最终的位置上
时间复杂度与初始序列无关!!!
时间复杂度
- O(n^2)
空间复杂度
- O(1)
适用于顺序存储和链式存储
不稳定
堆排序
堆的概念
- 小根 堆:小根的堆
- 大根 堆:大根的堆
堆的初始化
- 初始建堆时间复杂度
- O(h)=O(n)
- 初始建堆时间复杂度
堆排序
时间复杂度
- O(nlog2 n)
空间复杂度
- O(1)
适用于顺序存储(链式存储)
不稳定!
堆的插入
归并排序
合并操作
算法思想
时间复杂度
- O(high-low+1)
空间复杂度
- O(high-low+1)
归并排序
算法思想
时间复杂度
- 与初始序列无关
- O(nlog2 n)
空间复杂度
- O(n)
适用于顺序存储和链式存储
稳定!
基数排序
概念
算法思路
- 不基于比较!
时间复杂度
- O(d(n+r))//d位数所以要分配收集d次,分配需要循环n次,收集出队需要循环r次
空间复杂度
- O(r)
稳定!
总结&应用
总结截图
应用截图
外部排序
- 概念
- 指在排序期间元素无法全部同时存放在内存中,必须在排序的过程中根据要求不断地在内、外存之间进行移动
- 多路归并排序
- 概念