- 数据:数据是信息的载体,是描述客观事物的数、字符、以及所能输入到计算机中并被计算机程序识别和处理的符号的集合,是计算机程序加工的“原料”。
- 数据元素:数据的基本单位,有时一个数据元素可由若干个数据项组成,数据元素又称为元素、结点、记录。
- 数据项:数据不可分割的最小标识单位。
- 数据对象是具有相同性质的数据元素的集合。
- 数据结构是相互之间存在一种或多种特定关系的数据元素的集合:
- 数据元素都不是孤立存在的
- 是一堆数据元素和这些数据元素之间的关系的总和
- 按照数据元素之间关系的不同特性,大致分为4类基本结构:
- 集合
- 线性结构
- 树型结构
- 图状结构或网状结构
- 用一个二元组表示,记为:Data_Structure = (D,S),D是数据元素的有限集,S是该对象中所有数据成员之间的关系的有限集合。
- 数据的逻辑结构从逻辑关系上描述数据,与数据的存储、数据元素本身的形式、内容、相对位置无关。
- 数据的逻辑结构分类:
- 线性结构:线性表、栈、队列、串
- 非线性结构:树、图
- 数据结构在计算机中的表示称为数据的存储结构(物理结构),包括:
- 数据元素的表示:位、字长、元素、结点、数据域
- 关系的表示(两种基本的存储方法):
- 顺序映像(顺序存储结构)
- 借助数据元素在存储器中的相对位置来表示数据元素之间的逻辑关系。
- 所有元素存放在一片连续的存储单元中,逻辑上相邻元素存放到计算机内仍然相邻
- 非顺序映像(链式存储结构)
- 在每一个数据元素中增加一个存放地址的指针,借助该指针来表示数据元素之间的逻辑关系。
- 所有元素存放在可以不连续的存储单元中,但元素之间的关系可以通过指针确定,逻辑上相邻的元素存放到计算机内存后不一定相邻。
- 数据类型:是一个值的集合和定义在这个值集上的一组操作的总称。
- 原子类型:整型、实型、字符型等。
- 结构类型:数组、结构体、联合等。
- 抽象数据类型-ADT
- 由用户定义,表示应用问题的数据模型
- 可用(D,S,P)三元组表示,D是是数据对象,S是D上的关系集,P是对D的基本操作集。
ADT抽象数据类型名{
数据对象: <数据对象的定义>
数据关系: <数据关系的定义>
基本操作: <基本操作的定义>
} ADT 抽象数据类型名
- 算法定义:是对特定问题求解步骤的一种描述,是一个有穷的指令集,这些指令表示一个或多个操作。
- 算法的特性:
- 有穷性
- 确定性
- 可行性
- 输入
- 输出
- 算法时间复杂度:
算法中基本操作重复执行的次数是问题规模n的某个函数,其时间度量记作 T(n) = 0(f(n)),称作算法的渐近时间复杂度,简称时间复杂度。
一般常用最深层循环内的语句中的原操作的执行频度(重复执行的次数)来表示。
- 线性结构的特点:
- 存在唯一一个被称作“第一个”的数据元素。
- 存在唯一一个被成为“最后一个”的数据元素。
- 除第一个数据元素之外,每个元素都只有一个前驱。
- 除最后一个数据元素之外,每个元素都只有一个后继。
- 线性表:
- 是n个数据元素的有限序列
- 除了第一个元素没有直接前驱和最后一个元素没有直接后继之外,其余的每个元素都只有一个直接前驱和一个直接后继。
- ADT List:
- InitList(&L)
- 将L初始化为空表。
- DostroyList(&L)
- 操作前提:线性表L已存在。
- 操作结果:将L销毁。
- ClearList(&L)
- 操作前提:线性表L已存在。
- 操作结果:将表L置为空表。
- EmptyList(L)
- 操作前提:线性表L已存在。
- 操作结果:如果L为空表则返回真,否则返回假。
- ListLength(L)
- 操作前提:线性表L已存在。
- 操作结果:如果L表为空则返回0,否则返回表中的元素个数。
- GetItem(L,i,&e)
- 操作前提:表L已存在,1<=i<=listlength(L)。
- 操作结果:用e返回L中第i个元素的值。
- LocateElem(L,e)
- 操作前提:表L已存在,e为合法元素值。
- 操作结果:如果L中存在的元素e,则将“当前指针”指向元素e所在位置并返回1,否则返回0。
- ListInsert(&L,i,e)
- 操作前提:表L已存在,e为合法元素值,且1<=i<=ListLength(L)+1。
- 操作结果:在L中第i个位置之前插入新数据元素e,L长度+1
- ListDelete(&L,i,&e)
- 操作前提:表L存在且非空,1<=i<=ListLength(L)
- 操作结果:删除L的第i个元素,并用e返回其值,L的长度-1。
- 顺序表
- 是指用一组地址连续的存储单元依次存储线性表中的各个元素。
- 是一种随存取的存储结构,只要确定了起始位置,就可以访问表中的任何一个元素。
- 链表
- 用一组任意的存储单元存储线性表的数据元素。
- 利用指针实现了用不相邻的存储单元存放逻辑上相邻的元素。
- 每个数据元素a[i],除存储本身信息外,还需存储其直接后继的信息。
- 结点:数据元素a[i]存储映像。
- 数据域:元素本身信息。
- 指针域:指示直接后继的存储位置。
- 循环链表:
- 是一种头尾相接的链表。
- 特点:最后一个结点的指针域指向链表的头结点,整个链表的指针域链接成一个环。
- 双向链表:
- 指的是构成链表的每个结点中设立两个指针域:
- 一个指向其直接前驱的指针域prior。
- 一个指向其直接后继的指针域next。
- 将头结点和尾结点链接起来也能构成循环链表,并称之为双向循环链表。
- 栈
- 是限制在表的一端进行插入和删除操作的线性表,后进先出或先进后出线性表。
- 栈顶:允许进行插入、删除操作的一端,又称为表尾。用栈顶指针(top)来指示栈顶元素。
- 栈底:固定端,又称为表头。
- 空栈:当表中没有元素时称为空栈。
- 栈的存储:
- 顺序存储
- 动态存储
- 静态存储
- 链式存储
- 队列
- 运算受限的线性表,先进先出线性表,只允许在表的一端进行插入,而在另一端进行删除。
- 队首:允许进行删除的一端。
- 队尾:允许进行插入的一端。
- 循环队列
- 将为队列分配的向量空间看成一个首尾相接的圆环,并称这种队列为循环队列。
- rear所指的单元始终为空。
- 循环队列为空:front = rear
- 循环队列满: (rear+1)%MAX_QUEUE_SIZE = front
- 数组
- 数组由n(n>1)个具有相同数据类型的数据元素组成的有序序列,且该序列必须存储在一块地址池连续的存储单元中。
- 数组中的数据元素具有相同数据类型。
- 数组是一种随机存取结构,给定一组下标,就可以访问与其对应的数据元素。
- 数组中的数据元素个数是固定的。
- 对称矩阵
- 树
- 是n(n>=0)个结点组成的有限集合。
- 在任何一个非空树中:
- 有且仅有一个结点称为根(root)。
- 当n>1时,其余的结点可分为m(m>0)个互不相交的有限集合。其中,每个集合本身又是一棵树,被称作这个根的子树。
- 结点:一个数据元素及其若干指向其子树的分支。
- 结点的度:结点所拥有的子树的棵树。
- 树的度:树中结点度的最大值。
- 叶子结点(终端结点):树中度为0的结点。
- 非叶子结点(非终端结点、分支结点):树中的度不为0的结点。
- 除根节点外,分支结点又称为内部结点。
- 孩子结点(子结点):一个结点的子树的根,相应的,该结点是其孩子结点的双亲结点或父结点。
- 兄弟结点:同一双亲结点的所有子结点互称为兄弟结点。
- 层次结点:
- 规定树中根结点的层次为1,其余结点的层次等于其双亲结点的层次等于其双亲结点的层次+1
- 若某结点在第n(n>=1)层,则其余结点在第n+1层。
- 堂兄弟结点:双亲结点在同一层上的所有结点互称为堂兄弟结点。
- 结点的层次路径:从根结点开始,达到某结点p所经过的所有结点称为结点p的层次路径。
- 结点的祖先:结点p的层次路径上的所有结点(p除外)称为p的祖先。
- 结点的子孙:以某一结点为根的子树中的任意结点称为该结点的子孙结点。
- 树的深度:树中结点的最大层值,又称为树的高度。
- 有序树和无序树:对于一棵树,若其中每一个结点的子树(若有的话)具有一定的次序,则该树称为有序树,否则为无序树。
- 森林
- 是m(m>=0)棵互不相交的树的集合。
- 若将一棵树的根结点删除,剩余的子树就构成了森林。
- 总结
- 二叉树
- 二叉树是n(n>=0)个结点的有限集合。若n=0时称为空树,否则:
- 有且仅有一个特殊的称为树的根结点。
- 若n>1时,其余的结点被分成两个互不相交的子集T1、T2,分别称之为左、右子树,并且左右子树都是二叉树。
- 递归性。
- 二叉树性质:
- 在非空二叉树中,第i层上至多有2^i -1个结点(i>=1)。
- 深度为k的二叉树至多有2^k -1个结点(k>=1)。
- 对任何一棵二叉树,若其叶子结点树为n0,度为2的结点数为n2,则n0=n2+1
- 满二叉树:一棵深度为k且有2^k -1个结点的二叉树。
- 满二叉树特点:
- 每一层上的结点数总是最大结点数。
- 满二叉树的所有分支结点都有左、右子树。
- 可对满二叉树的结点进行连续编号,规定从根结点开始,按“自上而下、自左至右”的原则进行。
- 完全二叉树定义:
- 如果深度为k,由n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点一一对应。
- 或深度为k的满二叉树中编号从1到n的前n个结点构成了一棵深度为k的完全二叉树。
- 其中2^(k-1) <= n <= 2^k -1
- 完全二叉树特点:
- 只有最后一层叶子不满,且全部集中在左边。
- 若深度为k,则所有的叶子结点都出现在第k层或k-1层。
- 对于任一结点,如果其右子树的最大层次为I,则其左子树的最大层次为I或I+1
- n个结点的完全二叉树深度为:(向下取证,不大于x的最大整数)。
- 若对一棵有n个结点的完全二叉树(深度为floor[log以2为底n]+1)的结点按层(从第一层到第floor[log以2为底n]+1层)序自左向右进行编号,则对于编号i(1<= i <= n)的结点:
- 若i=1:则结点i是二叉树的根,无双亲结点;否则,若i>1,则其双亲结点编号是 floor[i/2]
- 若2i>n:则结点i为叶子结点,无左孩子;否则,其左孩子结点编号是2i
- 若2i+1>n:则结点i无右孩子;否则,其右孩子结点编号是2i+1
- 二叉树的存储:
- 顺序存储
- 链式存储
- 二叉树的遍历
- 定义:按某条搜索路线遍访每个结点且不重复(又称周游)。
- 用途:它是树结构插入、删除、修改、查找和排序运算的前提,是二叉树一切运算的基础和核心。
- 遍历方法:牢记一个约定,对每个结点的查看都是“先左后右”。
- 示例
- 线索二叉树:
- 具有n个结点的二叉树具有n+1 空指针域。
- 对结点的指针域做法有如下规定:
- 若结点有左孩子,则Lchild指向其左孩子,否则,指向其直接前驱。
- 若结点有右孩子,则Rchild指向其右孩子,否则,指向其直接后继。
- 指向结点前驱和后继的指针叫做索引。
- 按照某种次序遍历,加上线索的二叉树称之为线索二叉树。
- 树如何转换为二叉树:
- 第一步:将树中同一结点的孩子(兄弟)相连。
- 第二步:保留节点的最左孩子连线,删除其它孩子连线。
- 第三步:将同一孩子的连线绕左孩子旋转45°角。
- 二叉树如何转换为树:
- 把所有的右孩子变为兄弟。
- 二叉树序树:
- 二叉排序树或者是空树,或者满足下列性质的二叉树:
- 若左子树不为空,则左子树上所有结点的值(关键字)都小于根结点的值。
- 若右子树不为空,则右子树上所有结点的值(关键字)都大于根结点的值。
- 左、有子树都分别是二叉排序树。
- 平衡二叉树:
- 平衡二叉树或者是空树,或是满足下列性质的二叉树:
- 左子树和右子树深度之差的绝对值不大于1.
- 左子树和右子树也都是平衡二叉树。
- 平衡因子:
- 二叉树结点的左子树的深度减去其右子树深度称为该结点的平衡因子。
- Huffman树——最优二叉树:
- 结点路径:从树中一个结点到另一个结点的之间的分支构成这两个结点之间的路径。
- 路径长度:结点路径上的分支数目称为路径长度。
- 树的路径长度:从树根到每一个结点的路径长度之和。
- 结点的带权路径长度:从该结点到树的根结点之间的路径长度与结点的权(值)的乘积。
- 树的带权路径长度:树中所有叶子结点的带权路径长度之和,记作:WPL=w1 * n1 +w2*n2 … + wn * nn (n为叶子结点个数;wi为第i个结点的权值;ni为第i个结点的路径长度)
- Huffman 树:具有n个叶子结点(每个结点的权值为wi)的二叉树不止一棵,但在所有的这些二叉树中,必定存在一棵WPL值最小的树,称这课树为Huffman树(或称最优树)。
- Huffman 编码:
- 保证任意字符的编码都不是另一个字符编码的前缀,这种编码称为前缀编码。
- Huffman 树可以用来构造编码长度不等且译码不产生二义性的编码。
- 利用赫夫曼树可以构造一种不等长的二进制编码,且构造所得的赫夫曼编码是一种最优前缀编码,即使所传电文的总长度最短。
- 图
- 一个图(G)定义为一个偶对(V,E),记为G=(V,E)
- V是顶点的非空有限集合,记为V(G)
- E是无序集V&V的一个子集,记为E(G),其元素是图的弧。
- 将顶点集合为空的图称为空图。
- 弧:表示两个顶点v和w之间存在一个关系,用顶点偶对<v,w>表示。
- 图的顶点偶对将图分为有向图和无向图。
- 有向图:
- 若图G的关系集合E(G)中,顶点偶对<v,w>的v和w之间是有序的,称图G是有向图。
- 在有向图中,若<v,w>∈E(G),表示从顶点v到顶点w有一条弧。(v称为弧尾或始点,w称为弧头或终点)
- 无向图:
- 若图G的关系集合E(G)中,顶点偶对<v,w>的v和w之间是无序的,称图G是无向图。
- 在无向图中,若任意<v,w>∈E(G),有<w,v>∈E(G),即E(G)是对称,则用无序对(v,w)表示v和w之间的一条边,因此(v,w)和(w,v)代表的试同一条边。
- 完全无向图:
- 对于无向图,若图中定点数为n,用e表示边的数目,则e∈[0,n(n-1)/2]
- 具有n(n-1)/2条边的无向图称为完全无向图。
- 另外一个定义:
- 对于无向图G=(V,E),若任意的 vi,vj ∈V,当vi≠vj时,有(vi,vj)∈E
- 即图中任意两个不同的顶点间都有一条无向边,这样的无向图称为完全无向图。
- 完全有向图:
- 对于有向图,若干图中顶点数为n,用e表示弧的数目,则e∈[0,n(n-1)]。具有n(n-1)条边的有向图称为完全有向图。
- 另外一个定义:
- 对于有向图G=(E,V),若任意的vi,vj ∈V,当vi ≠ vj时,有<vi,vj>∈E且<vi,vi> ∈E
- 即图中任意两个不同的顶点间都有一条弧,这样的有向图称为完全有向图。
- 稀疏图和稠密图
- 有很少边或弧的图称为稀疏图,反之为稠密图。
- 权:
- 与图的边和弧相关的数,权可以表示从一个顶点到另一个顶点的距离或耗费。
- 子图和生成子图:
- 设有图G=(V,E)和G’=(V’,E’),若V’ ∈V且E’∈E,则称图G’是G 的子图。
- 若V’=V且E’∈E,则称图G’是G的一个生成子图。
- 顶点的邻接:
- 对于无向图G=(V,E),若边(v,w)∈E,则称顶点v和w互为邻接点,即v和w相邻接。边(v,w)依附于顶点v和w。
- 对于有向图G=(V,E),若有向弧<v,w>∈E,则称顶点v“邻接到”顶点w,顶点w“邻接自”顶点v,弧<v,w>与顶点v和w“相关联”。
- 顶点的度、入度、出度:
- 对于无向图(V,E),任意的vi∈V,图G中依附于vi的边的数目称为顶点vi的度,记为TD(vi)
- 在无向图中,所有顶点度 的和 是图中边的2倍。
- 对有向图G=(V,E),若任意的vi∈V,图G中以vi作为起点的有向边(弧)的数目称为顶点vi的出度,记为OD(vi)
- 以vi作为终点的有向边(弧)的数目称为顶点vi的入度,记为ID(vi)
- 顶点vi的出度与入度之和称为vi的度,记为TD(vi)
- 路径、路径长度、回路:
- 对于无向图G=(V,E),若从顶点vi经过若干条边能到达vj,称顶点vi和vj是连通的,又称顶点vi到vj有路径。
- 对有向图G=(V,E)从顶点vi到vj有 有向路径,指的是从顶点vi经过若干条有向边(弧)能到达vj
- 路径是图G中连接两顶点之间所经过的顶点序列。
- 路径上边或有向边(弧)的数目称为该路径的长度。
- 简单路径:在一条路径中,若没有重复相同的顶点,该路径称为简单路径。
- 回路:第一个顶点和最后一个顶点相同的路径称为回路(环)。
- 简单回路:在一个回路中,若除去第一个与最后一个顶点外,其余顶点不重复出现的回路称为简单回路(简单环)。
- 连通图、图的连通分量:
- 对于无向图G=(V,E),若任意vi、vj∈V,vi和vj都是连通的,则称图G是连通图,否则称为非连通图。
- 若G是非连通图,则极大的连通子图称为G的连通分量。(“极大”的含义是指 对子图再增加图G中的其他顶点,子图就不在连通)。
- 对有向图G=(V,E),若vi∈V,vj∈V,都有以vi为起点,vj为终点以及以vj为起点vi为终点的有向路径,称图G是强连通图,否则称为非强连通图。
- 若G是非强连通图,则极大的强连通子图称为G的强连通分量。
- 生成树、生成森林:
- 一个连通图(无向图)的生成树是一个极小连通子图,它含有图中全部n个顶点和只有足以构成一棵树的n-1条边,称为图的生成树。
- 关于无向图的生成树的几个结论:
- 一棵有n个顶点和小于n-1条边,则是非连通图。
- 若果多余n-1条边,则一定有环。
- 有n-1条边的图不一定是生成树。
- 有向图的生成森林是这样一个子图,由若干棵有向树组成,含有图中的全部顶点。
- 有向树是只有一个顶点的入度为0,其余顶点的入度均为1的有向图。
- 网:
- 每个边或弧都附加一个权值的图,称为带权图。
- 带权的连通图(包括若连通的有向图)称为网或网络。
- 网络是工程上常用的一个概念,用来表示一个工程或某种流程。
- 图的存储——邻接矩阵
- 以矩阵这种数学形式描述图中顶点之间的关系。
- 假设图中顶点数为n,则邻接矩阵A 定义为 A[i][j]=1 ,若vi和vj直接有边或弧存在;A[i][j] = 0 ,反之。
- 网的邻接矩阵的定义为,当vi和vj有弧相邻接时,Aij的值应为该弧上的权值,否则为无穷。
- 图的存储——邻接表
- 将和同一顶点“相邻接”的所有邻接点链接在一个单链表中,单链表的头指针则和顶点信息一起存储在一个一维数组中。
- 图的存储——十字链表和多重邻接表
- 图的遍历
- 从图的某一顶点出发,访遍图中的其余顶点,且每个顶点仅被访问一次。
- 图的遍历算法是各种图的操作的基础。
- 深度优先算法。
- 广度优先算法
- 查找
- 查找表:相同类型的数据元素(对象)组成的集合,每个元素通常由若干数据项构成。
- 关键字、关键码:数据元素中某个或几个数据项的值,它可以标识一个数据元素。
- 查找/检索:根据给定的k值,在查找表中确定了一个关键字等于给定值的记录或数据元素。
- 查找表中存在满足条件的记录:查找成功。
- 查找表中不存在满足条件的记录:查找失败。
- 平均查找长度:
- 查找过程中关键字的平均比较次数(平均查找长度,ASL)作为衡量一个查找算法效率高低的标准。
- 顺序查找法:
- 从表的一端开始逐个将记录的关键字和给定K值进行比较,若某个记录的关键字和给定K值相等,查找成功;否则,若扫描完整个表,仍然没有找到相应的记录,则查找失败。
- 拆半查找法:
- 针对有序表。
- 查找过程中,先确定待查找记录在表中的范围,然后逐步缩小范围(每次将待查记录所在区间缩小一半),直到找到或找不到记录为止。
- 分块查找法:
- 分块查找又称索引顺序查找,是顺序查找的一种改进方法。
- 将查找表分成几块,块间有序,即第i+1块的所有记录关键字均大于或小于第i块记录关键字;块内无序。
- 在查找表的基础上附加一个索引表,索引表是按关键字有序的,索引表中记录的构成是:
- B树——一种平衡的多路查找树
- 一棵m阶B树,或是空树,或是满足以下性质的m叉树:
- 根结点或者是叶子,或者至少有两颗子树,至多有m棵子树。
- 除根节点外,所有非终端结点至少有ceil[m/2]棵子树,至多有m棵子树。
- 所有叶子结点都在树的同一层上。
- 每个结点应包含如下信息(查找):
- n,A0,K1,A1,K2,A2,…,Kn,An
- 其中Ki(1<= i <=n)是关键字,且Ki<Ki+1(1<=i<=n-1)
- Ai(i=0,1,…,n)为指向孩子结点的指针,且Ai-1所指向的自述中所有结点的关键字都小于Ki。
- Ai所指向的子树中所有结点的关键字都大于Ki
- n是节点中关键字的个数,且ceil[m/2]-1<= n <= m-1,n+1位子树的棵数。
- B+树
- 任意一个结点有n棵子树,则必含有n个关键字。
- 所有叶子结点中包含了全部记录的关键字信息以及这些关键字记录的指针,而且叶子结点按关键字的大小从小到大顺序链接。
- 所有的非叶子结点可以看成是索引的部分,结点中只含有其子树的根结点中的最大或最小关键字。
- 散列表(哈希表)
- 在一般情况下,需在关键字与记录在表中的存储位置之间建立一个函数关系,以f(key)作为关键为key的记录在表中的位置,通常称这个函数为哈希函数。
- 哈希函数是一个映像,即:将关键字的集合映射到某个地址集合上,他的设置很灵活,只要这个地址集合的大小不超出允许范围即可。
- 由于哈希函数是一个压缩映像,因此,在一般情况下,很容易产生“冲突”现象,即:key1 ≠key2,而f(key1)=f(key2)。具有相同函数值的关键字对该哈希函数来说称作同义词。
- 很难找到一个不产生冲突的哈希函数,一般情况下,只能选择恰当的哈希函数,使冲突尽可能少的产生。