Skip to content

KenoChou/datastruct_cpp

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

49 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

数据结构

线性表

$$ 定义线性表为n(n>=0)个数据元素的一个有限数列。记作 $$

$$ L=(a_1,a_2,...a_i,a_{i+1},...,a_n) $$

$$ 其中,L是表名,a_i是表中的数据元素,n是表中的元素的个数,如果n=0,则L为空表 $$

$$ 线性表的第一个元素称为表头(head),最后一个元素称为表尾(tail) $$

线性表的特点

  1. 线性表是一个有限数列,意味着表中的元素的个数有限,且各个表中元素三相继排列的,每两个相邻的元素之间都有.
  2. 对顺序表中的所有元素,即可以进行顺序访问,也可以随即访问.
  3. 顺序表可以用C语言的一维数组实现
  4. 线性表存储数组的数据类型就是顺序表中元素的数据类型,数组的大小要大于等于顺序表的长度
  5. 顺序表中的第i个元素被存储在数组下表为i-1的位置上

栈的概念

栈是只允许在表的一端插入和删除的线性表

  • 栈顶:允许删除与插入
  • 栈底:不允许删除与插入
  • 空栈: 没有元素

栈的操作

void InitStack(Stack& S)
    前提:无
    结果:为栈S分配空间,并对各数据成员赋值
int Push(Stack&S,SElemType x)
    前提: 栈S已经存在且未满
    结果:新元素x进栈S并成为新的栈顶
int Pop(Stack&S,SElemType& x)
    前提:栈S已经存在且栈非空
    结果:若栈S空,则返回0,x不可用,否则栈顶元素推栈,退出元素由x返回,函数返回1
int GetTop(Stack&S,SelemType&x)
    前提:栈S已经存在且栈非空
    操作结果:若栈S空,则函数返回0,x不可用,否则由引用型参数x返回栈顶元素的值但不退栈,函数返回1
int StackEmpty(Stack& S)
     前提:栈S已经存在
     结果:函数测试栈S空否,若栈空,则返回1,否则函数返回0
int StackFull(Stack&S)
     前提:栈S已经存在
     结果:函数测试栈S满否,若栈满,则函数返回1,否则函数返回0
int StackSize(Stack&S)
     前提:栈S已存在
     结果:函数返回栈S的长度,即栈S中元素个数
    

队列

队列的概念

队列是一种限定存取位置的线性表。它只允许在表中一端插入,在另一端删除。

  • 队尾:允许插入的一端
  • 队头:允许删除的一段

队列的主要操作

void InitQueue(Queue& Q)
 前提:无
 结果:队列置空,并对各数据成员赋初值
int Enqueue(Queue&Q,QElemType x)
 前提:队列Q已存在且未满
 结果: 新元素x进队列Q并成为新的队尾
int Dequeue(Queue& Q,QElemType &X)
 前提:队列Q已经存在且为空
 结果:若队列Q空,则函数返回0,x不可用,否则队列Q的队头元素退队,退出元素由x返回,函数返回1.
int GetFront(Queue&Q,QElemType&x)
 前提:队列Q已经存在且队列非空
 结果:若队列Q空,则函数返回0,x不可用;否则由引用参数x返回队列元素的值但不退出队列,函数返回1
int QueueEmpty(Queue&Q)
    前提:队列Q已存在
    结果:判队列Q空否,若队列空,则函数返回1,否则函数返回0
int QueueFull(Queue& Q)
    前提:队列Q已经存在
    结果:判队列Q满否,否队满,则函数返回1,否则函数返回0
int QueueSize(Queue&Q)
    前提:队列Q已经存在
    结果 函数返回队列Q的长度,即队列Q中的元素个数

字符串

字符串是一串文字和符号的序列

字符串的概念

$$ 字符串简称串,是n{(n\geq0)}个字符串的一个有限序列,通常可记为 $$

$$ S=''a_0a_1a_2...a_n-1'' $$

$$ 其基本组成元素是单个字符,字符串的长度可变 $$

  1. 串值和串名:串值是可以直接引用的串,如“helloworld”,一般用单引号或者双引号作为分界符括起来
  2. 串长度:串中字符个数。长度为0的串为空串,长度大于零的串为非空串
  3. 子串:若一个字符串不为空,从这个串中连续取出若干个字符组成的串叫做原串的子串
  4. 前缀子串:从串的开始连续取出若干个字符组成的串
  5. 后缀子串:从串的某一位置开始到串的最后位置连续取出若干个位置组成的串

