数据结构复习
物理结构/逻辑结构理解
物理结构:即为存储结构,指的是数据结构再计算机存储的映像(成为节点或者元素)。
逻辑结构:指的是数据元素之间的逻辑关系的总称。
顺序存储结构的特点
逻辑关系上相邻的两个元素在物理位置也相邻,只要确定起始位置,线性表中的的任一元素都可以随机访问
随机存储结构
随机存储结构是一种允许数据在任何位置被访问的存储方式
在链表中插入一个结点,删除一个节点的操作
伪代码如下:
插入到链表的头部
// 插入新结点到链表的头部
Node* InsertAtHead(Node* head, Node* newNode) {
newNode->next = head; // 将新结点的 next 指向原头结点
head = newNode; // 更新头结点为新结点
return head;
}
插入到链表的尾部
// 插入新结点到链表的尾部
Node* InsertAtTail(Node* head, Node* newNode) {
if (head == nullptr) { // 如果链表为空
head = newNode; // 将新结点作为头结点
return head;
}
Node* current = head;
while (current->next != nullptr) { // 遍历到链表的最后一个结点
current = current->next;
}
current->next = newNode; // 将新结点连接到链表的末尾
return head;
}
删除头节点
// 删除链表的头结点
Node* DeleteAtHead(Node* head) {
if (head == nullptr) {
cout << "List is empty" << endl;
return nullptr;
}
Node* temp = head;
head = head->next; // 将头结点更新为下一个结点
delete temp; // 删除原头结点
return head;
}
栈的顺序结构
后进先出(LIFO)
链栈的实现(伪代码)
压栈
// 压栈操作
Node* Push(Node* top, int value) {
Node* newNode = new Node; // 创建一个新的结点
newNode->data = value; // 将数据存入新结点
newNode->next = top; // 将新结点的 next 指向原栈顶
top = newNode; // 更新栈顶为新结点
return top; // 返回新的栈顶指针
}
弹栈
// 弹栈操作
Node* Pop(Node* top, int& value) {
if (top == nullptr) {
cout << "Stack is empty, cannot pop." <<endl;
return top; // 如果栈为空,返回原栈顶指针
}
value = top->data; // 获取栈顶元素的值
Node* temp = top; // 保存栈顶结点
top = top->next; // 更新栈顶为下一个结点
delete temp; // 删除原栈顶结点
return top; // 返回新的栈顶指针
}
队列的顺序结构实现和链表结构实现
队列(Queue)是一种先进先出(FIFO)的数据结构
矩阵的压缩存储
**
主要有两种情形:
(1)特殊矩阵:对称矩阵,上/下三角矩阵,带状矩阵(对角阵)
采用一维数组或小规模的二维数组存储有用的非零元素和少量的零元素。
(2)稀疏矩阵:零元素多且非零元素相对较少的矩阵,
顺序存储结构实现称为三元组表:1.选择取,顺序存转置算法2.顺序取,直接存算法;3.链式存储结构实现称为十字链表(正交链表)
**
第六章二叉树,重点
6.1 二叉树的定义
二叉树是n个有限元素的集合,该集合由一一个称为根的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成,是有序树。
6.2 特殊的二叉树
1、满二叉树:如果一棵二叉树只有度为0的结点和度为2的结点,并且度为0的结点在同一层上,则这棵二叉树为满二叉树。
2、完全二叉树:深度为k,有n个结点的二叉树当且仅当其每一个结点都与深度为k的满二叉树中编号从1到n的结点- --对应时, 称为完全二叉树。
6.3 满二叉树以及完全二叉树的特性
(1)叶结点只可能在层次最大的两层上出现
(2)对任一结点,若右分支的子孙最大层次为L,则其左分支必为L或L+1
(3)满二叉树是完全二叉树的特例
6.4 二叉树的性质
(1)在二叉树的第i层,结点个数至多为2的i-1次方
(2)深度为k的二叉树至多有2的k次方-1个结点
(3)具有n个结点的完全二叉树深度为(log2 n ) +1
(4)如果对一棵有n个结点的完全二叉树(深度为log2 n +1)的结点按层次编号(上到下,左到右),对任一-结点有:a.i=1,则i是根,无双亲;若i>1,则双亲编号为(i/2)
b.若2i+1>n-1, 则i无左孩子; 2i+1< =n-1,左孩子编号(2i+1)
c.若2i+2>n-1,则i无右孩子,否则右孩子编号(2i+2)
(5)若二叉树终端结点数为n0(即叶结点数为n0),度为2的结点数为n2,则n0= n2+1
6.5 二叉树的存储结构
顺序存储结构:用一个数组存储结点,这样存储顺序不需要另外的附加信息就能表现一棵
树结点之间的关系
链式存储结构:用链表来表示一-棵二叉树,即用链表来指示元素之间的逻辑关系。通常有
两种存储形式,可以进一步充分利用内存,
6.6 二叉树的遍历
按一定的顺序访问二叉树中的所有结点
6.7 要重点复习实验中的内容
6.8 哈夫曼树的相关内容
哈夫曼树是一类带权路径长度最短的二叉树。权为l,w…wn的n个叶结点的所有二叉树
中,带权路径长度WPL最小的二叉树称为哈夫曼树。
构造步骤:
(1)根据n个权值构造n棵二叉树的森林
(2)在森林中选出两棵结点权值最小的二叉树,作为左右子树合并成为新的二叉树,权值
为原来的权值之和
(3)删除刚刚合并的两棵二叉树,加入新的二叉树
(4)重复2, 3,直到只含一棵树
堆
堆的特点
- 结构性:堆是一个完全二叉树,这意味着除了最后一层外,每一层都是完全填满的,并且最后一层的所有节点都尽可能地向左集中。
- 堆属性:
- 最大堆:任何一个父节点的值都大于或等于其所有子节点的值。根节点是堆中的最大值。
- 最小堆:任何一个父节点的值都小于或等于其所有子节点的值。根节点是堆中的最小值。
构建堆的过程
- 从非叶子节点开始:最后一个非叶子节点是最后一个节点的父节点,可以通过数组的索引来定位,位置为 n/2−1n/2 - 1n/2−1,其中 nnn 是数组的长度。
- 下沉调整(Max-Heapify 或 Min-Heapify):对每个非叶子节点执行下沉操作,从最后一个非叶子节点开始,直到根节点。下沉操作确保节点的值大于(最大堆)或小于(最小堆)其子节点的值。如果不是,则将节点与其最大(或最小)的子节点交换,并继续下沉。
第七章 图,重点
7.1****图中的相关概念,这个概念不会直接考,但概念肯定融合在具体的题目里
定义:图G由顶点集V和边集E组成,记为G=(V,E),其中V(G)表示图G中顶点的有限非空集;E(G)表示图G中顶点之间的关系(边)的集合。
注意:线性表可以是空表,树可以是空树,图不可以是空图,图可以没有边,但是至少要有一个顶点。
**1.****有向图:**边有方向
**2.****无向图:**边没有方向
**3.****混合图:**既有有向边又有无向边的图,可转换成有向图。
**4.****简单图:**无向图中不存在顶点到自身的边,任意两不同顶点之间没有平行的两条边,称为简单无向图;有向图中不存在顶点到自身的弧,任意两不同顶点之间没有同方向的两条弧,称为简单有向图;统称简单图,没有特别声明,图均指简单图。
**5.邻接、依附或关联:****无向图:**若两个顶点之间有边,则称为这两个点邻接。这个边也依附于这两个点,或称与边相关联的两个顶点是这两个顶点。有向图:存在弧<v,w>则称顶点v邻接到w,w邻接自v,这个弧也依附于这两个点,或称与弧相关联的两个顶点是这两个顶点,通常简称w是v的邻接点。
(线性表中数据元素仅有线性关系,树中节点有层次关系,图中任意两个点都有可能有关系。)
**6.****完全图:**任意两个顶点之间都存在边。(有向完全图则为任意两个顶点之间存在互相指向的边。)
含n个顶点的完全图有 1/2 ×n(n-1)条边,有向完全图则为它的2倍。
**7.****网或赋权图:**无向图或有向图的边或弧上还带有一个表示某种物理量的权值,则称其为网,又称赋权图。
**8.****稀疏图和稠密图:**边或弧数都很少的无向图或有向图称为稀疏图,反之则为稠密图。
**9.**顶点的度,入度和出度:
**10.**子图:
**11.**路径,简单路径和回路:
12**:连通和可达:**
13**:连通图和强连通图:**无向图中任意两个不同顶点都是连通的称它为连通图,否则为非连通图。有向图中任意两个不同顶点都是可达的称之为强连通图或简称连通图,否则为非强连通图或非连通图
14**:连通分量和强连通分量:**无向图的极大连通子图称为连通分量有向图的极大强连通子图称为强连通分量或连通分量。极大指该子图包括了所有连通的顶点以及这些顶点相关联的所有边。
**15.****树和有向树:**连通且无回路的的无向图称为无向树,简称树。含n个顶点的树有n-1条边。在忽略弧方向后,连通且无回路的有向树称为有向树。含n个顶点的有向树有n-1条弧。实际中指的有向树在选定一个顶点作为根节点后,弧的方向都与从根节点指向叶结点的方向一致或全部相反。
**16.**生成树、生成森林:由n个顶点构成的连通无向图的任何一个含n个顶点的极小连通子图称为该图的生成树。对于非连通无向图,由连通子图课得到生成子树,非连通无向图的所有连通分量得到的生成子树构成该树的生成森林
7.2 图的两种存储结构(重点!!!!)
1.邻接矩阵:用两个数组,一个数组保存顶点集,一个数组保存边集。
2.邻接表:数组与链表相结合的存储方法。
7.3 建立在图的存储结构上的图的两种遍历
1.深度优先遍历(DFS):从图中某个顶点v出发,访问此顶点,然后从v的未被访问的邻接点出发深度优先遍历图,直至图中所有和v有路径相通的顶点都被访问到。(类似于先序遍历)
2.广度优先遍历(BFS):类似于树的层次遍历。**
7.4无向网络的两种最小生成树的方法
(基本上都可以概括为贪心算法)
1.普里姆(Prim):从顶点开始搜索权值最小的边
2.克鲁斯卡尔(Kruskal):直接搜索权值最小的边组成森林
7.5** 单源点最短路径构造方法Dijkstra
1.迪杰斯特拉算法(Dijkstra):把图中的顶点集合V分成两组,第一组为已求出最短路径的顶点集合S(初始时S中只有源节点,以后每求得一条最短路径,就将它对应的顶点加入到集合S中,直到全部顶点都加入到S中);第二组是未确定最短路径的顶点集合U。
算法步骤:
(1)初始化时,S只含有源节点;
(2)从U中选取一个距离v最小的顶点k加入S中(该选定的距离就是v到k的最短路径长度);
(3)以k为新考虑的中间点,修改U中各顶点的距离;若从源节点v到顶点u的距离(经过顶点k)比原来距离(不经过顶点k)短,则修改顶点u的距离值,修改后的距离值是顶点k的距离加上k到u的距离;
(4)重复步骤(2)和(3),直到终点在S中。
查找,二分查找
9.1 查找的概念和相关定义
查找是根据给定的某个值,在查找表中确定一个其关键字等于给定值的数据元素。
查找表是由同一类型的数据元素(或记录)构成的集合。由于集合中的数据元素之间存在着完全松散的关系,因此查找表是一种非常灵便的数据结构。
**注意:**从逻辑上来说,查找表中的数据元素之间没有本质的关系。查找表可以不是线性表,树结构和图结构中的任意一种。
查找的操作分为两种:静态查找和动态查找。
1.静态查找:
1.1. 查询某个特定的数据元素是否在查找表中;
1.2. 检索某个特定的数据元素的各种属性。
2.动态查找:
2.1. 在查找表中插入一个数据元素;
2.2. 从查找表中删去某个数据元素。
查找表中的基本术语
**关键字:**数据元素中某个数据项的值,用以标识一个数据元素。
**主关键字:**可以唯一的标识一个数据元素的关键字。
**次关键字:**可以识别不止一个数据元素的关键字。
查找的结果分为两种:成功和失败。
1.查找成功:找到满足条件的数据元素,作为结果,可返回数据元素在查找表中的位置,也可以返回该数据元素的具体信息;
2.查找失败:无法找到满足条件的数据元素,作为结果,应该报告一些错误信息,如失败标志、失败位置。
9.2 二分查找的条件和算法实现
查找前要求记录按关键字值排序(升序或降序),即是有序表,且用数组作为存储结构(不是用链表作存储结构)。
哈希查找,重点,什么是开散列,什么是必散列;重点;
哈希(散列)查找的概念,两种解决地址冲突的方法以及相关概念和课堂讲解的知识点
1)散列函数:p = H(key);p表示散列地址,key表示关键字,函数H()表示关键字与存储位置之间的某种关系。
2)散列表:一维数组,数组下标表示散列地址。
3)冲突、同义词:不同的关键字可能会求得同一个散列地址,这样的情况称为冲突,造成这种情况的关键字称为同义词。
散列查找主要研究两个问题:
\1. 构造散列函数;
\2. 处理冲突。
开放地址法
基本思想:当一个记录的散列地址发生冲突时,以初始散列地址H0为基础,采取合适的方法计算另一个地址Hi,若另一个地址仍是冲突,继续计算,直至找到空地址为止。寻找新地址的过程称为“探测”。
Hi = (H(key) + di) % m
链地址法
把具有相同散列地址的记录放在同一个单链表中,称为同义词链表。
m个散列地址就有m个单链表,同时将各链表的头指针放入一个一维数组中统一管理。
二叉排序树的概念
二叉排序树可用递归方式定义如下:
二叉排序树或是一棵空树,或是具有下列性质的二叉树:对于根结点,若左子树不空,则左子树上所有结点的值小于根结点的值;若右子树不空,则右子树上所有结点的值大于或等于根结点的值;根结点的左右子树也分别是二叉排序树
查找操作
在二叉排序树中进行查找操作的步骤如下:
-
从根节点开始:将待查找的键与根节点的键进行比较。
-
向左或向右移动:
- 如果待查找的键小于当前节点的键,则移动到左子节点。
- 如果待查找的键大于当前节点的键,则移动到右子节点。
- 如果等于当前节点的键,则查找成功,返回当前节点或节点的值。
-
重复:重复上述过程,直至找到键或遍历到一个叶子节点的空链接(即找不到相应的键)。
二叉平衡树的概念
二叉树中任一结点的左右子树的高度相差不超过1的二叉树,称为平衡二叉树
(balanced binary tree,简称BBT树)。即对任结点,设其左子树的高度为L,右子树的高度为H,则都有|L -H|≤1。
ASL(平均查找长度,Average Search Length)
ASL(平均查找长度,Average Search Length)是衡量查找效率的一种重要指标,尤其是在二叉搜索树(BST)或其他类似数据结构中。ASL计算的是在特定树结构中进行查找操作所需的平均比较次数。
对于二叉搜索树,ASL 可以按照以下步骤来计算:
步骤1:计算每个节点的深度
节点的深度是从根节点到该节点的边的数量。例如,根节点的深度为0,根节点的直接子节点深度为1,以此类推。
步骤2:确定查找成功的平均查找长度(ASL成功)
查找成功的平均查找长度计算每个节点被查找时的平均深度。公式为:
这里,“+1”是因为查找次数从1开始计数(即根节点查找次数为1)。如果每个节点被查找的概率相同,这个公式简化为:
步骤3:确定查找失败的平均查找长度(ASL失败)
查找失败的平均查找长度涉及到每个可能的失败查找点,这些点通常是指向空的子节点链接。为了计算查找失败的ASL,我们需要知道每个空子节点链接的深度,然后应用与查找成功类似的公式。
如果每个空链接被访问的概率相同,这个公式简化为:
三大类排序,六种排序方法
三大类:
1.插入类:直接插入排序,希尔排序,
2.交换类:冒泡排序,快速排序
3.选择类:简单选择排序,堆排序
各种排序方法的实现,时间相应,稳定性的比较以及改进的着眼点
1**、直接插入排序**
整个排序过程为n-1趟插入,即先将序列中第1个记录看成是一个有序子序列,然后从第2个记录起逐个进行插入,直至整个序列变成按关键字非递减有序序列为止。
2**、希尔排序**
先取一个正整数d1<n,把所有相隔d1的记录放到一组组内进行直接插入排序;然后取d2<d1,重复上述分组和排序操作;直至di=1,即所有记录放进一个组中排序为止。
3**、冒泡排序**
冒泡排序就是把小的元素往前调或者把大的元素往后调。比较是相邻的两个元素比较,交换也发生在这两个元素之间。
**4.**快速排序
通过一趟排序,将待排序记录分割成独立的两部分,其中一部分记录的关键字均比另一部分记录的关键字小,则可分别对这两部分记录进行排序以达到整个序列有序。
★快速排序实际上是对冒泡排序的一-种改进。
★改进的着眼点:在冒泡排序中,记录的比较和移动是在相邻单元中进行的,记录每次交换只能上移或下移一个单元,因而总的比较次数和移动次数较多。
简单(直接)选择排序
首先通过n-1次关键字比较,从n个记录中找出关键字最小的记录,将它与第一个记录交换
再通过n-2次关键字比较,从剩余的n-1个记录中找出关键字次小的记录,将它与第二个记录交换
重复上述操作,共进行n-1趟排序后,排序结束
6**、堆排序**
将无序序列建成一个堆,得到关键字最小(或最大)的记录;得到堆顶的最小(或最大)值后,使剩余n-1个元素的序列重又建成一个堆,则得到n个元素的次小值(或次大值)。如此重复执行,便得到一个有序序列,这个过程称之为堆排序(降序)(或升序)。
算法的特性
稳定性的重要性
稳定性在多关键字排序或复合数据结构的排序中尤为重要。例如,如果你首先根据名字对一组人进行排序,然后根据年龄对这些人进行排序,一个稳定的排序算法可以保证在年龄相同的情况下,人们的相对顺序(即按名字排序的结果)被保留。
稳定的排序算法
下面是一些常见的稳定排序算法:
- 冒泡排序:通过重复交换相邻逆序的元素,逐渐将每个元素移至其正确位置。
- 插入排序:构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。
- 归并排序:将数组分成两半,分别排序,然后合并两个有序部分。
- 计数排序:使用一个额外的数组,计算每个值的出现次数,然后根据计数数组输出排序结果。
- 基数排序:按照低位先排序,然后收集;再按高位排序,然后再收集;依此类推,从最低位到最高位进行排序。
- 鸡尾酒排序:冒泡排序的变种,从低到高然后从高到低进行来回排序,有助于减少小值在数组后部的“乌龟”问题。
不稳定的排序算法
下面是一些常见的不稳定排序算法:
- 选择排序:反复找出剩余未排序元素中的最小(大)元素,放到已排序的序列的末尾。
- 希尔排序:基于插入排序的一种算法,但是加入了间隔序列的概念以改进性能,特别是大列表的排序。
- 快速排序:从数列中挑出一个元素,作为“基准”(pivot),重新排序数列,所有元素比基准值小的摆放在基准前面,所有元素比基准值大的摆在基准的后面。再递归地对小于基准值元素的子数列和大于基准值元素的子数列进行排序。
- 堆排序:利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或大于)它的父节点。
选择合适的排序算法
选择使用哪种排序算法通常基于数据的大小、数据的结构、预期的效率以及是否需要稳定性等因素。对于需要保证数据原有顺序的场景,选择稳定的排序算法尤为重要。对于追求速度和处理大数据量的情况,可能会优先选择非稳定的高效算法,如快速排序或堆排序。
要正确理解数据结构 D,R)中的D和R
D = Data(数据): 在很多编程和数据结构的上下文中,“D”常常代表“数据”(Data)。这可能是指数据本身,或是与数据相关的操作、存储、处理等方面。
R = Rules(规则) 或 Relationships(关系): “R” 可以代表“规则”(Rules),特别是在设计数据模型或算法时,或者是“关系”(Relationships),这在关系数据库或图论中尤为重要。
值大的摆在基准的后面。再递归地对小于基准值元素的子数列和大于基准值元素的子数列进行排序。
4. 堆排序:利用堆这种数据结构所设计的一种排序算法。堆积是一个近似完全二叉树的结构,并同时满足堆积的性质:即子节点的键值或索引总是小于(或大于)它的父节点。
选择合适的排序算法
选择使用哪种排序算法通常基于数据的大小、数据的结构、预期的效率以及是否需要稳定性等因素。对于需要保证数据原有顺序的场景,选择稳定的排序算法尤为重要。对于追求速度和处理大数据量的情况,可能会优先选择非稳定的高效算法,如快速排序或堆排序。
要正确理解数据结构 D,R)中的D和R
D = Data(数据): 在很多编程和数据结构的上下文中,“D”常常代表“数据”(Data)。这可能是指数据本身,或是与数据相关的操作、存储、处理等方面。
R = Rules(规则) 或 Relationships(关系): “R” 可以代表“规则”(Rules),特别是在设计数据模型或算法时,或者是“关系”(Relationships),这在关系数据库或图论中尤为重要。