自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

努力学习C++的熊大(保护森林版)

欢迎和熊大讨论技术问题,如果俺文章有啥不对的地方,愿大佬们多多指出谢谢啦

  • 博客(49)
  • 收藏
  • 关注

原创 为什么 unordered_set / unordered_map 这么快?我用连地址法手写了一遍

,而unordered_set和unordered_map是无序的,不管任何顺序,只根据key计算到对应位置进行查询插入,所以这里毋庸置疑就是用的哈希表来进行模拟实现。以下举例是以unordered_set为例。在两个类都依赖对方的时候,这就需要声明,然后这里迭代器的使用又需要后面定义哈希桶的私有成员,这里也需要友元类既能泛型迭代器还能访问私有成员。unordered_set和unordered_map底层是哈希表无序的(不追求排序),而set和map的底层是红黑树是有序的(追求排序)

2026-01-23 16:08:10 829 1

原创 哈希王座:线性探测×二次探测×链式革命——冲突解决的终极博弈

常见的是通过key直接插入到数组,查询的时候也是通过key去下标访问数组(这就不会有哈希冲突问题,因为每个key都有直接对应的映射关系)。缺点就是可能会导致堆积(就是出现哈希冲突的key占据了别人的哈希计算的值,然后不断影响后面的值),这会导致查询和插入的效率大幅度减低。针对于解决哈希冲突的哈希函数(哈希冲突的无法避免的,只能是通过哈希散列函数和好的冲突处理,如二次/多重探测)。负载因子是哈希表中存储数据N/哈希表大小M的除数(小于1),负载因子是判断空间利用的情况。,是⼀种组织数据的方式。

2026-01-20 15:25:46 776 1

原创 深入探索C++关联容器:Set、Map、Multiset与Multimap的终极指南及底层实现剖析

之前我们所学的STL容器包括序列式容器、容器适配器和关联式容器,这里。

2026-01-15 20:45:49 856

原创 掌握红黑树:详解插入过程中的旋转与重着色策略

第五种情况也是属于第四种情况一样,不能通过直接改变颜色来解决问题,这需要通过旋转来旋平衡,这里和第四种旋转方式和改变颜色方式就不一样了,需要右左双旋,然后再。因为这里我们很难控制黑色结点,所以我们这里插入红色结点会很好控制黑色结点数量,然后我们根据红色结点的规则去慢慢修改父节点/插入结点的颜色。,还有一个是红色结点不能连续存在,这两个规则就决定了,红黑树最长路径不超过最短路径的2倍,这就是为什么能保持平衡的原因。,都是双旋,只不过双旋顺序不一样,这里是先右单旋,然后再左单旋,改变颜色顺序也是一样的,

2025-12-21 13:05:11 735 3

原创 手撕AVL树:从理论到实践,掌握插入操作的完美平衡

本章主要详细的描述了AVL树的插入过程中出现的所有情况,以及介绍了旋转这一思路,使用图文配合能让我们更加深入理解旋转的过程,以及插入的流程,这个AVL的树插入实现为我们后面学习红黑树的学习提供的底层的思路,红黑树的学习也离不开旋转这一步骤,关键是理解插入实现。当然这个AVL树其次重点就是平衡检测,这个利用计数来高度差并于平衡因子来比较判断是否平衡思路也值得我们学习,这里还有AVL树的删除,可以参考《殷⼈昆 数据结构:⽤⾯向对象⽅法与C++语言描述》。

2025-12-16 23:08:19 681 1

原创 二叉搜索树:数据宇宙中的秩序法典与高效检索圣殿

第三种:情况较为复杂,就是左右孩子都存在,这就需要寻找一个代替结点去继承该删除结点,我们可以选择左子树中的最右结点(也就是左子树中最大结点),或者我们选择右子树中的最左结点(也就是右子树中最小结点),这两个操作都可以实现,目的是为了满足根结点一定要小于右子树/大于左子树即可。)的查找效率,但是二分查找有一个缺陷就是内部支持下标随机访问的且有序,删除和插入需要挪动数据效率很低,所以二叉搜索树就是在插入和删除要优与二分查找。,或者是具有以下性质的⼆叉树: 1.若它的左⼦树不为空,则。若它的右⼦树不为空,则。

2025-12-14 11:45:27 546 1

原创 C++多态机制深度解析:从虚函数表到运行时动态绑定

