mirror of
https://gitee.com/coder-xiaomo/notes
synced 2025-01-11 20:18:16 +08:00
899 lines
29 KiB
Markdown
899 lines
29 KiB
Markdown
---
|
||
sidebarDepth: 4
|
||
---
|
||
|
||
<style>
|
||
</style>
|
||
# 数据结构
|
||
|
||
|
||
> 参考书籍:数据结构教程(第5版) 李春葆
|
||
|
||
📔📕📖📗📘📙📚📓📒★⭐🌟🌠
|
||
|
||
|
||
|
||
::: 文档正在整理中......
|
||
|
||
|
||
|
||
::: details <b>目录</b>(点击展开)
|
||
[[toc]]
|
||
:::
|
||
|
||
|
||
|
||
## 1 数据结构
|
||
|
||
### 定义
|
||
|
||
**数据**:描述客观事物的数和字符的集合。
|
||
|
||
**数据元素**:数据的基本单位。
|
||
|
||
**数据项**:具有独立含义的数据最小单位,也称为字段区域。
|
||
|
||
**数据对象**:性质相同的数据元素的集合,它是数据的一个子集。
|
||
|
||
**数据结构**:所有数据元素以及数据元素之间的关系,可以看作是相互之间存在着某种特定关系的数据元素的集合。
|
||
|
||
**数据结构 = 数据 + 结构**
|
||
|
||
### 数据结构
|
||
|
||
#### 逻辑结构
|
||
|
||
数据的**逻辑结构** 由数据元素之间的逻辑关系组成。
|
||
|
||
##### 表示
|
||
|
||
1. 图表表示
|
||
|
||
2. 二元组表示
|
||
|
||
一个二元组表示如下:B=(D,R)
|
||
|
||
其中,B是一种逻辑结构,它由数据元素的集合D以及D上二元关系的集合R所组成。 D={} R={}
|
||
|
||
前驱元素
|
||
|
||
后继元素
|
||
|
||
开始元素
|
||
|
||
终端元素
|
||
|
||
##### 类型
|
||
|
||
集合
|
||
|
||
线性结构
|
||
|
||
树形结构
|
||
|
||
图形结构
|
||
|
||
#### 存储结构(物理结构)
|
||
|
||
数据的**存储结构** 数据元素及其关系在计算机存储器中的存储表示,也称为数据的物理结构。
|
||
|
||
常用存储结构类型
|
||
|
||
1.顺序存储结构
|
||
|
||
2.链式存储结构
|
||
|
||
3.索引存储结构
|
||
|
||
4.哈希(或散列)存储结构
|
||
|
||
#### 数据运算
|
||
|
||
**数据的运算** 施加在该数据上的操作。
|
||
|
||
算法
|
||
|
||
算法时间性能分析
|
||
|
||
算法空间性能分析
|
||
|
||
## 2 线性表
|
||
|
||
**线性表**:具有相同特性的数据元素的一个有限序列。
|
||
|
||
**存储密度**:结点中数据元素本身所占的存储量和整个结点占用的存储量之比。(顺序表的存储密度比较高)
|
||
|
||
顺序表
|
||
|
||
顺序表:线性表的顺序存储结构
|
||
|
||
基本运算*(对原表有操作的,传入形参的变量名前需要加&)*
|
||
|
||
建立顺序表 CreateList(SqList *&L, Elemtype a[], int n) // 由a中的n个元素建立顺序表L
|
||
|
||
初始化线性表 InitList(&L)
|
||
|
||
销毁线性表 DestroyList(&L)
|
||
|
||
判断线性表是否为空表 ListEmpty(L)
|
||
|
||
求线性表的长度 ListLength(L)
|
||
|
||
输出线性表 DispList(L)
|
||
|
||
求线性表中的某个数据的元素值 GetElem(L, i, &e)
|
||
|
||
按元素值查找 LocateElem(L, e)
|
||
|
||
插入数据元素ListInsert(&L, i, e)
|
||
|
||
删除数据元素 ListDelete(&L, i, &e)
|
||
|
||
链表
|
||
|
||
链表:线性表的链式存储结构
|
||
|
||
链表
|
||
|
||
单链表
|
||
|
||
双链表
|
||
|
||
循环链表
|
||
|
||
基本运算
|
||
|
||
初始化线性表 InitList(&L)
|
||
|
||
销毁线性表 DestroyList(&L)
|
||
|
||
求线性表的长度 ListLength(L)
|
||
|
||
输出线性表 DispList(L)
|
||
|
||
求线性表中的某个数据的元素值 GetElem(L, i, &e)
|
||
|
||
按元素值查找 LocateElem(L, e)
|
||
|
||
插入数据元素ListInsert(&L, i, e)
|
||
|
||
删除数据元素 ListDelete(&L, i, &e)
|
||
|
||
头插法 尾插法
|
||
|
||
## 3 栈 队列
|
||
|
||
栈
|
||
|
||
**栈**:一种只能在一端进行插入或删除操作的线性表。
|
||
|
||
定义
|
||
|
||
表中允许操作的一端,称为**栈顶**,表的另一端称为**栈底**。
|
||
|
||
当栈中没有元素时称为**空栈**。
|
||
|
||
栈的插入操作同城称为**进栈**或**入栈**(push),栈的删除操作通常称为**出栈**或**退栈**(pop)
|
||
|
||
特点:后进先出
|
||
|
||
类型
|
||
|
||
**顺序栈**:采用顺序结构存储的栈
|
||
|
||
**链栈**:采用链式存储结构的栈
|
||
|
||
基本运算算法
|
||
|
||
初始化栈 initStack(&s)
|
||
|
||
销毁栈 DestroyStack(&s)
|
||
|
||
判断栈是否为空 StackEmpty(s)
|
||
|
||
进栈 Push(&s, e)
|
||
|
||
出栈 Pop(&s, &e)
|
||
|
||
取栈顶元素 GetTop(s, &e)
|
||
|
||
队列
|
||
|
||
**队列**:简称**队**,他也是一种操作受限的线性表,其限制为仅允许在表的一端进行插入操作,而在表的另一端进行删除操作。
|
||
|
||
定义
|
||
|
||
把进行插入的一端称为**队尾**(rear),把进行删除的一端称为**队头**或**队首**(front)
|
||
|
||
向队列中插入新元素称为**进队**或**入队**(enquene),新元素进队后就成为新的队尾元素
|
||
|
||
从队列中删除元素称为**出队**或**离队**(dequene),元素出队后,其直接后继元素就成为队首元素
|
||
|
||
特点:先进先出
|
||
|
||
类型
|
||
|
||
**顺序队**:采用顺序存储结构的队列
|
||
|
||
**链队**:采用链式存储结构的队列
|
||
|
||
环形队列(循环队列)
|
||
|
||
**假溢出**:因为队满条件设置不合理导致队满条件成立而队列中仍然有空位置的情况
|
||
|
||
基本运算算法
|
||
|
||
初始化队列 initQueue(&q)
|
||
|
||
销毁队列 DestroyQueue(&q)
|
||
|
||
判断队列是否为空 QueueEmpty(q)
|
||
|
||
进队列 enQueue(&q, e)
|
||
|
||
出队列 deQueue(&q, &e)
|
||
|
||
## 4 串
|
||
|
||
**串**:由零个或多个字符组成的有限序列
|
||
|
||
顺序串:
|
||
|
||
非紧缩格式
|
||
|
||
紧缩格式
|
||
|
||
链串:采用链式存储结构存储的串
|
||
|
||
串基本运算
|
||
|
||
生成串 StrAssign(&s, cstr)
|
||
|
||
销毁串 DestroyStr(&s)
|
||
|
||
串的复制 StrCopy(&s, t)
|
||
|
||
判断串相等 StrEqual(s, t)
|
||
|
||
求串长 StrLength(s)
|
||
|
||
串的连接 Concat(s, t)
|
||
|
||
求子串 SubStr(s, i, j)
|
||
|
||
子串的插入 InsStr(s1, i, s2)
|
||
|
||
子串的删除 DelStr(s, i, j)
|
||
|
||
子串的替换 RepStr(s, i, j, t)
|
||
|
||
输出串 DispStr(s)
|
||
|
||
串的模式匹配
|
||
|
||
Brute-Force算法
|
||
|
||
KMP算法
|
||
|
||
## 5 递归
|
||
|
||
定义
|
||
|
||
在定义一个过程或函数时出现调用本过程或本函数的成分称为**递归**,若调用自身,称为**直接递归**;若过程或函数p调用过程或函数q,而q又调用p,称为**间接递归**。
|
||
|
||
**尾递归**:如果一个递归过程或递归函数中的递归调用语句是最后一条执行语句,则称这种递归调用为尾递归。
|
||
|
||
递归模型由递归出口和递归体两部分组成。**递归出口**确定递归到何时结束。**递归体**确定递归求解时的递推关系。
|
||
|
||
## 6 数组
|
||
|
||
**数组**:具有相同类型的数据元素的有限序列,可以将它看作是线性表的推广。
|
||
|
||
定义
|
||
|
||
**对称矩阵**:若一个n阶方阵A[n][n]中的元素ai,j=aj,i (0≤i, j≤n-1),则称其为n阶对称矩阵。
|
||
|
||
**上三角矩阵**:矩阵的下三角部分中的元素均为常数c的n阶方阵。
|
||
|
||
**下三角矩阵**:矩阵的上三角部分中的元素均为常数c的n阶方阵。
|
||
|
||
**对角矩阵**:若一个n阶方阵A满足其所有非零元素都集中在以主对角线为中心的带状区域中,则称其为对角矩阵。
|
||
|
||
**稀疏矩阵**:放一个阶数较大的矩阵中的非零元素个数s相对于矩阵元素的总个数t非常小时,即s<<t时,称该矩阵为稀疏矩阵。
|
||
|
||
稀疏矩阵是一种特殊的二维数组
|
||
|
||
**三元组表**:若把稀疏矩阵的三元组线性表按顺序存储结构存储,则称为稀疏矩阵的三元组顺序表,简称为 三元组表。
|
||
|
||
数组
|
||
|
||
一维数组
|
||
|
||
二维数组
|
||
|
||
特殊矩阵的压缩存储
|
||
|
||
对称矩阵的压缩存储
|
||
|
||
上、下三角矩阵的压缩存储
|
||
|
||
对角矩阵的压缩存储
|
||
|
||
稀疏矩阵
|
||
|
||
## 7 树
|
||
|
||
7.1 树
|
||
|
||
7.1.1 树的定义
|
||
|
||
**树**:由n(n≥0)个结点(或元素)组成的有限集合(记为T)。
|
||
|
||
如果n=0,它是一棵空树,这是树的特例;
|
||
|
||
如果n>0,这n个结点中有且仅有一个结点作为树的**根结点**,简称为**根**,其余结点可分为m(m≥0)个互不相交的有限集T1, T2, …, Tm,其中每个子集本身又是一棵符合本身定义的树,称为根结点的**子树**。
|
||
|
||
7.1.2 树的逻辑表示方法
|
||
|
||
(1)树形表示法
|
||
|
||
(2)文氏图表示法
|
||
|
||
(3)凹入表示法
|
||
|
||
(4)括号表示法
|
||
|
||
7.1.3 树的基本术语
|
||
|
||
(1)结点的度与树的度
|
||
|
||
**结点的度**:树中某个结点的子树的个数
|
||
|
||
**树的度**:树中所有结点的度中的最大值
|
||
|
||
**m****次树**:度为m的树
|
||
|
||
(2)分支结点与叶子结点
|
||
|
||
**分支结点(非终端结点)**:树中度不为0的结点
|
||
|
||
**叶子结点**:度为0的结点
|
||
|
||
**单分支结点**:度为1的结点(分支数为1)
|
||
|
||
**双分支结点**:度为2的结点(分支数为2)
|
||
|
||
(3)路径与路径长度
|
||
|
||
**路径**:对于树中的任意两个结点ki和kj,若树中存在一个结点序列(ki, ki1, ki2, …, kin, kj),使得序列中除ki以外的任一结点都是其在序列中的前一个结点的后继结点,则称该结点序列为由ki到kj的一条路径
|
||
|
||
**路径长度**:是该路径所通过的结点数目减1(即路径上分支数目)
|
||
|
||
(4)孩子结点、双亲结点和兄弟结点
|
||
|
||
**孩子结点、双亲结点**:在一棵树中,每个结点的后继结点被称为该结点的孩子结点。相应地,该结点被称为孩子结点的双亲结点
|
||
|
||
**兄弟结点**:具有同一双亲结点的孩子结点互为兄弟结点
|
||
|
||
**子孙结点**:每个结点对应子树中的所有结点(除自身外)称为该结点的子孙结点
|
||
|
||
**祖先结点**:把从根结点到达某个结点的路径上经过的所有结点(除自身外)称为该结点的祖先结点
|
||
|
||
(5)结点层次和树的高度
|
||
|
||
**结点层次**或**结点深度**:从树根开始定义,根结点为第一层,它的孩子结点为第二层,依此类推,一个结点所在的层次为其双亲结点的层次加1。
|
||
|
||
**树的高度**或**树的深度**:树中结点的最大层次
|
||
|
||
(6)有序树和无序树
|
||
|
||
一般情况下,如果没有特别说明,默认树都是指有序树
|
||
|
||
树中各结点的子树按照一定次序从左向右安排,且相对次序不能随意变换,称为**有序树**,否则称为**无序树**
|
||
|
||
(7)森林
|
||
|
||
把含有多棵子树的树时的根结点删去就成了森林。反之,给m(m>1)棵独立的树加上一个根结点,并把这m棵树作为该结点的子树,则森林就变成了一棵树。
|
||
|
||
**森林**:n(n>0)个互不相交的树的集合
|
||
|
||
7.1.4 树的性质(证明见书P192-193)
|
||
|
||
性质1:树中的结点数等于所有结点的度数之和加1
|
||
|
||
性质2:度为m的树中第i层上最多有m^(i-1)个结点(i≥1)
|
||
|
||
性质3:高度为h的m次树最多有(m^h - 1) / (m - 1)个结点
|
||
|
||
性质4:具有n个结点的m次树的最小高度为┌log m ( n(m-1) + 1 )┐
|
||
|
||
7.1.5 树的基本运算
|
||
|
||
1. **先根遍历**
|
||
|
||
(1)访问根结点
|
||
|
||
(2)按照从左到右的顺序先根遍历根结点的每一棵子树
|
||
|
||
2. **后根遍历**
|
||
|
||
(1)按照从左到右的顺序后根遍历根结点的每一棵子树
|
||
|
||
(2)访问根结点
|
||
|
||
3. **层次遍历**
|
||
|
||
从根结点开始,从上到下、从左到右的顺序访问树中的每一个结点
|
||
|
||
7.1.6 树的存储结构(书P195-P198)
|
||
|
||
1. 双亲存储结构
|
||
|
||
2. 孩子链存储结构
|
||
|
||
3. 孩子兄弟链存储结构
|
||
|
||
7.2 二叉树
|
||
|
||
7.2.1 二叉树的定义
|
||
|
||
**二叉树**:一个有限的结点集合,这个集合或者为空,或者由一个根结点和两棵互不相交的【书上这里似乎掉了点东西】称为左子树和右子树的二叉树组成
|
||
|
||
**满二叉树**:(满二叉树是完全二叉树的一种特例)
|
||
|
||
在一棵二叉树中,所有分支结点都有左孩子结点和右孩子结点,且叶子结点都集中在二叉树的最下一层
|
||
|
||
一棵高度为h且有2^h - 1个结点的二叉树
|
||
|
||
特点:
|
||
|
||
叶子结点都在最下一层
|
||
|
||
只有度为0和度为2的结点
|
||
|
||
**完全二叉树**:二叉树中最多只有最下面两层的结点的度数可以小于2,并且最下面一层的叶子结点都依次排列在该层最左边的位置上
|
||
|
||
特点:
|
||
|
||
叶子结点只可能在最下面两层
|
||
|
||
对于最大层次中的叶子结点,都依次排列在该层最左边的位置上
|
||
|
||
如果有度为1的结点,只可能有1个,且该结点只有左孩子而无右孩子
|
||
|
||
按层序编号时,一旦出现编号为i的结点是叶子结点或只有左孩子,则编号大于i的结点均为叶子结点
|
||
|
||
当结点总数n为奇数时,n1=0,当结点总数n为偶数时,n1=1
|
||
|
||
**层序编号**:约定编号从树根为1开始,按照层序从小到大、同一层从左到右的次序进行。
|
||
|
||
7.2.2 二叉树的性质
|
||
|
||
性质1:非空二叉树上的叶子结点数=双分支结点数+1
|
||
|
||
性质2:非空二叉树的第i层上最多有2^(i-1)个结点(i≥1)
|
||
|
||
性质3:高度为h的二叉树最多有2^h-1个结点(h≥1)
|
||
|
||
性质4:完全二叉树中的层序编号为i的结点(1≤i≤n, n≥1, n为结点数)有以下性质:
|
||
|
||
(1)若i≤└n/2┘,即2i≤n,则编号为i的结点为分支结点,否则为叶子结点。
|
||
|
||
(2)若n为奇数,则每个分支结点都既有左孩子结点,又有右孩子结点;若n为偶数,则编号最大的分支结点(编号为└n/2┘)只有左孩子结点,没有右孩子结点,其余分支结点都有左、右孩子结点。
|
||
|
||
(3)若编号为i的结点有左孩子结点,则左孩子结点的编号为2i;若编号为i的结点有右孩子结点,则右孩子结点的编号为2i+1
|
||
|
||
(4)除根结点以外,若一个结点的编号为i,则它的双亲结点的编号为└n/2┘
|
||
|
||
性质5:具有n个(n>0)结点的完全二叉树的高度为┌log₂(n+1)┐或└log₂n┘+1
|
||
|
||
7.2.3 二叉树与树、森林之间的转换
|
||
|
||
1. 森林、树转换为二叉树
|
||
|
||
将一棵树转换成二叉树的过程如下:
|
||
|
||
(1)树中所有相邻兄弟之间加一条连线
|
||
|
||
(2)对树中的每个结点只保留它与长子之间的连线,删除与其他孩子之间的连线
|
||
|
||
(3)以树的根结点为轴心,将整棵树顺时针转动45°,使之结构层次分明。
|
||
|
||
2.二叉树还原为树/森林
|
||
|
||
若一棵二叉树是由一棵树转换而来的,则该二叉树还原为树的过程如下:
|
||
|
||
(1)若某结点是其双亲的左孩子,则把该结点的右孩子、右孩子的右孩子等都与该结点的双亲结点用连线连起来。
|
||
|
||
(2)删除原二叉树中所有双亲结点与右孩子结点之间的连线。
|
||
|
||
(3)整理由前面两步得到的树,即以根结点为轴心,逆时针转动45°,使之结构层次分明。
|
||
|
||
实际上,二又树的还原就是将二叉树中的左分支保持不变,将二叉树中的右分支还原成兄弟关系。
|
||
|
||
7.3 二叉树的存储结构
|
||
|
||
二叉树的顺序存储结构
|
||
|
||
二叉树的链式存储结构
|
||
|
||
基本运算算法
|
||
|
||
创建二叉树 CreateBTree(*b, *str)
|
||
|
||
销毁二叉树 DestroyBTree(&b)
|
||
|
||
查找结点 FindNode(b, x)
|
||
|
||
找孩子结点 LchildNode(p) 和 RchildNode(p)
|
||
|
||
求高度 BTHeight(b)
|
||
|
||
输出二叉树 DispBTree(b)
|
||
|
||
7.5 二叉树的遍历
|
||
|
||
**先序遍历**
|
||
|
||
(1)访问根结点
|
||
|
||
(2)先序遍历左子树
|
||
|
||
(3)先序遍历右子树
|
||
|
||
**中序遍历**
|
||
|
||
(1)中序遍历左子树
|
||
|
||
(2)访问根结点
|
||
|
||
(3)中序遍历右子树
|
||
|
||
**后序遍历**
|
||
|
||
(1)后序遍历左子树
|
||
|
||
(2)后序遍历右子树
|
||
|
||
(3)访问根结点
|
||
|
||
**层次遍历**
|
||
|
||
(1)访问根结点(第1层)
|
||
|
||
(2)从左到右访问第2层的所有结点
|
||
|
||
(3)从左到右访问第3层的所有结点、……、第h层的所有结点
|
||
|
||
7.6 二叉树的构造
|
||
|
||
定理7.1:任何n(n≥0)个不同结点的二叉树,都可由它的中序序列和先序序列唯一地确定。
|
||
|
||
定理7.2:任何n(n≥0)个不同结点的二叉树,都可由它的中序序列和后序序列唯一地确定。
|
||
|
||
7.7 线索二叉树
|
||
|
||
遍历二叉树的结果是一个结点的线性序列,可以利用这些空链域存放指向结点的前驱结点和后继结点的地址。其规定是当某结点的左指针为空时,令该指针指向这个线性序列中该结点的前驱结点;当某结点的右指针为空时,令该指针指向这个线性序列中该结点的后继结点,这样的指向该线性序列中的“前驱结点”和“后继结点”的指针称为**线索**。创建线索的过程称为**线索化**。线索化的二叉树称为**线索二叉树**。
|
||
|
||
7.8 哈弗曼树
|
||
|
||
定义
|
||
|
||
在许多应用中经常将树中的结点赋予一个有某种意义的数值,称此数值为该结点的**权**。
|
||
|
||
从根结点到该结点之间的路径长度与该结点上权的乘积称为该结点的**带权路径长度**(WPL)。树中所有叶子结点的带权路径长度之和称为该**树的带权路径长度**。
|
||
|
||
在n0个带权叶子结点构成的所有二叉树中,带权路径长度WPL最小的二叉树称为**哈弗曼树**或最优二叉树。
|
||
|
||
## 8 图
|
||
|
||
定义
|
||
|
||
**图**(graph)G由两个集合V(vertex)和E(edge)组成,记为G=(V,E),其中V是顶点的有限集合,记为V(G),E是连接两个不同定点(顶点对)得边的有限集合,记为E(G)
|
||
|
||
**有向图**:表示边的顶点对(或序偶)是有序的(<i,j>和<j,i>是两条不同的边)
|
||
|
||
**无向图**(<i,j>和<j,i>是两条不同的边)
|
||
|
||
基本术语
|
||
|
||
1. 端点和邻接点
|
||
|
||
在一个无向图中,若存在一条边(i,j),则称顶点i和顶点j为该边的两个**端点**,并称它们互为**邻接点**,即顶点i是顶点j的一个邻接点,顶点j也是顶点i的一个邻接点,边(i,j)和顶点i、j关联。关联于相同两个端点的两条或者两条以上的边称为**多重边**,在数据结构中讨论的图都是指没有多重边的图。
|
||
|
||
在一个有向图中,若存在一条有向边<i,j>(也称为弧),则称此边是顶点i的一条出边,同时也是顶点j的一条入边,i为此边的**起始端点**(简称为起点),j为此边的**终止端点**(简称终点),顶点j是顶点i的**出边邻接点**,顶点i是顶点j的**入边邻接点**。
|
||
|
||
2.顶点的度、入度和出度
|
||
|
||
在无向图中,一个顶点所关联的边的数目称为该**顶点的度**(degree)。在有向图中,顶点的度又分为入度和出度,以顶点j为终点的边数目,称为该顶点的**入度**(indegree)。以顶点i为起点的边数目,称为该顶点的**出度**(outdegree)。一个顶点的入度与出度的和为该**顶点的度**。
|
||
|
||
一个图中所有顶点的度之和等于边数的两倍。因为图中的每条边分别作为两个邻接点的度各计一次。
|
||
|
||
3.完全图
|
||
|
||
若无向图中的每两个顶点之间都存在着一条边,有向图中的每两个顶点之间都存在着方向相反的两条边,则称此图为**完全图**。
|
||
|
||
无向完全图包含有n(n-1)/2条边,有向完全图包含有n(n- 1)条边。
|
||
|
||
4.稠密图和稀疏图
|
||
|
||
当一个图接近完全图时,称为**稠密图**。相反,当一个图含有较少的边数(如e<nlog₂n)时,则称为**稀疏图**。
|
||
|
||
5.子图
|
||
|
||
设有两个图G=(V,E)和G'=(V',E'),若V'是V的子集,即V'⊆V,且E'是E的子集,即E'⊆E,则称G'是G的**子图**。
|
||
|
||
说明:图G的子图一定是个图。
|
||
|
||
6.路径和路径长度
|
||
|
||
在一个图G=(V, E)中,从顶点i到顶点j的一条**路径**是一个顶点序列(i, i1, i2, ···, im, j)。若此图G是无向图,则边(i,i1), (i1,i2), ···, (i(m-1), im), (im, j)属于E(G);若此图是有向图,则<i,i1>, <i1,i2>, ···, <i(m-1),im>, <im,j>属于E(G)。**路径长度**是指条路径上经过的边的数目。若一条路径上除开始点和结束点可以相同以外,其余顶点均不相同,则称此路径为**简单路径**。
|
||
|
||
7.回路或环
|
||
|
||
若一条路径上的开始点与结束点为同一个顶点,则此路径被称为**回路**或**环**。开始点与结束点相同的简单路径被称为**简单回路**或**简单环**。
|
||
|
||
8.连通、连通图和连通分量
|
||
|
||
在无向图G中,若从顶点i到顶点j有路径,则称顶点i和顶点j是**连通的**。若图G中的任意两个顶点都是连通的,则称G为**连通图**,否则称为**非连通图**。无向图G中的极大连通子图称为G的**连通分量**。显然,连通图的连通分量只有一个(即本身),而非连通图有多个连通分量。
|
||
|
||
9.强连通图和强连通分量
|
||
|
||
在有向图G中,若从顶点i到顶点j有路径,则称从顶点i到顶点j是**连通的**。若图G中的任意两个顶点i和j都连通,即从顶点i到顶点j和从顶点j到顶点i都存在路径,则称图G是**强连通图**。有向图G中的极大强连通子图称为G的**强连通分量**。显然强连通图只有一个强连通分量(即本身),非强连通图有多个强连通分量。
|
||
|
||
在一个非强连通图中找强连通分量的方法如下:
|
||
|
||
(1)在图中找有向环。
|
||
|
||
(2)扩展该有向环:如果某个顶点到该环中的任一顶点有路径,并且该环中的任一项点到这个顶点也有路径,则加入这个顶点。
|
||
|
||
10.权和网
|
||
|
||
图中每一条边都可以附有一个对应的数值,这种与边相关的数值称为权。权可以表示从一个顶点到另一个顶点的距离或花费时间的带价。边上带有权的称为**带权图**,也称作**网**。
|
||
|
||
存储结构
|
||
|
||
邻接矩阵(适合存储边的数目较多的稠密图)
|
||
|
||
图的**邻接矩阵**是采用邻接矩阵数组表示顶点之间相邻关系的存储结构。
|
||
|
||
特点
|
||
|
||
(1)图的邻接矩阵表示是唯一的。
|
||
|
||
(2)对于含有n个顶点的图,当采用邻接矩阵存储时,无论是有向图还是无向图,也无论边的数目是多少,其存储空间都为O(n^2),所以邻接矩阵适合于存储边的数目较多的稠密图。
|
||
|
||
(3)无向图的邻接矩阵数组一定是一个对称矩阵,因此可以采用压缩存储的思想,在存放邻接矩阵数组时只需存放上(或下)三角部分的元素即可。
|
||
|
||
(4)对于无向图,邻接矩阵数组的第i行或第i列非零元素、非∞元素的个数正好是顶点i的度。
|
||
|
||
(5)对于有向图,邻接矩阵数组的第i行(或第i列)非零元素、非∞元素的个数正好是顶点i的出度(或入度)。
|
||
|
||
(6)在邻接矩阵中,判断图中两个顶点之间是否有边或者求两个顶点之间边的权的执行时间为O(1)。所以在需要提取边权值的算法中通常采用邻接矩阵存储结构。
|
||
|
||
邻接表
|
||
|
||
图的**邻接表**是一种顺式与链式存储相结合的存储方法。
|
||
|
||
**逆邻接表**:在有向图的邻接表中对每个顶点链接的是指向该顶点的边。
|
||
|
||
特点
|
||
|
||
(1)邻接表的表示不唯一,这是因为在每个顶点对应的单链表中各边结点的链接次序可以是任意的,取决于建立邻接表的算法以及边的输入次序。
|
||
|
||
(2)对于有n个顶点和e条边的无向图,其邻接表有n个头结点和2e个边结点;对于有n个顶点和e条边的有向图,其邻接表有n个头结点和e个边结点。显然,对于边数目较少的稀疏图,邻接表比邻接矩阵更节省存储空间。
|
||
|
||
(3)对于无向图,邻接表中顶点i对应的第i个单链表的边结点数目正好是顶点i的度。
|
||
|
||
(4)对于有向图,邻接表中顶点i对应的第i个单链表的边结点数目仅仅是顶点i的出度。顶点i的入度为邻接表中所有adjvex域值为i的边结点数目。
|
||
|
||
(5)在邻接表中,查找顶点i关联的所有边是非常快速的,所以在需要提取某个顶点的所有邻接点的算法中通常采用邻接表存储结构。
|
||
|
||
其他存储方法
|
||
|
||
十字链表
|
||
|
||
**十字链表**是有向图的另外一种存储结构,它是邻接表和逆邻接表的结合。
|
||
|
||
邻接多重表
|
||
|
||
邻接多重表是无向图的另外一种存储结构,与十字链表类似。
|
||
|
||
基本运算算法
|
||
|
||
创建图的运算算法
|
||
|
||
输出图的运算算法
|
||
|
||
销毁图的运算算法
|
||
|
||
图的遍历
|
||
|
||
**图的遍历**:从给定图中任意指定的顶点(称为初始点)出发,按照某种搜索方法沿着图的边访问图中的所有顶点,使每个顶点仅被访问一次,这个过程称为图的遍历。
|
||
|
||
深度优先遍历 DFS(Depth First Search)
|
||
|
||
深度优先遍历的过程是从图中的某个初始点v出发, 首先访问初始点v,然后选择一个与定点v相邻且没被访问过的顶点w,以w为初始顶点,再从它出发进行深度优先遍历,直到图中与定点v邻接的所有定点都被访问过,显然这个遍历过程是一个递归过程。
|
||
|
||
广度优先遍历 BFS(Breadth First Search)
|
||
|
||
广度优先遍历的过程是首先访问初始点v,接着访问顶点v的所有未被访问过的邻接点v1, v2, ···, vt,然后再按照v1, v2, ···, vt的次序访问每一个顶点的所有未被访问过的邻接点,依此类推,直到图中所有和初始点v有路径相通的顶点都被访问过为止。
|
||
|
||
生成树与最小生成树
|
||
|
||
一个连通图的**生成树**是一个极小连通子图,其中含有图的全部顶点,和构成一条树的(n-1)条边。
|
||
|
||
对于一个带权(假设每条边上的权均为大于零的实数)连通无向图G中的不同生成树,其每棵树的所有边上的权值之和也可能不同;图的所有生成树中具有边上的权值之和最小的树称为图的**最小生成树**。
|
||
|
||
**深度优先生成树**:由深度优先遍历得到的生成树
|
||
|
||
**广度优先生成树**:由广度优先遍历得到的生成树
|
||
|
||
对于非连通图,每个连通分量中的顶点集和遍历时走过的边一起构成一棵生成树,各连通分量的生成树组成非连通图的**生成森林**。
|
||
|
||
算法
|
||
|
||
普里姆(Prim)算法
|
||
|
||
图采用邻接矩阵更合适
|
||
|
||
时间复杂度为O(n²)
|
||
|
||
适合稠密图求最小生成树
|
||
|
||
克鲁斯卡尔(Kruskal)算法
|
||
|
||
图采用邻接矩阵更合适
|
||
|
||
对于无向连通图,时间复杂度为O(elog₂e) (e条边)
|
||
|
||
适合稀疏图求最小生成树
|
||
|
||
最短路径
|
||
|
||
迪克斯特拉(Dijkstra)算法 ——从一个顶点到其余各顶点的最短路径
|
||
|
||
图采用邻接矩阵更合适
|
||
|
||
用一个一维数组dist存放最短路径长度,用一个一维数组path存放(n-1)条最短路径
|
||
|
||
时间复杂度为O(n²)
|
||
|
||
不适合含有负权值的带权图求单源最短路径。
|
||
|
||
不能求源点到图中其他顶点的最长路径
|
||
|
||
弗洛伊德(Floyd)算法 ——每对顶点间的最短路径
|
||
|
||
用于求两顶点之间的最短路径
|
||
|
||
时间复杂度为O(n³) (不考虑路径输出)
|
||
|
||
拓扑排序
|
||
|
||
在一个有向图中找一个拓扑序列的过程称为**拓扑排序**。
|
||
|
||
用顶点表示活动,用边表示活动之间优先关系的有向图称为**顶点表示活动的网**(AOV网,activity on vertex)
|
||
|
||
AOE网与关键路径
|
||
|
||
以顶点表示事件,有向边表示活动,边e的权c(e)表示完成活动e所需的时间,或者说活动e的持续时间。图中入度为0的顶点表示工程的**开始事件**,出度为0的顶点表示工程的**结束事件**,称这样的有向图为**边表示活动的网**(AOE网,activity on edge network)。
|
||
|
||
**源点**:入度为0的点
|
||
|
||
**汇点**:出度为0的点
|
||
|
||
关键路径:在AOE网中,从源点到汇点的所有路径中具有最大路径长度的路径称为**关键路径**。
|
||
|
||
完成整个工程的最短时间就是AOE网中关键路径的长度,或者说是AOE中一条关键路径上各活动持续时间的总和,把关键路径上的活动称为**关键活动**。
|
||
|
||
关键活动不存在富余的时间,而非关键活动可能存在富余的时间。通常一个AOE网可能存在多条关键路径,但它们的长度是相同的。因此,只要找出AOE网中的所有关键活动也就找到了全部关键路径。
|
||
|
||
## 9 查找
|
||
|
||
基本概念
|
||
|
||
**查找**:给定一个值k,在含有n个元素的表中找出关键字等于k的元素。若找到,则查找成功,返回该元素的信息或该元素在表中的位置;否则查找失败,返回相关的指示信息。
|
||
|
||
**动态查找表**:在查找的同时对表做修改操作(如插入和删除),则相应的查找表称为动态查找表
|
||
|
||
**静态查找表**:在查找中不涉及表的修改操作,则相应的查找表称为静态查找表
|
||
|
||
**内查找**:整个查找过程都在内存中进行
|
||
|
||
**外查找**:查找过程中需要访问外存
|
||
|
||
**平均查找长度**:在查找运算中时间主要花费在关键字的查找比较上,把平均需要和给定值k进行比较的关键字次数称为平均查找长度(ASL,Average Search Length)。
|
||
|
||
线性表的查找
|
||
|
||
**顺序查找**:是一种最简单的查找方法。它的基本思路是从表的一端向另一端逐个将元素的关键字和给定值k比较。
|
||
|
||
**折半查找**(**二分查找**):是一种效率较高的查找方法。
|
||
|
||
折半查找要求线性表是有序表,即表中的元素按关键字有序。
|
||
|
||
判定树(比较树)
|
||
|
||
**分块查找**:性能介于顺序查找和折半查找之间的查找方法。
|
||
|
||
索引存储结构
|
||
|
||
树表的查找
|
||
|
||
二叉排序树(二叉搜索树)
|
||
|
||
二叉排序树的插入和创建
|
||
|
||
二叉排序树的查找
|
||
|
||
二叉排序树的删除
|
||
|
||
平衡二叉树
|
||
|
||
平衡二叉树中插入结点的过程
|
||
|
||
LL型调整
|
||
|
||
RR型调整
|
||
|
||
LR型调整
|
||
|
||
平衡二叉树中删除结点的过程
|
||
|
||
平衡二叉树的查找
|
||
|
||
B-树
|
||
|
||
B+树
|
||
|
||
哈希表的查找
|
||
|
||
## 10 内排序
|
||
|
||
基本概念
|
||
|
||
**排序**:整理表中的元素,使之按关键字递增或递减有序排列。
|
||
|
||
如果待排序的表中存在有多个关键字相同的元素,经过排序后这些具有相同关键字的元素之间的相对次序保持不变,则称这种排序方法是**稳定的**。反之,若具有相同关键字的元素之间的相对次序发生变化,则称这种排序是**不稳定的**。
|
||
|
||
**内排序**:在排序过程中,整个表都放在内存中处理,排序时不涉及数据的内、外存交换
|
||
|
||
**外查找**:在排序过程中要进行数据的内、外存交换
|
||
|
||
有序区
|
||
|
||
无序区
|
||
|
||
插入排序
|
||
|
||
直接插入排序
|
||
|
||
折半插入排序
|
||
|
||
希尔排序
|
||
|
||
交换排序
|
||
|
||
冒泡排序
|
||
|
||
快速排序
|
||
|
||
选择排序
|
||
|
||
简单选择排序
|
||
|
||
堆排序
|
||
|
||
归并排序
|
||
|
||
归并排序
|
||
|
||
二路归并排序
|
||
|
||
基数排序
|
||
|
||
最低位优先 LSD
|
||
|
||
最高为优先 MSD
|