广义表

广义表的概念

$$ 一个广义表元素可定义为n{(n\geq0)}个元素a_0,a_1,a_2,...a_{n-1}组成的有限序列 $$

$$ LS=(a_0,a_1,a_2,...a_{n-1}) $$

$$ 其中LS为表名,a_i(0{\leq}i{\leq}n-1)是表中元素,它或是数据元素(原子),亦或是子表 $$

$$ n是表的长度,即表中元素个数,长度为0的表为空表 $$

$$ 如果n{\geq1},则称广义表的第一个元素a_0为广义表的表头,其他元素为表的表尾 $$

广义表的性质

  • 次序:在广义表中,各元素在表中以线性序列排列,顺序不能交换
  • 有长度:广义表元素个数是一定的,不能是无限的,可以是空表
  • 有深度:广义表的表元素可以是原表的子表,子表还可以是字表...因此广义表是多层次结构
  • 可递归:广义表本身可以是自己的子表
  • 可共享:广义表可以为其他广义表共享

树的概念

树的具体:家族家谱,公司的组织结构,书的章节

树的定义与术语

树的定义

$$ 一颗树是n(n\geq0)个结点的有限集合,n=0为空树,非空记作 $$

$$ T={{r,T_1,T_2...T_n}} $$

$$ r是T的根结点,T_1,T_2...T_m是除其他结点构成的互不相交的m(m\geq0)个子集合。 $$

$$ 每颗子树的跟结点都有一个直接前趋(即它的上层结点),但可以有0个或多个直接后继(即它的下层结点)。 $$

$$ m称为r的分支数 $$

树的基本术语

$$ 结点:它包含数据元素的值及指向其他结点的分支指针 $$

$$ 结点的度:是结点所拥有的子树棵树。 $$

$$ 叶结点:即度为0的结点,又称为终端结点 $$

$$ 分支结点:除叶结点外的其他结点,又称非终端结点 $$

$$ 子女结点:若结点x有子树,则子树的根结点即为结点x的子女。 $$

$$ 双亲结点:若结点x有子树,它即为子女的双亲。 $$

$$ 兄弟结点:同一双亲的子女结点为兄弟。 $$

$$ 祖先结点:从根结点到该结点所经分支上的所有结点 $$

$$ 子孙结点:某一结点的子女,以及这些子女的子女都是该结点的子孙 $$

$$ 结点间的路径:树中任一结点v_1,v_2,...,v_k到v_j,其中(v_i,v_i),(v_1,v_2),...(v_k,v_j)是树中的分支 $$

$$ 则v_i,v_1,v_2,...v_k,v_j是v_i与v_j间的路径 $$

$$ 结点的深度:即结点所处层次,简称结点的层次,即从根到该结点的路径上分支数加1 $$

$$ 结点的高度:空树的高度为0,叶结点的高度为1,非叶结点的高度等于两个子女结点高度中的最大值加1 $$

$$ 树的深度:树中距离根结点最远的结点,结点所处层次即为树的深度。空树的深度为0 $$

$$ 只有一个根结点的树的深度为1 $$

$$ 树的高度:树的高度等于根结点的高度 $$

$$ 树的宽度:统计树中每一层结点个数 $$

$$ 树的度:树中结点的度的最大值 $$

$$ 有序树:树中结点的各树子树T_0,T_1,....是有次序的,即为有序树 $$

$$ 无序树:树中结点的各颗子树之间的次序是不重要的,可以互换位置 $$

$$ 森林:是m{(m\geq0)}颗树的集合。 $$

void InitTree(Tree&T)
    前提:无
    结果:建立一个根指针为T的空树
void ClearTree(TreeNode*& T )
    前提:树非空
    结果:将树T中所有结点释放,将树清空
position FirstChild(Tree&T,position p)
     前提:结点p是树T的结点
     结果:返回结点p的第一个子女结点地址,若无子女,则函数返回0
position NextSibing(Tree& T,position p)
        前提:结点p是树T的结点
        结果:返回结点p的下一个兄弟结点地址,若无一个兄弟,返回0
