
DSA
文章平均质量分 68
学习笔记,各种算法进行了详细分析,也有典型例题
CODER-GODV
CODER-GODV
展开
专栏收录文章
- 默认排序
- 最新发布
- 最早发布
- 最多阅读
- 最少阅读
-
希尔排序(动图+详解)
O(n^2)O(n)于是希尔就想:若是能先将待排序序列进行一次预排序,使待排序序列接近有序,然后再对该序列进行一次插入排序。因此此时直接插入排序的时间复杂度为O(n),那么只需控制预排序阶段的时间复杂度小于O(n^2)那么整体的时间复杂度就比插入排序的时间复杂度低了那具体的预排序应该怎么做才会时间复杂度满足要求呢?你可能会疑惑,为什么gap由大到小?因为gap越大,数据挪动的越快,耗时少;gap越小,数据挪动的越慢,耗时多。前期让gap较大,可以让数据快速移动到自己对应位置附近,减少挪动次数。原创 2022-11-17 08:00:00 · 2189 阅读 · 0 评论 -
快速排序(多版本实现)
可能你会觉得这个方法有点抽象,其实只用注意到prev所指向的元素一定是交换过后小于key的元素,那么可以这么理解,它是小于key的最后一个元素所以当cur越界时,prev所指向的是小于key的最后一个元素,那么只需最后将prev和key所指向的内容交换即可。快速排序非递归算法的实现都是借助栈来实现的,唯一不同的是单趟排序的方法不同,所以所有的非递归实现快速排序的算法主体流程大致相同,具体流程请看Hoare版本的非递归实现,这里就不再一一赘述。若选择最右边的数据作为key,则需要Left先走。原创 2022-11-16 08:00:00 · 114 阅读 · 0 评论 -
字符串匹配
何为字符串匹配?就是从目标文本字符串中找到目标字符串的过程本文着重讨论。原创 2022-11-15 12:30:51 · 1379 阅读 · 0 评论 -
左式堆(以大堆为例)
左式堆存在的意义是什么?我们来看下面场景:如何将堆A和堆B合并为一个堆H呢?相信你在思考过后可能会想到我们之前学过的完全二叉堆的操作方法,不错的确可以使用完全二叉堆的操作接口进行两个堆的合并,但是效率如何?我们接下来分析一下方法一:将B堆依次取出插入到A堆中方法二:将A、B堆混合并且使用建堆我们是否有更优的方法?这就是左式堆存在的意义了,能够使效率达到O(logn)原创 2022-11-08 10:32:30 · 304 阅读 · 0 评论 -
完全二叉堆(优先级队列)
kn-1},把它的所有元素按完全二叉树的顺序存储方式存储在一个一维数组中,并满足ki=k2i+2),其中i=0,1,2,…检测e和其父结点的堆序性是否被破坏,如果没有则完成插入;叶子结点只能出现在最下层和次下层,且最下层的叶子结点集中在树的左部。逻辑结点的孩子和父亲结点在物理上下标对应的关系(以下标i为例)将根结点最小的堆叫做小堆,也叫最小堆或小根堆。将根结点最大的堆叫做大堆,也叫最大堆或大根堆。堆中的任意结点总是不大于其父结点的值。原创 2022-11-06 18:18:21 · 399 阅读 · 0 评论 -
哈希表(开散列和闭散列)
都说使用除留余数法时,哈希表的大小最好是素数,这样能够减少哈希冲突产生的次数。原创 2022-11-07 08:00:00 · 1816 阅读 · 0 评论 -
计数排序(易懂)
计数排序,又叫非比较排序。顾名思义,该算法不是通过比较数据的大小来进行排序的,而是通过统计数组中相同元素出现的次数,然后通过统计的结果将序列回收到原来的序列中。然后依次输出count[i]次i + min就是最终的排序结果。原创 2022-11-06 00:01:07 · 128 阅读 · 0 评论 -
平衡二叉搜索树(红黑树)
如果初始化颜色为黑色,一定会破坏基本特征4如果初始化颜色为红色,可能会破坏基本特征3孰轻孰重,一目了然。原创 2022-11-03 23:14:31 · 97 阅读 · 0 评论 -
B树代码实现
此处分裂原则是,`s = (m + 1) / 2` ,将s作为新的父结点,s的左边为它的左孩子,右边为它的右孩子新分裂出的左孩子`⌊(m + 1) / 2⌋ - 1 = ⌈m / 2⌉ - 1 `新分裂出的右孩子` m - ⌈m / 2⌉ = ⌊m / 2⌋ `可见左右孩子都符合m阶B树的条件原创 2022-11-02 11:47:28 · 112 阅读 · 0 评论 -
有序向量二分查找算法-CPP实现(效率最高版本)
负无穷< e < V[lo]时,返回lo-1(左侧哨兵) V[hi-1] < e < 正无穷时,返回hi-1(右侧哨兵左邻)优点:此版本左、右分支前的关键码比较次数相等,最好情况下效率不如版本一;缺点二:并未严格兑现search(e)接口"返回不大于e且秩最大的元素"的要求。转向左、右分支前的关键码比较次数不等,而递归深度却相同。2)失败时,应返回不大于(亦是小于)e的最大者。各种情况下的查找长度更加接近,整体性能更趋稳定。1)当有多个命中元素时,必须返回最靠后者。缺点一:效率仍然可以优化,因为不难发现。原创 2022-10-10 08:00:00 · 210 阅读 · 0 评论 -
栈应用-进制转换(CPP实现简单易懂图解)
如下图所示,将需要转换进制的数除以进制得到的余数写在后面,商在下一轮循环中做被除数,知道商等于0,退出循环,逆序输出余数即为转换进制后的数,这一特点刚好可以用stack这一FILO特性的数据结构。原创 2022-10-16 08:30:00 · 523 阅读 · 0 评论 -
插值查找-CPP实现
5) = 2^32 = 4G时 log2(n) = 32,log2(log2(n)) = 5。首先通过插值查找,将查找范围缩小到一定的范围 然后再进行二分查找。通常优势不明显——除非查找区间宽度极大,或者比较操作成本极高。从O(logn)到O(loglogn),是否值得?易受小扰动的干扰和“蒙骗” 须引入乘法、除法运算。于是,[lo, hi]内各元素大致按照。向量中各元素均匀且独立随机分布。原创 2022-10-12 08:30:00 · 112 阅读 · 0 评论 -
归并排序-CPP实现
**交换顺序原因:** 当C全部填满A,k = lc,如果不交换顺序, B向A中填充一个元素,此时j++,如果j++此时等于lb,那么数组B就会越界访问,但是如果交换顺序就是先访问数组B,不会造成数组越界原创 2022-10-14 07:30:00 · 352 阅读 · 0 评论 -
插入排序-CPP实现(简单易懂图解)
O(n^2),始终将序列看成两部分:左边始终有序, 右边始终无序,开始时左边是空序列, 依次将右边每个元素插入到左边不大于这个数的最后一个元素的后面,直到序列中每个元素都插入完成,整体有序原创 2022-10-16 07:00:00 · 330 阅读 · 0 评论 -
选择排序-CPP实现(简单易懂)
O(n^2), 找到数组中最小的数字 2 ,然后和第一个数字交换位置。(如果第一个数字就是最小值,那么自己和自己交换位置,也可以不做处理,就是一个 if 的事情),由于数组第一个位置已经是有序的,所以只需要查找剩余位置,找到其中最小的数字5,然后和数组第二个位置的元素交换。原创 2022-10-15 07:00:00 · 242 阅读 · 0 评论 -
起泡排序-CPP实现
加一个flag,判断扫描一轮下来是否有顺序,如果有顺序就停止,就能解决缺点一,但还是没有解决缺点二。原创 2022-10-13 07:00:00 · 100 阅读 · 0 评论 -
LCS迭代和递归-CPP实现
最长公共子序列也称作最长公共子串(不要求连续),英文缩写为LCS(Longest Common Subsequence)。其定义是,一个序列 S ,如果分别是两个或多个已知序列的子序列,且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共子序列。原创 2022-10-08 23:07:48 · 376 阅读 · 0 评论 -
有序向量斐波那契查找-CPP实现
二分查找的效率仍有改进余地,因为不难发现转向左、右分支前的关键码比较次数不等,而递归深度却相同若能通过递归深度的不均衡,对转向成本的不均衡进行补偿平均查找长度应能进一步缩短…比如,若设n = fib(k) - 1,则可取mi = fib(k-1) - 1于是,前、后子向量的长度分别为fib(k-1) - 1、fib(k-2) - 1原创 2022-10-11 08:00:00 · 201 阅读 · 0 评论 -
伸展树(Splay树)
首先找到要删除的元素并把它伸展至根结点,然后判断它的右子树是否为空,如果为空,就直接删除;如果不为空,就找到根结点最近的后继,然后将他们的值互换,把那个后继的右子树赋值为当前值,然后删除那个后继原创 2022-10-28 20:32:48 · 554 阅读 · 0 评论 -
二叉搜索树(CPP实现简单易懂)
当要删除的结点左右结点都不为空时,首先将该结点的数据和它中序遍历右边的第一个结点互换数据,然后必定会转换为第一种情况,它的右边第一个结点的左节点必定为空。,如果根结点大于目标结点,递归调用根结点的左子树为根结点;如果根结点小于目标结点, 递归调用根结点的右子树为根结点;如果根结点等于目标结点,返回该结点。当要删除的结点的左右结点至少有一个为空的情况,就将当前结点的指针改为左右结点中的一个并将自身开辟的空间的空间释放。其实就是查找的过程,一直找到空指针,就把空指针赋值为要插入的数据并返回。原创 2022-10-23 08:00:00 · 187 阅读 · 0 评论 -
广度优先搜索(BFS)和深度优先搜索(DFS)
里面的元素是各个结点的信息,元素的内容有数据域,还有边结点类的与表头相连的第一个元素的指针,边结点类包含指向的元素在数组中的秩,下一个边结点的指针,权重,每当表头的链表多增加一个元素,将此元素的指针放在新增加元素的next指针中,然后把该指针设置为表头元素的第一条边。准备一个字符队列存放已经访问过的结点,首先将起点先访问,并且将是否访问的数组置为1,然后再把它推入队列中,依次出队列,然后找到与它相连的结点并且没有被访问过的结点,然后将其访问并把它推入队列,直到队列为空说明所有的结点访问完毕。原创 2022-10-23 08:30:00 · 286 阅读 · 0 评论 -
二叉树-重构(CPP实现简单易懂图解含有先序 + 后序的重建算法)
通过先序序列中的第二个元素可以找到左子树的根结点并且可以求出左子树的长度从而可以找到先序序列和后序序列中的左子树序列,然后递归调用,用整体长度减去左子树长度就可以求出右子树长度从而可以找到先序序列和后序序列中的右子树序列,然后递归调用,直到退化为长度为1的情况,并将其赋值,左右子树设置为NULL,返回根结点,重建二叉树完成。通过后序遍历序列找到根结点, 以此找到根结点在中序遍历结点中的位置,然后递归调用函数,设置其左子节点为递归调用左子树, 设置其右子节点为递归调用右子树。原创 2022-10-22 07:00:00 · 652 阅读 · 0 评论 -
二叉树-遍历(CPP实现简单易懂图解解法很全)
准备一个栈容器,先对根结点一直向左迭代,并每次将其入栈,直到访问到空结点,然后将当前结点设置为栈顶的一个结点,如果它的右结点为空或者已经访问过,就访问当前元素, 并把它移出栈,将当前结点设置为空,以便访问上一个结点,反复如此,直到当前结点和栈为空,退出循环,即后续遍历完成。先准备一个栈,依次从根节点一直向左下前进,直到发现当前节点为空,然后从栈中弹出一个节点,先访问自己,然后再访问它的右子节点,一直迭代这过程,直到当前节点为空节点, 并且此时栈为空,即中序遍历完成。基线条件:当节点为空时,返回空。原创 2022-10-21 07:00:00 · 901 阅读 · 0 评论 -
栈应用-逆波兰表达式(CPP实现简单易懂图解)
在由运算符(operator)和操作数(operand)组成的表达式中不使用括号(parenthesis-free)即可表示带优先级的运算关系 例如:0!+ 7!/ 8 ) / 90!* 7!原创 2022-10-20 08:00:00 · 481 阅读 · 0 评论 -
栈应用-中缀表达式求值(CPP实现简单易懂图解)
准备两个栈容器,一个填充数值A, 一个填充符号B, 首先向B中填充一个。当字符串扫描完成, B栈容器会被清空, C中唯一的一个元素即为计算的值。1. 当前栈中操作符的优先级小于当前元素, 将当前元素填充到B中2. 当前栈中操作符的优先级等于当前元素, 将B中栈顶元素弹出,字符串中的秩 +1 3. 当前栈中操作符的优先级大于当前元素, 弹出操作符和操作数,进行计算,再将计算结果push到A栈容器, 继续比对栈中操作符的优先级和当前元素的优先级, 直到出现`情况1`, 字符串的秩才会 +1原创 2022-10-19 07:00:00 · 710 阅读 · 0 评论 -
栈应用-栈混洗(CPP实现多版本简单易懂)
给定 pushed 和 popped 两个序列,每个序列中的 值都不重复,只有当它们可能是在最初空栈上进行的推入 push 和弹出 pop 操作序列的结果时,返回 true;如果pushed和poped为一个栈,就不能随机访问,所以要将poped反向移到新创建的rpoped,这样rpoped中的访问顺序就为poped中的进入顺序,接下来的思路同思路一。将要检测的pushed和poped模拟成一个向量,从而模拟混洗过程,当poped中的元素等于s中的元素,就进行。解释:1 不能在 2 之前弹出。原创 2022-10-17 06:30:00 · 218 阅读 · 0 评论 -
栈应用-括号匹配(CPP实现简单易懂图解)
给定一个字符串,里边可能包含“()”、“{}”、“[]”三种括号,请编写程序检查该字符串的括号是否成对出现。或者当迭代完,栈中还有元素剩余这三种情况都是匹配失败,当迭代完,栈为空,说明括号都匹配成功。则出栈,当还没迭代完,栈就为空, 说明右括号多余或者。消去一对紧邻的左右括号,不影响全局的匹配判断。Yes:代表括号成对出现并且嵌套正确。No:未正确使用括号字符。原创 2022-10-18 07:30:00 · 242 阅读 · 0 评论