- 博客(66)
- 收藏
- 关注
原创 哈希封装“unordered_set·map“
本文与对set·map的封装高度相似,可以参考我之前的对set·map封装的文章:链接:(没看过的话就点点我吧😚😚😚😚😚😚😚😚😚)
2024-10-28 22:22:55 984
原创 unordered_set·unorder_map的使用
unordered_set的声明如下,Key就是unordered_set底层关键字的类型;unordered_set默认要求Key⽀持转换为整形,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现⽀持将Key转成整形的仿函数传给第⼆个模板参数;unordered_set默认要求Key⽀持⽐较相等,如果不⽀持或者想按⾃⼰的需求⾛可以⾃⾏实现⽀持将Key⽐较相等的仿函数传给第三个模板参数;unordered_set底层存储数据的内存是从空间配置器申请的,如果需要可以⾃⼰实现内存池,传给第四个参数;
2024-10-23 11:12:19 757
原创 封装红黑树实现set·map
还有,我们自己实现不按照库里的方式实现是因为库里的实现比较复杂,就对于插入来说,我们每插入一个数据就可能需要对header的left和right进行重新维护,删除同理,还有对于有些旋转操作,也需要对header的parent,root的parent进行维护。注意:普通的类,其实就是一个好好的类,类里面的内嵌类型(内部类,或者说把另外一个类型typedef成别的,都称为内部类)end()如何表⽰呢?如下图:当it指向50时,++it时,50是40的右,40是30的右,30是18的右,18。
2024-10-19 11:38:35 1053
原创 红黑树的实现
在之前的AVL树学习中,AVL树的平衡是按照左右高度差(平衡因子)来进行平衡规定,是一种比较直观的方式,然而红黑树的出发点是这么想的:你AVL树的平衡控制太严格了,这种严格的平衡是通过不断地通过旋转来进行调整的,然而我可以提供一种比较"松散"的方式(来看我的概念吧😝)
2024-10-13 21:28:36 1027
原创 AVL树实现
对于二叉搜索树而言,在多次插入和删除操作后,二叉搜索树可能退化为链表。在这种情况下,所有操作的时间复杂度将从 O(logn) 劣化到 O(n)。EG:经过两次删除节点操作,这棵二叉搜索树便会退化为链表:EG:完美二叉树中插入两个节点后,树将严重向左倾斜,查找操作的时间复杂度也随之劣化:所以,我们如果要保持对二叉搜索树的操作效率,我们可以发现,我们应当控制二叉搜索树所有左右子树的相对平衡,因此,AVL树其实就是二叉搜索树的进化版本。
2024-10-01 13:03:33 957
原创 map的使用
map底层的红⿊树节点中的数据,使⽤存储键值对数据T1 first;T2 second;{}{}{}可以理解为,现在的key和value不再单独出现,而是整合在一个pair的结构体里面,pair里有两个成员变量,一个代表key,另一个代表value。int main()//1.插入有名的pair对象pair kv1("first", "第一个");//2.插入匿名的pair对象。
2024-09-26 15:03:12 952
原创 set的使用
前⾯我们已经接触过STL中的部分容器如:string、vector、list、deque、array、forward_list等,这些容器统称为序列式容器,因为逻辑结构为线性序列的数据结构,两个位置存储的值之间⼀般没有紧密的关联关系,⽐如交换⼀下,他依旧是序列式容器。关联式容器也是⽤来存储数据的,与序列式容器不同的是,关联式容器逻辑结构通常是⾮线性结构,两个位置有紧密的关联关系,交换⼀下,他的存储结构就被破坏了。set不支持改,因为set的底层是红黑树,如果改变了某个位置的数据,也就是破坏了原本树的结构。
2024-09-24 16:02:13 939
原创 二叉搜索树
插入操作: 在达到插入操作,我们可以通过递归来实现:递归逻辑:但是,我们也可以是不适用递归实现,因为根本就没有必要用递归实现,我们可以使用循环来实现。这种方法直接从根节点开始,逐步向下搜索合适的插入位置,直到找到空位置为止。循环逻辑:处理根节点:如果树为空(即根节点为),则新节点成为根节点。 Insert代码实现:查找操作:查找逻辑:(递归,循环都可,选循环)Find代码实现: 删除操作:(难点)
2024-09-15 10:40:02 654 2
原创 C++多态
在虚函数的后⾯写上 =0 ,则这个函数为纯虚函数,纯虚函数不需要定义实现(实现没啥意义因为要被派⽣类重写,但是语法上可以实现),只要声明即可。包含纯虚函数的类叫做抽象类,抽象类不能实例化出对象,如果派⽣类继承后不重写纯虚函数,那么派⽣类也是抽象类。纯虚函数某种程度上强制了派⽣类重写虚函数,因为不重写实例化不出对象。class Carpublic:public:cout
2024-09-13 16:03:10 789 2
原创 函数栈帧的创建和销毁
EBP,ESP这两个寄存器中存放的是地址,这两个地址是用来维护函数栈帧的。其实在VSmain函数也是由别的函数调用的:(main函数的调用关系):扩展基址指针,通常用作栈帧的基址指针,用于访问局部变量和函数参数。:扩展累加器,用于算术和逻辑运算。在32位模式下,它与8位的。:扩展数据寄存器,用于存储数据,特别是在输入/输出操作中。注意:函数栈帧的创建和销毁在不同编译器下是略有差异的。:扩展基址寄存器,通常用于存储数组索引或内存地址。:扩展计数寄存器,常用于循环计数。:扩展栈指针,指向当前栈顶的地址。
2024-09-07 12:52:54 1038
原创 常见位运算总结
如果我们想要让index为2的数据到最低位,我们应该右移2位,所以说这里的index就是为了和右移程度相匹配。位图的本质其实就是哈希表,只是在数组中存放的是比特位,也就是一个数据的二进制位。a ^ b ^ c = a ^ ( b ^ c ) (数据多时,结果唯一)(使用无进位相加(本质就是在做1的抵消)),在实现1的抵消时,并没有考虑顺序。实现-n操作也就是为了将最右侧的1,左边的区域全部变成相反。最右边为最低位,从最右边开始计数(使用下标)经过提取操作:(得到结果)
2024-09-05 16:02:10 718
原创 位运算C/C++
位运算的应用非常广泛,它们通常在需要处理大量数据或对性能有严格要求的场合中非常有用。由于位运算直接操作内存中的位,因此它们通常比等效的算术或逻辑运算更快。位运算是一种直接对整数的二进制位进行操作的方法。下面我将通过一个详细的示例来解释每个位运算符的工作原理,并提供一种可视化的方法来帮助理解。位运算是C和C++编程语言中的一种操作,它直接对整数的。将操作数的每一位取反,0变1,1变0。可视化过程:只有当两个位都是1时,结果位才为1。可视化过程:只要有一个位是1,结果位就为1。对应位都为1时,结果才为1。
2024-08-30 17:41:30 809
原创 遍历结果的推导
我们可以根据先序遍历和中序遍历,可以重建出唯一的二叉树,所以,在我们知道一颗二叉树的前序遍历的结果是ABCD,想要知道满足条件的不同的二叉树有多少种时,我们就还应该知道这些二叉树的中序遍历的结果有多少,就是以先序遍历作为入栈条件,以不同的出栈,出的结果就是不同的中序遍历:(例子)那么我们有多少个不合法的,我们要解决这个问题就需要找到第一个前缀和=0的,栈里是要有元素才可以出栈。
2024-08-29 17:23:14 579
原创 外排序之文件归并排序
跟外排序对应的就是内排序,我们之前讲的常⻅的排序,都是内排序,他们排序思想适应的是数据在内存中,⽀持随机访问。外排序通常采⽤的是⼀种“排序-归并”的策略。在排序阶段,先读⼊能放在内存中的数据量,将其排序输出到⼀个临时⽂件,依此进⾏,将待排序数据组织为多个有序的临时⽂件。在排序阶段,先读⼊能放在内存中的数据量,将其排序输出到⼀个临时⽂件,依此进⾏,将待排序数据组织为多个有序的临时⽂件。file1和file2利⽤归并排序的思想,依次读取⽐较,取⼩的尾插到mfile,mfile归并为⼀个有序⽂件;
2024-08-28 16:42:06 389
原创 C++继承
下⾯我们看到Person是⽗类,也称作基类。Student是⼦类,也称作派⽣类。(因为翻译的原因,所以既叫⽗类/⼦类,也叫基类/派生类)其实继承方式和访问限定符有着紧密关系:两两对应的效果:类成员/继承方式public继承protected继承private继承父类的public成员子类的public成员子类的protected成员子类的private成员父类的protected成员子类的protected成员子类的protected成员子类的private成员。
2024-08-27 21:54:03 795
原创 C++模板进阶
【优点】模板复用了代码,节省资源,更快的迭代开发,C++的标准模板库(STL)因此而产生增强了代码的灵活性【缺陷】模板会导致代码膨胀问题,也会导致编译时间变长出现模板编译错误时,错误信息非常凌乱,不易定位错误。
2024-08-25 22:52:24 640
原创 快排之自省排序
(sgi stl中使⽤的是深度为2倍排序元素数量的对数值)那就说明在这种数据序列下,选key出现了问题,性能在快速退化,那么就不要再进⾏快排分割递归了,改换为。introsort是introspective sort采⽤了缩写,他的名字其实表达了他的实现思路,他的思路就是进行⾃我侦测和反省,快排。(这也是C++中,STL中的快排的实现原理)
2024-08-24 16:11:27 256
原创 快排之三路划分
决定快排性能的关键点是每次单趟排序后,key对数组的分割,如果每次选key基本⼆分居中,那么快排的递归树就是颗均匀的满⼆叉树,性能最佳。三路划分的主要优点是它减少了不必要的数据交换,特别是当数组中有很多重复元素时,这可以显著提高排序效率。核⼼思想是把数组中的数据分为三段【⽐key⼩的值】 【跟key相等的值】【⽐key⼤的值】,所以叫做三路划分算法。
2024-08-23 14:16:43 287
原创 排序之计数排序
计数排序是一种线性时间复杂度的排序算法,适用于处理整数且整数的范围不大的情况。它是基于这样的思想:对于每个元素,我们可以计算出它在排序后数组中的位置,然后将元素放到该位置。计数排序的基本步骤如下:以下是计数排序的简单理解:将每个元素放到它在排序后数组中的位置上,我们可以使用遍历:给定一个长度为 n 的数组 arr ,其中的元素都是“非负整数”由于 的各个索引天然有序,因此相当于所有数字已经排序好了。接下来,我们遍历 ,根据各数字出现次数从小到大的顺序填入 arr 即可:但是假设输入数据是商品对象,
2024-08-22 16:10:38 865
原创 排序之归并排序
注意:除法会丢失数据,因为(偶数a)+(偶数a+1),对应的middle还是(偶数a),这也就是为什么分区间的时候是【begin,mid】【mid+1,end】而不是【begin,mid-1】【mid,end】,用【0,9】进行观察就可以发现。这个例子展示了非递归归并排序的整个过程,每一步都通过迭代的方式合并相邻的有序子数组,直到整个数组变得有序。:将两个有序的子数组合并为一个有序数组。:首先,确定数组的初始大小为1,即每个元素都是一个有序的子数组。我们从大小为1的子数组开始,数组中的每个元素都是有序的。
2024-08-21 16:24:03 899
原创 排序之快速排序
在实践中,随机选择通常被认为是一种很好的策略,因为它可以减少最坏情况发生的概率,并且对于各种类型的数据集都表现良好。L遇R:因为L是要找大,R要找小,R先走,停下来,R停下来的位置一定比key小,然而L要找大,找到就停下来了,但是没找到大的就遇到R,然后停下来了;R遇L:R先走,找小,没有找到比key小的,直接跟L相遇了。L停留的位置是上一轮交换的位置,上一轮交换,把比key小的值换到L的位置;在实际编程中,通常遵循简洁性原则,避免添加不必要的代码,除非这样做可以提高代码的可读性或有其他明确的好处的呢。
2024-08-20 22:53:54 864
原创 排序之希尔排序
对于插入排序来说,在正常情况下是优于冒泡排序的,插入排数在面对逆序数组时才会有最差的时间利用率(默认插入排序排的是升序),为了优化插入排序的算法,第一部便是预排序(让数组接近有序),再者,插入排数,这中框架,便是插入排序的优化排序-----希尔排序。Ciura增量序列是:1, 4, 10, 23, 57, 132, ...,序列中的每个数字是前一个数字加上2的k次方,其中k是当前序列的索引。:在每组内,你进行简单的排序,就像你在玩单人纸牌游戏一样,把牌一张一张地放到合适的位置上。
2024-08-19 23:38:18 694
原创 时间复杂度与空间复杂度
在编程中,特别是在算法设计和数据结构的选择上,复杂度是一个非常重要的概念,它用来描述算法或操作的执行时间或资源消耗与输入规模的关系。复杂度通常分为时间复杂度和空间复杂度两种。
2024-08-19 17:15:26 693
原创 排序之选择排序
选择排序是一种简单直观的排序算法,其基本思想是在每一轮选择中找到未排序部分的最小(或最大)元素,然后将其与未排序部分的第一个元素交换位置。尽管选择排序不是最高效的排序算法,但它的优点是算法简单,且在数据量较小或部分数据已经有序的情况下,性能表现尚可。因此,如果预计数据集的大小较小,或者在排序前可以快速判断数据集的大小,选择排序可能是一个不错的选择。:在找到最小元素后,如果它不在当前位置,可以一次性将所有元素移动到它们最终的位置,而不是仅仅交换最小元素。:在未排序的数组部分,找到最小元素的索引。
2024-08-19 13:32:57 729
原创 排序之插入排序
插入排序是一种简单的排序算法,它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描,找到相应位置并插入。:如果第二张牌的数字比第一张牌小,你就继续拿出第三张牌,将它与第一张牌比较。如果第三张牌的数字也比第二张牌小,你就将它放在第一张牌的前面,然后继续比较第二张和第三张牌。:然后你拿出第二张牌,将它与第一张牌比较。如果第二张牌的数字比第一张牌大,你就将它放在第一张牌的后面,这样你就有两张牌的有序序列了。:你继续拿出剩下的牌,重复上述步骤,直到所有的牌都被比较过并插入到正确的位置。
2024-08-19 12:44:56 587
原创 二叉树遍历(C++版本)
访问结点所做的操作依赖于具体的应用问题。遍历是二叉树上最重要的运算之一,也是二叉树上进行其它运算的基础。前·中·后序遍历:前序遍历亦称先序遍历)——访问根结点的操作发生在遍历其左右子树之前。中序遍历访问根结点的操作发生在遍历其左右子树之中(间)。后序遍历访问根结点的操作发生在遍历其左右子树之后。由于被访问的结点必是某子树的根,。NLRLNR和LRN分别又称为先根遍历、中根遍历和后根遍历。相应地,前序、中序和后序遍历都属于。
2024-08-18 14:45:23 1199
原创 TOP-K
我们可以使用一个额外的数据结构(例如哈希表)来记录每个元素出现的次数,这样即使元素值相同,我们也能知道它们是否是不同的实例。遍历数组中的每个元素,如果堆的大小小于K,就将元素推入堆中;如果堆的大小等于K,并且当前元素大于堆顶元素,则弹出堆顶元素,并将当前元素推入堆中。此外,这个实现的时间复杂度是O(n log K),其中n是数组中元素的数量。注意,这种方法的时间复杂度仍然是O(n log k),但是它能够正确处理重复元素的情况。中,并逆序打印这些元素,因为最小堆的顶部是最小的元素,而我们需要最大的元素。
2024-08-17 14:53:48 830
原创 排序之堆排序
堆排序是一种基于比较的排序算法,它使用二叉堆数据结构来实现。二叉堆是一种特殊的完全二叉树,它满足以下两个性质:结构性:完全二叉树,即除了最后一层外,其他各层的节点数都达到最大,并且最后一层的节点尽可能地集中在左侧。堆属性:可以是最大堆或最小堆。在最大堆中,父节点的值总是大于或等于其子节点的值;在最小堆中,父节点的值总是小于或等于其子节点的值。
2024-08-17 12:29:40 287
原创 二叉树(binary tree)
在计算机科学中,树(Tree)是一种抽象数据类型,它是由节点(Node)组成的层次结构。树中的每个节点代表一个数据元素,而节点之间的连接关系则代表了数据元素之间的逻辑关系。深度(Depth):从根节点到某节点的边的数量。高度(Height):树中最长路径的长度,即从根到最远叶节点的边的数量。树在计算机科学中有着广泛的应用,包括但不限于数据存储、组织、搜索算法、文件系统、网络结构等。注意;我们通常将“高度”和“深度”定义为“经过的边的数量”,但有些题目会将其定义为“经过的节点的数量”。
2024-08-16 14:17:39 781
原创 链表(linked_list)的理解以及实现
链表是一种线性数据结构,其中的每个元素都是一个节点对象,各个节点通过“引用”相连接。引用记录了下一个节点的内存地址,通过它可以从当前节点访问到下一个节点。可以看出:链表物理结构不是连续的。
2024-08-15 20:05:35 1145
原创 STL中的栈(stack)和队列(queue)以及简单(复用)实现
deque(双端队列:是一种双开口的连续空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
2024-08-14 12:58:35 886
原创 编码的理解
这些符号是不能在磁盘或内存当中存储的,计算机最早是由老美发明出来的,内存和磁盘当中只有 0,1,严格来说内存和磁盘中只能表示整型,那么我们应该怎么表示符号--------编码。内存存值,显示符号,打印时访问内存,有很多个字节,拿到第一个字节是97,再拿97去编码里面去查,97映射的符号是a,所以显示对应的符号,所以打印的时候就是查编码表的过程。但是ASCll是适合老美的,编码表是来表示文字的,计算机要继续推广,我们的文化博大精深,汉族就有近10万个,从国际上来,我们需要一个比较统一的编码表:Unicod。
2024-08-02 16:06:22 457
包含了多个关于C++编程概念和特性的图像文件,具体内容涵盖了排序算法、内存管理、迭代器使用、拷贝构造函数等多个方面,会更新,放心
2024-08-23
STL中string,vector,list,queue,stack....等原码
2024-08-23
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人