position Parent(Tree & T,position p)
        前提:结点p是树T的结点
        结果:返回结点p的双亲地址,若结点p为根,返回0
int InsertChild(Tree& T,position p,TElemType x)
        前提:树T非空且结点p为树T的结点
        结果:在结点p下插入值为x的新子女,若插入失败,函数返回0,否则函数返回1
int DeleteChild(Tree& T,position p,int i)
            前提:树T非空且结点p是树T的结点
            结果:删除结点p的第i个结点,若删除失败,则函数返回0,否则函数返回1
void DeleteSubTree(Tree &T,position i)
            前提:t是树T的结点
            结果:删除以t为根的子树的全部结点且t置为空
void Traversal(Tree &T ,position p)
            前提:树T非空且结点p是树的结点
            结果:遍历以结点p为根的子树

二叉树及其存储

二叉树的概念

二叉树的性质

二叉树的主要操作

二叉树的顺序存储表示

二叉树的链表存储表示

二叉树的遍历

二叉树的递归遍历算法

递归遍历算法的应用举例

二叉树遍历的非递归算法

小根堆和大根堆

$$ 简单路径与回路:若路径上各顶点v_i,v_2,...v_m均不互相重复,则称这样的路径为简单路径。 $$

$$ 若路径上第一个顶点v_1与最后一个顶点v_m重合,则称这样的路径为回路或环。 $$

$$ 若回路中的路径是简单路径,则称这样的回路是简单回路 $$

$$ 连同图与连同分量:在无向图中,从顶点v_1到顶点v_2有路径,则称顶点v_1与v_2是连同的 $$

$$ 如果图中任意一对顶点都是连通的,则称此图是连通图。非连通图的极大连通子图叫做连通分量 $$

$$ 强连通图与强连通分量:在有向图中,若每一对顶点v_i和v_j之间的都存在一条v_i到v_j的路径, $$

$$ 也存在一条从v_j到v_i的路径,则称此图是强连通图 $$

$$ 非强连通图的极大强连通子图叫做强连通分量 $$

$$ 生成树:一个无向连通图的生成树是它的极小连通子图,若图中含有n个顶点,则其生成树是由{n-1}条边构成 $$

$$ 若是有向图,则可能得到它的由若干有向树组成的生成森林 $$

图的基本操作

假设图的顶点数据的数据类型是Type,边上权值的数据类型是weight,则有如下操作
void CreateGraph(Graph&G,int n,int m)
    前提:无。
    结果从键盘输入n个顶点和m条边的信息,建立一个图
 void PrintGraph(Graph& G)
    前提:图G已存在
    结果 输出所有边和顶点的信息。
 void InitGraph(Graph& G)
    前提:图已经建立
    结果:将图的顶点数和边数的都置为0.
 int GetVertexPos(Graph& G,Type x)
    前提: 该顶点属于图的顶点集合
    结果: 从顶点的数据值找出该顶点的顶点号,如果查找失败 ,返回-1
 int NumberOfVertices(Graph& G)
    前提 :图以及存在;
    结果: 函数返回图中当前已有的顶点数
 int NumberOfEdges(Graph& G)
    前提:图已存在
    结果:函数返回图中当前图中已有的边数
 Type GetValue(Graph& G,int i)
     前提:图已存在,且i是合法的顶点号
     结果: 函数返回顶点i的值,若i不合理则返回0
 Weight GetWeight(Graph& G.int V1,int V2)
     前提:图已经存在,且V1 ,V2是合理的顶点号,(V1,V2)是图中的边
     结果:函数返回边V1,V2所带回的权值
int FirstNeighbor(Graph& G,int v)
     前提:图已经存在,V是合理的顶点号
     结果:函数返回第一个邻接顶点V的顶点号,若无则返回-1
int NextNeighbor(Graph & G,int V,int W)
     前提:图已经存在,v和W都是合理的顶点号
     结果:函数返回顶点V的邻接顶点W后下一邻接顶点的顶点号,若无则返回-1
void InsertVertex(Graph& G,Type vertex)
    前提: 图的顶点数未到达最大顶点数
    结果: 在图中插入一个顶点vertex ,该顶点暂时没有边
void InsertEdge(Graph& G,int V1,int V2)
    前提:V1和V2都是图中的顶点,且依附于V1和V2的边还不存在
    结果:在图中插入一条边(V1,V2)