理解实现多态要有2个重要条件:1.必须是基类的指针和引用才能调用虚函数(可以这么理解,如果不传指针/引用就相当于找不到对应的对象地址,会默认调用基类。这里还要说明一下父类 = 子类,这个是不会产生临时对象的,也就可以实现既传子类又能传父类,这也是多态的一个重要性质)2被调用的函数必须是虚函数,并且完成虚函数的重写(这个就是我们上面讲的虚函数重新写定义函数,但是声明是基类)。public://条件2:重写cout << "原价票价高铁票:" << endl;

2025-12-13 11:39:30 980

原创 深入解析C++继承体系:从访问控制到虚继承的全面指南

继承是面向对象编程的核心特性之一,它允许一个类(派生类/子类)获取另一个类(基类/父类)的属性和行为。派生类能继承基类中的所有成员变量和成员函数,但是友元关系不能继承(就像你把的朋友不能继承他家财产),这里就需要自己在继承内加入友元关系。这里需要友元两个类,而编译器会往上找,所以这里还需要声明另一个类(继承z中需要调用函数还需要声明一些函数,这里的函数是上面寻找不到的,也就是在此类后面定义的类,如果需要使用后面定义的类的函数,就得声明,使用别人类之前是友元)。。

2025-12-11 19:45:45 767

原创 stack、queue与priority_queue的用法解析与模拟实现

stack是一个先进后出数据结构,而queue是一个先进先出的数据结构,还有一个queue的展开就是优先级队列priority_queue,这里priority_queue的知识点较多,涉及到了仿函数和综合了堆排列。其次就是栈和队列,他们之间的模拟又涉及到了容器适配器deque(双端队列),以及让我们学习到该如何学习和了解源码。这里最主要的就是stack、queue和priority_queue的应用场景。

2025-10-21 19:25:49 775 5

原创 高级 C++ 模板编程技术与应用

在模板中其实是可以定义和声明分离,只不过针对找不到链接问题(函数地址,因为实例化未找到地址,从而找不到链接问题),解决办法就是在定义处在声明一次模板(这能够让编译器知道特定模板函数地址,当然这个不是模板,这是确定的函数,用于让编译器寻找到对应实例化模板的地址)所以一般都是在.h中直接定义函数,这样在编译过程中.h会到.cpp中去,调用对应的函数,从而在链接之前对模板进行实例化,产生对应的函数地址,用于调用函数。

2025-10-21 19:25:39 812

原创 list的使用

以下使用是基于与string和vector部分较不常见的使用(少部分经常使用的未列举),还有部分可看。

2025-10-02 15:29:32 461 1

原创 List迭代器和模拟(迭代器的模拟)

