![](https://img-blog.csdnimg.cn/9aadec0176a4465fbc04a87d0c6dd4cf.png?x-oss-process=image/resize,m_fixed,h_224,w_224)
数据结构
文章平均质量分 81
包括算法分析、表、栈、队列、树、散列、优先队列(堆)、排序、不相交集类、图论算法、算法设计技巧、摊还分析、高级数据结构及其实现。
zhugenmi
励志做一个资深码农
展开
-
【算法设计技巧】动态规划
任何数学递推公式都可以直接翻译成递归算法,但基本实现是:编译器常常不能正确对待递归算法,结果导致低效的程序。当怀疑很可能是这种情况时,我们必须再给编译器提供一些帮助,将递归算法重新写成非递归算法,让后者把那些子问题的答案系统地记录在一个表内。一种利用这种方法的技巧叫作动态规划(dynamic programming)。...原创 2023-02-27 08:00:00 · 116 阅读 · 0 评论 -
【算法设计技巧】分治算法
用于设计算法的另一种常用技巧为分治算法。传统上,在其代码中至少含有两个递归调用的例程叫作分治算法,且一般认为子问题是不相交的(即基本上不重叠)。例如,问题的一个O(NlogN)和,它们分别有O(NlogN)的最坏情形以及平均时间的时间界。......原创 2023-02-25 19:33:29 · 1396 阅读 · 0 评论 -
【算法设计技巧】贪婪算法与回溯算法
贪婪算法分阶段地工作。在每个阶段,可以认为所作决定是好的,而不考虑将来的后果。一般地说,这意味着选择的是某个。当算法终止时,我们希望局部最优等于全局最优。如果是这样的话,那么算法就是正确的;否则,算法得到的是一个次最优解。在许多情况下,回溯算法(backtracking algorithm) 相当于穷举搜索的巧妙实现,但性能一般不理想。然而在某些情形下它相对于蛮力穷举搜索的工作量也是有显著的节省。......原创 2022-07-29 08:00:00 · 339 阅读 · 0 评论 -
【图论算法】深度优先搜索的应用
深度优先搜索depth-first search)是对先序遍历(preorder traversal)的推广。我们从某个顶点 v 开始处理 v,然后递归地遍历所有邻接到 v 的顶点。它的应用广泛,本文主要说明了无向图、双连通性、双连通以及割点的概念、找出图中割点的算法、欧拉回路、找出欧拉回路的算法、有向图、查找强分支以及相关示例来说明对该算法的应用。......原创 2022-07-30 08:00:00 · 2686 阅读 · 2 评论 -
【图论算法】最小生成树 (Prim 算法、Kruskal 算法)
一个无向图G的(minimumspanningtree)就是由该图的那些连接G的的边构成的树,即在最小生成树中边的条数为|V|,且其。最小生成树存在当且仅当G是连通的。虽然一个强壮的算法应该指出G不连通的情况,但是我们还是假设G是连通的。对于最小生成树问题,贪婪的做法是成立的,这里介绍两种算法,它们的区别在于最小(值的)边如何选取上。...原创 2022-07-27 08:00:00 · 835 阅读 · 0 评论 -
【图论算法】最短路径算法(无权最短路径、Dijkstra算法、带负边值的图、无圈图)
本篇博客将考察各种最短路径问题。包括无权最短路径、Dijkstra算法、带负边值的图、无圈图等的详细说明,包括对无圈图的关键路径分析,说明了动作节点图,事件节点图,最早完成时间,最晚完成时间和松弛时间的计算方法。最后通过一个无权最短路径的例子--词梯游戏来运用本章的算法。............原创 2022-07-22 10:28:23 · 4215 阅读 · 0 评论 -
【图论算法】图的表示与拓补排序
表示图的一种简单的方法是使用一个二维数组,称为邻接矩阵(adjacent matrix)表示法。对于每条边 (u, v),我们置 A[u][v] 为 true;否则,数组的对应元素就是 false。如果边有一个权,那么我们可以置 A[u][v] 等于该权,而使用一个很大或者很小的权作为标记表示不存在的边。虽然这种表示的优点是非常简单,但它的空间需求为 O(|V|^2^),如果图的边不是很多,那么这种表示法的代价就太大了。如果图是稠密的:|E|=O(|V|^2^),则邻接矩阵就是一种合...原创 2022-07-21 08:00:00 · 256 阅读 · 0 评论 -
不相交集类 (并查集)
不相交集类是的一种有效的数据结构,其实现简单,可以使用一个简单的数组,而且每种操作只需要常数时间。本章描述了等价关系、动态等价性问题、并查集基本数据结构、按大小求并和按高度求并算法以及路径压缩,附带实现代码...原创 2022-07-20 08:00:00 · 469 阅读 · 0 评论 -
【排序】桶式排序与基数排序
前面的章节证明了只使用比较的任意一般排序算法在最坏情形下都需要Ω(NlogN)时间,但在某些特殊情形下,以线性时间进行排序仍然是可能的。本章介绍了桶式排序,基数排序,包括字符串基数排序,计数基数排序,固定长度字符串的计数基数排序以及可变长字符串的基数排序。.........原创 2022-07-19 08:00:00 · 342 阅读 · 0 评论 -
【排序】快速排序
对于C++,快速排序(quicksort)历史上一直是实践中已知最快的泛型排序算法,其平均运行时间是O(NlogN)。原创 2022-07-18 08:00:00 · 780 阅读 · 0 评论 -
【排序】归并排序
归并排序(mergesort)以O(NlogN)最坏情形时间运行,而所使用的比较次数几乎是最优的。这个算法的基本操作是**合并两个已排序的表**。因为这两个表是已排序的,所以若将输出放到第3个表中,则该算法可以通过对输入的一趟排序来完成。基本的合并算法是取两个输入数组A和B,一个输出数组C,以及3个计数器Actr, Bctr, Cctr,它们初始置于对应数组的开始端。A[Actr] 和 B[Bctr] 中的较小者被复制到C中的下一个位置,相关的计数器向前推进一步。当两个输入表有一个用完的时候,则将另一个表中原创 2022-07-17 08:00:00 · 239 阅读 · 0 评论 -
【排序】插入排序、希尔排序和堆排序
最简单的排序算法之一,由N-1趟排序组成。对于p=1到N-1趟,插入排序保证从位置0到位置p上的元素为已排序状态。插入排序利用了这样的事实已知位置0到位置p-1上的元素已经处于排过序的状态。平均时间情形为O(N)。......原创 2022-07-16 08:00:00 · 220 阅读 · 0 评论 -
【优先队列(堆)】二项队列类模板的实现
左式堆和斜堆都在每次操作以O(logN)时间有效地支持合并、插入和deleteMin,但还有改进的余地,二叉堆以每次操作平均花费常数时间支持插入。二项队列支持所有这三种操作,每次操作的最坏情形运行时间为O(logN),但插入操作平均花费常数时间。一个二项队列(binomial queue)不是一棵堆序的树,而是一组堆序树,称为森林(forest)。堆序树中的每一棵都是有约束的形式,叫作二项树(binomial tree)。每一个高度上至多存在一棵二项树。高度为0的二项树是一棵单节点树,高度为k的二项树Bk通原创 2022-07-15 08:00:00 · 131 阅读 · 0 评论 -
【优先队列(堆)】左式堆类模板的实现
左式堆(leftist heap)像二叉堆那样也具有结构性和有序性。左式堆和二叉堆唯一的区别是:左式堆不是理想平衡的(perfectly balanced),而实际上是趋向于非常的不平衡。把任一节点X的零路径长 (null path length) npl (X) 定义为从X到一个不具有两个儿子的节点的最短路径的长。因此,具有0个或1个儿子的节点的npl为0,而 npl (nullptr) = -1。注意,任一节点的零路径长比它的诸儿子节点的零路径长的最小值多1。这个结论也适用少于两个儿子的节点,因为n原创 2022-07-14 15:02:13 · 133 阅读 · 0 评论 -
【优先队列(堆)】二叉堆类模板的实现
二叉堆(binary heap),像二叉查找树一样,堆也有两个性质,即结构性和堆序性。堆是一棵被完全填满的二叉树,有可能的例外是在底层,底层上的元素从左到右填入。这样的树称为完全二叉树(complete binary tree)。对于数组中任一位置i上的元素,其左儿子在位置2i上,右儿子在左儿子后的单元(2i+1)中,它的父亲则在位置⌊i/2⌋上。因此,这里不仅不需要链,而且遍历该树所需要的操作也极为简单,在大部分机器上运行也非常快。这种实现的唯一问题在于,最大的堆大小需要事先估计,但一般这并不成问题(原创 2022-07-13 08:00:00 · 201 阅读 · 0 评论 -
【散列】杜鹃散列详情与C++实现代码
如果在每次投掷中随机选取两个箱子且将被投项投入(在那一刻)较空的箱子中,则最大箱子的球数只是θ(log logN),这是一个显著更小的数。其中一种做法就是杜鹃散列(cuckoo hashing)。在杜鹃散列中,假设我们有N项,我们保持两个散列表,每个都多于半空,并且我们有两个独立的散列函数,它们可将每一项分配给每个表中的一个位置。杜鹃散列保持下述不变性:一项总是被存储在它的两个位置之一中。杜鹃散列的好处包括最坏情形常数查找和删除次数,避免懒惰删除和额外的数据,以及并行处理的可能。但杜鹃散列对散列函数的选择非原创 2022-07-12 08:00:00 · 376 阅读 · 2 评论 -
【散列】散列表HashTable线性探测法类模板的实现
一般说来,对于不使用分离链接的散列表来说,其装填因子应该低于 λ=0.5,这样的表叫作探测散列表(probing hash table)。如上图所示,当插入关键字68时,h(68)=68%11=2,与23冲突,于是被放入到下一个空闲位置4;插入11时,h(11)=0,与55冲突,向后寻找并存入空闲位置5。。。。只要表足够大,总能找到一个空闲位置,但花费的时间是相当多的。可以看出,插入和不成功查找需要相同次数的探测,且成功查找应该比不成功查找平均花费较少的时间。平方探测法是消除线性探测中一次聚集问题的冲突原创 2022-07-11 08:00:00 · 651 阅读 · 0 评论 -
【散列】散列表HashTable分离链接法类模板的实现
分离链接法(separate chaining),做法是将散列到同一个值得所有元素保留到一个链表List中。如果这个元素是个新的元素,那么它将被插入到链表的前端。插入前端的原因是:假设关键字是前10个完全平方数并设散列函数就是 hash(x)=x mod 10,则最后得到的分离链接散列表为下图所示。定义散列表的装填因子λ为散列表中的元素个数对该表大小的比,分离链接散列表的一般法则是让表的大小大致与预料的元素个数差不多(即λ ≈ 1)。实现代码:........................原创 2022-07-10 08:00:00 · 232 阅读 · 0 评论 -
【散列】散列表HashTable
散列表,又叫哈希表(Hash Table),是能够通过给定的关键字的值直接访问到具体对应的值的一个数据结构。散列表的实现常常叫做散列(hashing),散列是一种用于以常数平均时间执行插入、删除和查找的技术。也就是说,把关键字映射到一个表中的位置来直接访问记录,以加快访问速度。通常,我们把这个关键字称为 Key,把对应的记录称为 Value,所以也可以说是通过 Key 访问一个映射表来得到 Value 的地址。而这个映射表,也叫作散列函数或者哈希函数,存放记录的数组叫作散列表。其中有个特殊情况,就是通过不同原创 2022-07-09 16:36:52 · 318 阅读 · 0 评论 -
AVL树-带平衡条件的二叉查找树
平衡二叉树,又称为 AVL 树。实际上就是遵循以下两个特点的二叉查找树:每棵子树中的左子树和右子树的深度差不能超过 1;二叉树中每棵子树都要求是平衡二叉树;AVL树的查找、插入、删除操作在平均和最坏的情况下都是O(logn),这得益于它时刻维护着二叉树的平衡。如果我们需要查找的集合本身没有顺序,在频繁查找的同时也经常的插入和删除,AVL树是不错的选择。平衡因子:将二叉树上节点的左子树高度减去右子树高度的值称为该节点的平衡因子BF(Balance Factor),表示的就是其左子树深度同右子树深度的差原创 2022-07-07 13:04:58 · 139 阅读 · 0 评论 -
二叉查找树BinarySearchTree(BST)类模板的实现
重要性质:二叉树中,第 i 层最多有 2i-1 个结点。如果二叉树的深度为 K,那么此二叉树最多有 2K-1 个结点。二叉树中,终端结点数(叶子结点数)为 n0,度为 2 的结点数为 n2,则 n0=n2+1。证明:每一棵具有N个节点的二叉树都需要N+1个nullptr链。证明:每棵二叉树共有2N个链域,其中除根节点外每个节点都有父节点,即共有N-1个指针指向某个节点,空指针为2N-(N-1)=N+1。如果二叉树中除了叶子结点,每个结点的度都为 2,则此二叉树称为满二叉树。满二叉树中第 i 层的节点数为原创 2022-07-06 14:18:25 · 300 阅读 · 0 评论 -
双向链表List类模板的实现
List类本身,它包含连接到表两端的链、表的大小,以及一些方法。 - **Node类**,可能是一个私有的内嵌类。一个节点包含数据和指向前后两个节点的两个指针,以及一些适当的构造函数。 - **const_iterator类**,它抽象了位置的概念,是一个公有的内嵌类。该const_iterator存储一个指向“当前”节点的指针,并提供基本迭代器操作的实现,所有的操作,像=、==、!= 和 ++ 等,均以重载运算符的形式出现。 - **iterator类**,它抽象了位置的概念,是一个公有的内嵌类..原创 2022-06-20 17:17:31 · 247 阅读 · 0 评论 -
动态数组Vector类模板的实现
提供一个vector类模板的实现原创 2022-06-23 09:00:00 · 219 阅读 · 0 评论