void RemoveVertex(Graph& G,int V)
    前提:图已经存在,且V是图中合理的顶点号
    结果:删去顶点V和所有关联它的边
void RemoveEdge(v                                   Grapg& G,int V1,int V2)
     前提:图已经存在,V1,V2是合理的顶点号,且(V1,V2)是合理的边
     结果:在图中删去边(V1,V2)
    

查找

查找的概念

  • 查找表:查找的元素集合

    • 静态查找表:如果对表执行插入和删除操作等操作表后表结构不发生改变
    • 动态查找表:如果对表执行插入和删除等操作后,为保持较高的查找效率,结构本身要调整
  • 关键码:在查找表中,每一个元素有若干个属性,其中应当有一个属性,其值可唯一地被标识

查找的算法性能分析

$$ 设查找表中有n个元素,查找第i(1{\leq}i{\leq}n),找到它的关键码比较次数是c_i $$

$$ 则p_i{\times}c_i是成功查找第i个元素可能的关键码比较次数 $$

$$ ASL_{成功}=\sum_{i=1}^n p_ic_i,\sum_{i=1}^nP_i=1 $$

$$ ASL_{不成功}:查找在查找表中不存在元素,还定义查找不成功的平均查找长度,它被定义在查找表中有n个元素 $$

$$ 现在要查找表中的第n+1个元素,找到其插入元素的平均比较次数 $$

顺序查找法

折半查找法

次优查找树

斐波那契查找

插值查找

二叉查找树

二叉查找树的概念

二叉查找树又称二叉排序树,它或者是一颗空树

  • 每个结点都有一个作为查找依据的关键码(key),所有结点的关键码互不相同

  • 左子树(如果非空)上所有结点的关键码的都小于根结点的关键码

  • 右子树(如果非空)上所有结点的关键码都大于根结点的关键码

  • 左子树和右子树也是二叉查找树

    如果对一个二叉查找树进行中序遍历,可以将个结点的关键码按从小到大的顺序排列

平衡二叉树

二叉树的概念

定义:左子树与右子树的高度之差的绝对值不会超过1

排序

排序的相关概念

  • 数据表:它是待排序元素的有限集合

  • 排序码:通常定义排序码为元素中用来标识与阿努斯,作为排序依据的属性

  • 排序的确切定义:递增or递减

  • 原地排序:排序过程中只使用了规模为O(1)的额外空间存储空间,排序结果仍然保留在原来的数据表内

  • 排序算法的稳定性:如果在元素序列中两个元素Ri和Rj,它们的排序码Ki=Kj

    • 如果排序前Ri在Rj之前,排序后为改变,则说排序是稳定的
  • 排序方法分类

    • 有序区增长:

​ 将数据表分为有序区和无序区,在排序过程中逐步扩大有序区,缩小无序区

  • 有序程度增长:

​ 数据表无能明确区分有序区和无序区,随着排序过程的执行,逐步调整表中的元素的排列,

​ 使得表中有序程度不断提高,直到完全有序

  • 内排序与外排序
    • 内排序:内排序是子阿排序期间数据元素全部放在内存中
    • 外排序:排序期间元素太多,不能完全放在内存中,需要按照排序要求在内存宇外存移动排序
  • 静态排序与动态排序
    • 静态排序:
      • 采用顺序表存储代排序元素
      • 采用链表存储排序元素,经通过增加一个指针地址信息来改变元素之间的逻辑顺序
      • 动态排序
        • ​ 通过动态链表存储带排序元素,通过修改链接指针来改变元素之间的逻辑顺序,但表的结构不会改 变

排序算法的性能分析

  • 执行时间
  • 额外内存空间
    • 除使用有限的几个负责元素交换的工作单元之外,不需要使用其他额外内存空间
    • 使用链表指针或树组下标表明元素的逻辑顺序,指针或下标需要额外的内存空间
    • 需要额外的空间来存储待排序元素序列的副本或排序的中间结果

插入排序

插入排序

基于静态链表的直接插入排序

折半插入排序

希尔排序

交换排序

起泡排序

快速排序

选择排序

简单选择排序

锦标赛排序

堆排序

归并排序

二路归并排序

基数排序

MSD基数排序

LSD基数排序

About

datastruct

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published