算法对迭代器是有要求的,算法迭代器名字就是要求。迭代器通用的功能++/*(解引用)/!=这几个基本组成。如果是数据结构stl迭代器是双向迭代器是实现不了随机的功能的,这也导致了有时候使用迭代器时候用不了+ -迭代,这就是因为双向迭代器不支持+,-这些运算符重载。双向迭代器不能支持+-操作,一般能实现的只有随机迭代器(解决办法就是在调用之前使用一个变量存储迭代器然后++\--操作达到想要的指向地址)list内部的sort算法,如果数据量小,就用,数据量大,用别人的。

2025-10-02 15:28:56 421

原创 力口17电话号码的字母组合

题目意思是输入数字字符串,然后根据数字下对应的字母与另一些数字对应的字母进行数学中的排列组合,这里需要解决的问题是需要根据数字字符串个数来排列组合,所以这里可能会用到递归思想,首先我们不考虑递归,当digits=“2”时伪代码digits="23"时伪代码因为这里不确定循环次数,这时候就能通过循环+递归这种方式可以动态调整循环次数(时间复杂度3^n)

2025-10-01 10:01:51 232

原创 vector的使用和模拟

vector这里较为重要的有vector的使用和vector的模拟,其中迭代器的失效很重要,通过底层实现vector的中发现在任意删和任意插(insert,erase)中pos指向会发生改变,这就导致了迭代器的失效,这里解决这个问题就是更新pos位置,然后返回pos对应的指针。

2025-09-23 20:32:36 652 1

原创 只出现一次的数字||(力口137)

这里我发现了位进制的运算的厉害之处了,题刷的越多,知道的越多(也就是见识也越来越多),还是需要多刷题,然后并不断总结前人代码,发现他们这么做的意义是什么,想解决的问题是什么,并且我发现最重要的还是自己去画图然后模拟(带数据模拟)不断寻找规律之处。当然这道题还给我了一种思想就是还是带着10进制的思想去写这一类的二进制问题,我们需要针对自己需求进行答题,这里我是带着二进制的思想去写的,但是这里给了我一种写三进制感觉,不同进制之间的关系也存在。

2025-09-21 01:23:07 242

原创 C++STL与字符串探秘

STL C++标准库的重要组成部分,是一个包罗数据结构与算法的软件框架。一般汉字是占两个字节,偶尔的偏僻字会占三个字节。学习string因为它里面能非常好的表示utf-8,而utf-8是变长编码,能过兼容ascii编码(老美的文字),string里面就是差不多字符顺序表。string 遍历+修改方法1.下标+[]调用运算符重载。

2025-09-17 19:46:15 812

原创 力口oj题LCR 192. 把字符串转换成整数 (atoi)

总的来说,作者基本上查文档的时间比做题的时间还长,可能是刚开始学string对一系列string的用法不太了解,对英语熟练度也不行,看文档费力。但是我发现了文档的重要性了,如果就一个人记住所以用法是完全不可能的,所以要利用好文档,同时也要提高自己英语水平。

2025-09-10 01:42:37 752

原创 C++模板初阶

然后模板函数形参类型名就可以用以上两个来实现需要传2个不同类型的实参情况。

2025-09-06 18:22:26 808

原创 C++内存管理

就和把披萨放到烤箱里面,而你没设定温度和时间这个未定义,那就是看运气了,如果恰好等你去的时候,打开它那就是完美披萨,相对应的,如果你没有或者超过了那段时间去取那个披萨,此时的披萨就不能吃了)。

2025-09-06 11:46:18 1167

原创 C++类和对象入门的结束

class为定义类的关键字,格式为class 名字 {里面是类的主体};(这个分号不能省略)类的主体可以写函数,而这里面函数会默认为内联函数,如果不想用内联函数,就放入.h文件中声明然后.cpp里面定义即可。在C++中struct也可以是类,也就是说struct也可以定义函数了。类里面一般有函数和变量,函数称为类的方法或成员函数,而变量就称为类的属性或成员变量。他是一个特殊的成员函数,这是对象实例化定义时的初始化。构造函数的出现是为了避免程序员在写代码过程中忘记初始化。class A。

2025-08-26 00:30:56 841 1

原创 C++入门

namespace的定义实质上就是定义一个域,与全局域区分开,namespace定义和结构体定义一样(只不过结构体的花括号后面有分号,这里没有分号)。namespace定义的域名,遇到有全局域和namespace定义的域时,首先会使用全局域,当然这里要是全局域中没找到这个变量,及时namespace内有变量,也会报错,而当你想要使用namespace对应的域时,那就必须 (域名::变量) 这样使用才能访问到这个域的变量,这样就能使得不同的域使用相同的同名的变量(解决同名的冲突问题)。。

2025-08-08 15:39:00 1075 2

原创 八大排序算法

排序是计算机科学中最基础、应用最广泛的算法之一。它将一组无序的数据元素(或记录)按照某种特定的顺序(如升序或降序)重新排列,是数据检索、统计分析、高效算法设计等众多领域的基石。本章总结了学习过程中八大排序算法,包括比较排序和非比较排序。

2025-08-03 10:36:26 2263 6

原创 树的基础知识总结

基本概念:树是一种非线性的数据结构,它由n(n>=0)个有限结点组成一个有层次关系的集合。树有一个特殊结点是根结点,他没有前驱结点,可以理解成所有结点都是由这个结点延展出去的。除了这个根结点后面的子结点都是互不相交的集合(也就是只有一个途径才能知道这个子结点一棵树有n个结点,就有n-1条边),只有这样才能保持是树这个结构。基本术语树的表示一半使用的是孩子兄弟表示法//下面的孩子//右边兄弟int data;//数据孩子兄弟表示法示意图二、常见的树结构1.二叉树。

2025-07-19 13:41:48 971 3

原创 设计循环队列oj题(力口622)

当然写到这里,肯定会想到我不扩容这个空间,(rear+1)%(capacity)观察是否等于begin是否可以,答案是不行的,因为我们在插入过程中是rear是先插入再++,这就会导致在下标第capacity-2位置上插入数据后到达下标capacity-1,而到了下标capacity-1时,(rear+1)%(capacity)时就会等于begin,导致内部数据从capacity到capacity-1就满了。通过对比可知,在结构方面数组会略显一筹,但是数组在判断循环队列是否插满和是否为空时会冲突。

2025-07-18 19:43:23 758

原创 有效的括号数据结构oj题(力口20)

这里我们根据第二个要求,可以知道当遇到右括号时,需要找到与之最近的左括号匹配,通过这个我们就能想到,当遇到右括号时把后进的左括号与之对比看是否满足相同类型括号。注意了是顺序,大家以为就是左括号(小括号)遇到左括号(中括号)然后遇到了右括号(小括号)和右括号(中括号),然而恰恰相反,而是小括号(左)、中括号(右)和中括号(右)小括号(右)相依匹配。),判断是否匹配成功,只要有一个匹配失败,就说明这个字符串不符合有效字符,以上都符合后,最后判断栈是否还有左括号,如果没有则符号题目要求。

2025-07-18 13:09:20 505

原创 随机链表的复制数据结构oj题(力口138)

这里我们要注意深拷贝和随机指针,首先就是深拷贝对应的浅拷贝是和原链表用一个结点,而深拷贝则对应的不和原链表一个结点,也就是说需要我们自己开辟空间去创建一个结点和原链表一模一样。所以这里最为复杂的是该如何处理random指针,这里很难寻找到相对结点靠左的结点和random对应,我们这里选择在原链表基础上进行拷贝,通过原链表上的random指针的next(这个表示在原链表上的下一个指针,这个指针就是复制的链表)与我们拷贝对应。最后一步就是将原链表和复制好的链表断开。

2025-07-16 23:42:45 384

原创 随机链表的复制数据结构oj题(CM11)

这里我们可以想到这里是用到单链表,很难从后往前去交换,所以我们这里就可以设置两个头结点,其中一个链表用来保存小于x的结点,还有一个保存大于等于x的结点,最后就能将两个链表合并在一起。这里给了一个头结点pHead,和一个定值x,这里要的是比x值小的结点要在x这个结点的左边,并且这里写着不改变数据顺序,也就是。比如:{5,2,1,3,6},x=3;最终返回的顺序为{2,1,3,5,6}。

2025-07-16 21:06:05 707

原创 链式二叉树数据结构(递归)

实现以上的二叉树方法离不开递归,当然这里遍历可以分两种类型,一种是递归型(前中后序遍历),另一种是非递归型(层序遍历),但是另一种非递归型需要利用到另外学到的数据结构(队列)。用这个队列可以存储需要顺序遍历的结点,当然这个思想,让我也知道了原来数据结构之间也是可以联系在一起的,并可以一起使用并实现一个另一个数据结构的方法。这个二叉树体现出了递归的便利性,但也需要我们不断画图,并不断理解起函数栈帧的建立和销毁。

2025-07-10 13:42:58 1023 2

原创 堆数据结构

堆在排序中优势很好,时间复杂度就为O(nlogn),但是无论如何都避免不了和冒泡排序一样将所有的都遍历了一边,在解决TOP——K问题上门还是有很大用处的,可以避免在操作系统上申请空间,在提高性能方面有很大作用。而相对于向上调整算法,向下调整算法建堆的时间复杂度要低,能够优化算法,提高编译效率。这个建堆的思想能够为我们收获最大值(小堆)和最小值(大堆),为我们优化排序提供了一个好方法。

2025-07-05 21:34:04 965 2

原创 队列和栈数据结构

为了弥补链表尾删和尾插时间复杂度为o(N)这一缺陷,这里可以定义2个结构体,一个结构体用来结点内元素的结构体,另一个结构体是用来标记头结点(这里没有头结点,只是为了理解,设置的头结点,里面有数据。ps:头结点没有数据)和尾结点用于保存尾节点,方便访问和插入删除尾结点。//结点结构}QueueNode;//队列结构//int size;}Queue;优点缺点操作简单,插入删除这些时间复杂度都是o(1)内存浪费(需要向内存动态申请空间)内存管理方便(避免插入和删除移动数据)局限性。

2025-07-03 16:59:26 914 1

原创 单链表和双向链表

对于单链表的优缺点对于双向链表优缺点双向链表优点缺点查询比单链表效率高,虽然都是o(N),但是可以利用双向特性,进行左右开始查询(类似二分法)内存占用大(两个指针和一个数据,3个元素)双向遍历代码实现向较为单链表复杂插入删除方便总结:对于双向链表和单链表,当需要频繁存入大量数据并查询时,可以首先考虑单链表(内存和代码实现)。当需要频繁插入和删除并频繁遍历时,可以考虑双向链表(时间效率高)。

2025-07-02 16:44:11 962 1

原创 链表的中间结点数据结构oj题(力扣876)

快慢指针就是一个fast指针每次走两步,另一个low指针每次走一步,等fast出界时,low就是中间指针。先计算内部有多少个节点,然后进行除以二,得到中间节点数后,进行遍历到对应的中间节点。(本人有点笨,只能想到这种方法了)。通过向大佬学习,我发现一个更加好用的方法,,请你找出并返回链表的中间结点。如果有两个中间结点,则返回第二个中间结点。,这个方法是个好方法思路简单,代码也好写,就是难想出来哈哈哈。原理就是通过1/2总长度。,对于我来说一开始想到的。

2025-05-16 20:57:46 499 2

原创 反转链表链表数据结构oj题(206)

遍历中嵌套头插函数,时间复杂度不会很大,也就是O(n)。为了方便代码的书写,我们。可以方便我们写代码,重点讲解一下第二个思路,先上图,再讲解将抽象具体化。对于反转这道题,我们学习了单链表的增删改查后,立马就能想到。,请你反转链表,并返回反转后的链表。

2025-05-16 20:17:05 449

原创 移除链表元素数据结构oj题(力扣题206)

在最后时如果ptail不为空,那就必须将ptail->next置空,可以将这个作为结束节点,避免返回不符合题意值。就是遍历循环寻找val这个值,进行删除该节点,这中方法是最容易想出来的,可是。对于需要删除链表中val的值,我们立马可以想到一种。,然后得到符合题意的节点移动到ptail中。这里我们着重讲解这个方法,这个方法就是。,请你删除链表中所有满足。就是用类似空间换时间的方法(写代码过程中我们需要使用。给你一个链表的头节点。

2025-05-16 17:05:33 480

原创 复杂度和顺序表(双指针方法)

时间复杂度和空间复杂度是用于判断算法好坏的指标,程序性能的核心指标。时间复杂度主要衡量⼀个算法的运⾏快慢,⽽空间复杂度主要衡量⼀个算法运⾏所需要的额外空间。目录目录一、时间复杂度和空间复杂度1.1概念1.2规则二、顺序表2.1静态顺序表2.2动态顺序表三、双指针法。

2025-04-30 22:21:31 1223 1

原创 c语言中文件操作详解

文本文件就是通过将字符(一个字节)对应的ascll值保留到文件中,这个过程需要将字符(数字也会当成字符)转换为一个一个的ascll值,然后进行存储每个字符对应的ascll值的二进制。

2025-04-22 09:51:04 1463 3

原创 内存函数和动态内存管理

memcpy这个库函数用于是任何类型,将一个地址的内容复制到到另一个地址上,它是针对于内存的修改,使用使用过程中是memcpy(arr1(拷贝地址),arr2(从这里抄内容到arr1中),size_t(字节个数)),需要头文件string.h返回的是arr1这个已经拷贝的地址。它遇到\0不会停止,它只受字节个数的影响,它针对的是内存的修改,也就是一个一个字节的修改。注意这里是适用于不重叠的内存。memmove和memcpy的使用是一样的,不过它专门用于重叠内存的拷贝。

2025-04-18 16:07:44 1549 1

原创 struct结构体、union联合体和枚举

可以没有大小。特点就是计算结构体总大小时,不会计算数组大小,这个柔性数组是可以通过动态内存来确定数组大小(更加灵活),这个我后面会和动态内存一起讲。

2025-04-09 18:39:34 1276 1

原创 整数和浮点数在内存中的存储

来表示(最前面的1不在23个比特,为了节约比特取确保精度)而E这个表示是中间的剩下的8个比特位来表示指数。如图所示:floatdouble如:-

2025-04-08 17:20:50 911 1

原创 字符函数和字符串函数使用

strncpy、strncat、和strncmp这些库函数是在前面函数的基础上加了一个控制拷贝(拼接、对比)字节个数功能,其他功能不变。

2025-04-07 22:12:29 1414 2

空空如也

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除