自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(31)
  • 收藏
  • 关注

原创 【C++】STL 容器适配器—priority_queue 优先级队列

它提供了一种队列,其中的元素不是按照“先进先出”(FIFO)的顺序被处理,而是根据优先级:在任何时候,优先级最高的元素总是下一个被移除。第一个模板参数是要存储的数据类型,第二个模板参数是存储数据的底层容器,默认是vector,第三个模板参数是比较函数,用来定义优先级规则,用仿函数实现,默认是less,所以默认是大堆。我们想要用优先级队列存储自定义类型数据时,要提供仿函数,即比较的方法,如果每个自定义类型都写一个对应的仿函数是很繁琐的,这里就可以用模板的特化。返回优先级最高的元素的常量引用,也就是取堆顶。

2025-08-27 12:00:00 1160

原创 【C++】STL 容器适配器—queue 特性及实现+默认容器deque结构

它“封装”或“适配”了这个底层容器,只暴露符合队列操作的函数(如 push, pop, front),而隐藏了不符合队列理念的操作(如随机访问 [],在中间插入 insert)。缓冲区的大小通常由实现定义,可能与存储的元素类型大小有关(例如,可能是 512 字节 / sizeof(T) 后得到每个缓冲区能存放的元素个数)。queue 本身不是一个独立的容器,而是在某个底层序列容器(如 deque 或 list)之上提供了一个特定的接口。map 本身是一个连续存储的数组(例如,一个 T**),但。

2025-08-26 12:00:00 930

原创 【C++】STL 容器适配器—stack 特性+模拟实现

std::stack 是 C++ 标准模板库(STL)中的一个容器适配器,它提供了一种先进后出(FILO - First In Last Out)的数据结构,通常称为栈。不需要我们自己实现,因为成员变量只有一个底层容器,底层容器的默认构造会自动调用。因此 deque 是默认底层容器,当然我们也可以结合实际情况指定容器。判断栈是否为空,同样是调用底层容器的empty。出栈也发生在栈顶,调用底层容器的尾删函数。压栈发生在栈顶,调用底层容器的尾插函数。调用底层容器的取尾部数据的函数。

2025-08-25 16:00:00 789

原创 【数据结构】堆

优点缺点获取极值 O(1):快速访问最大/最小元素,就是取堆顶仅能访问极值:无法高效访问任意元素 (O(n))插入/删除极值 O(log n):高效动态维护不支持高效查找/删除任意元素 (O(n))建堆 O(n):高效构建不支持高效合并:合并两个堆通常 O(n)堆排序 O(n log n) 原地:空间效率高缓存不友好:数组存储,但跳转访问子节点可能导致缓存未命中Top-K O(n log K):空间占用小。

2025-08-24 12:00:00 1288

原创 【数据结构】二叉树

树是一种强大的非线性数据结构,用于表示层次关系。树形结构的强大之处在于其逻辑清晰和操作高效。二叉树是树的特殊形式,限制每个节点最多有两个子节点,且严格区分左子节点和右子节点。它是许多高效算法和数据结构(如二叉搜索树、堆、AVL树、哈夫曼编码)的基础。重要的类型包括满二叉树、完全二叉树、平衡二叉树和二叉搜索树。存储方式主要有顺序存储(适合完全二叉树)和链式存储(最常用)。遍历方式包括先序、中序、后序和层次遍历。由于二叉树链式结构的特点,我们的函数都是要递归实现的。

2025-08-23 12:00:00 776

原创 【数据结构】队列

pcur从队头开始遍历,pcur不为空说明还未越过队尾,就进入循环,释放掉pcur当前所指向的节点,这里要用 next 记录 pcur 下一个节点的地址,防止释放 pcur 后找不到下一个节点了。队列也可以用数组或链表的结构实现,使用链表的结构实现更优一些,因为如果使用数组的结构,出队是在数组头部出数据,还需要挪动数据,效率会比较低。注意要分清队列和队列的节点,队列节点是用来存储数据的,而队列是用来管理这些节点的。若队列有多个节点,则需要先记录第二个节点的地址,再释放+改变队头指针。(head) 进行。

2025-08-22 10:00:00 1101

原创 【数据结构】栈

栈(Stack)是一种操作受限的特殊顺序表,只允许在一端进行元素的插入/删除操作,这端叫做栈顶,另一端叫做栈底。它遵循后进先出原则(LIFO,Last In First Out),这意味着最后一个加入栈的元素,将是第一个被移除的元素。先判断参数接收的地址是否有效,再判断栈的容量是否足够,若足够,就直接插入。若不够,则扩容,容量为0则扩为4,不为0则扩为2倍,注意 realloc 的返回值是。的优先级相同,都属于最高优先级组,它们会按照从左到右的顺序进行计算,所以先访问到栈中的 arr,再通过下标访问元素。

2025-08-21 14:00:00 641

原创 【数据结构】链表

对于链表的增删查改,本质就是改变特定节点的next和prev指针的指向,因此只要画清楚图,理清逻辑关系 + 连接结点时执行操作的顺序,实现起来就可以得心应手本篇中我们介绍了双向带头循环链表,其他种类的链表与此是异曲同工的,甚至要更简单,因为对于链表的增删查改,本质就是改变特定节点的 next 和 prev 指针的指向欢迎大家来评论区学习探讨.

2025-08-20 12:00:00 1092

原创 【数据结构】顺序表

因为顺序表中有动态数组,是我们在堆上动态申请的内存空间,所以一个顺序表不用了时,应该把内存归还给操作系统,也就是销毁顺序表。接收一个顺序表的地址,将其初始化,一开始未开辟动态数组,也未存储数据,size 与 capacity 都为0。实际上要删除数组尾部数据,就直接让有效元素个数 -1 就可以了,这样就访问不到这个数据了,就相当于删除了。查找一个指定元素在一个顺序表中的位置,若顺序表中有,则返回它的下标,没有则返回 -1。的方式一个一个向后挪动数据,直至把数组第一个元素的位置空出来,时间复杂度O(n)

2025-08-19 15:00:00 1047

原创 【C++】STL 容器—list 底层剖析

但从我们的实现来看,operator-> 只是返回了节点中 _data 的地址,对应于这个情景中,调用 opeartor-> 只是返回了每个节点中结构体成员的地址,要访问到其中的数据,还需要一次 -> 才对。std::list 是C++中的双向链表容器,是用来管理节点的,所以节点的结构和list类要分开,这是一个节点的结构。报错是因为对AA*解引用,拿到的_data是AA结构体的一个对象,而AA这个结构体没有重载<<,因此无法用<<输出。要声明节点,普通迭代器,const迭代器,便于使用。

2025-08-16 14:00:00 605

原创 【C++】STL 容器—vector 底层剖析+迭代器失效详解+模拟实现

我们看到,即便函数体内修改了 pos,但因为是传值传参,修改不能被保存,所以出了函数体,pos 的指向未改变,此时 pos 就相当于指向无效空间,所以 *pos 报错,我们就说 pos 这个迭代器失效了。,发现连续的偶数删不完,这是因为删完第一个4后,要挪动数据,导致原来位置还有一个4,但此时迭代器已经自增,访问不到原来的位置了,迭代器失效。考虑如下情境,假设我们写了这样的一个erase函数,并且想用它删除一个vector中的偶数,可能会写出这样的代码,的值拷贝了,相当于拷贝了它们的地址,是一个。

2025-08-15 09:15:00 570

原创 【C++】string类的模拟实现

不缩容是因为缩容有风险,因为内存不能从中间位置释放,所以缩容实际上是开了一块新空间再拷贝,会消耗性能。注意const迭代器,const指的是这个迭代器指向的内容不能被修改,而不是迭代器本身不能被修改,所以要用。遇到\0就停止拷贝了,如果源字符串有多个\0,则会导致第一个\0后面的内容丢失。遇到\0就停止拷贝了,如果源字符串有多个\0,则会导致第一个\0后面的内容丢失。赋值重载我们实现的是深拷贝,这样会频繁地开空间又释放,效率太低了。都不包含\0,常量串的末尾也是\0,别忘了拷贝\0。

2025-08-11 10:30:00 714

原创 【C++】string 的特性和使用

auto是C++11引入的关键字,用于自动推导变量类型。注意当 reserve 的参数大于字符串底层总空间大小时,扩容,小于字符串底层总空间大小时不缩容。~string(),是string类已经写好的,而且在程序结束时会自动调用,没啥好说的。字符串的截取,其中str是源字符串,pos是开始截取的位置,len是截取的长度。这两种初始化方式的意义是不一样的,str1是直接构造,str2是隐式类型转换。迭代器是通用的遍历容器的方法,用原生指针或用封装原生指针的自定义类实现。其中比较重要的是1,2,4,6。

2025-08-09 20:00:31 702

原创 【C++】类和对象(下)(初始化列表;隐式类型转换;static成员;友元;内部类;匿名对象)

1. 性能优势(避免不必要的构造+赋值)public:String();// 默认构造// 参数构造// 赋值操作String str;public:// 方式1:构造函数体内赋值(低效)// 先默认构造,再赋值// 方式2:初始化列表(高效)Example() : str("Hello") {} // 直接调用参数构造方式1开销:默认构造 + 赋值操作(2次函数调用)方式2开销:直接参数构造(1次函数调用)2. 正确性保证(必须使用初始化列表的场景)

2025-08-07 14:00:00 645

原创 【C++】类和对象(中)(类的默认成员函数详解+运算符重载)

析构函数以波浪号~开头,后跟类名,没有返回类型和参数。

2025-08-06 11:30:00 741

原创 【C++】类和对象(上)(类和对象的基本定义和特性)

面向对象三大特性:封装,继承,多态。学习类和对象是实现这些特性的基础。类是用户定义的数据类型,允许将成员变量(属性)和成员函数(行为)封装在一个单元中,从而实现代码的模块化、重用性和可维护性。成员变量:存储对象的状态(如整数、字符串等)。成员函数:定义对象的行为(如计算、显示信息等)。定义在类里面的成员函数默认为inline。public:// 成员变量void display() { // 成员函数。

2025-08-05 12:00:00 781

原创 【C++】入门基础:引用,内联(inline)

因为默认是展开了,展开就没必要放到符号表里了,找不到函数地址,会发生链接错误。

2025-07-25 12:00:00 1513

原创 【C++】入门基础:命名空间域,输入&输出,缺省参数,函数重载

namespace定义的变量都是作用域都是全局,注意:这四个域都会影响查找规则,但是只有局部域和全局域影响生命周期,命名空间域和类域不影响生命周期。std::cout/std::cin:它们是系统提供的唯一标准I/O通道,是C++标准定义的全局唯一输出/输入流对象,使用时需要包含头文件。,std::cin是istream类的对象,std::cout是ostream类的对象,它们主要面向窄字符的标准输入/输出流。函数的返回值不同不能作为判断函数重载的条件!C++中常见的域有函数域,全局域,命名空间域,类域。

2025-07-24 12:00:00 714

原创 编译和链接

每一个源文件都会经编译器处理生成一个符号表,符号表是编译器或解释器在编译或解释源代码时使用的一种数据结构,用于存储程序中出现的各种符号信息。符号表的主要功能是记录符号的属性,如类型、作用域、内存地址等,以便后续的语义分析、代码生成和优化阶段使用。我们知道,C语言是高级语言,计算机能认识的是机器语言,即二进制指令,翻译环境的工作就是将高级语言翻译成机器语言。汇编器会解析每条汇编指令,将其映射为对应的二进制操作码。在编译和链接过程中,编译器生成的符号地址通常是临时的,需要通过重定位修正为实际运行时地址。

2025-07-17 15:40:11 968

原创 【C语言】结构体

这两种实现方式,print2更好,函数传参的时候,参数是需要压栈,会有时间和空间上的系统开销。如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。这是IP数据报的格式,其中很多的属性只需要几个比特位就能描述,这里使用位段,能够实现想要的效果,也节省了空间,这样网络传输的数据报大小也会较小一些,对网络的畅通是有帮助的。跟结构相比,位段可以达到同样的效果,并且可以很好的节省空间,但是有跨平台的问题存在。结论:结构体传参的时候,要传结构体的地址。

2025-07-16 15:02:36 1097

原创 数据在内存中的存储

对于E,E是一个无符号整数,但是我们知道科学计数法中指数是可以出现负数的,所以IEEE 754规定,存入内存时E的真实值必须再加上一个中间数,对于8位的E,这个中间数是127;例如,-7的二进制表示是-111.0,它对应S=1,M=1.11,E=2,二进制中 1.01 × 2^2 的"2"就像十进制中 1.23 × 106 的 “6”,指数位决定了数值的"数量级"。对于有符号的整数,它的二进制序列分为符号位和数值位,最高位是符号位,其余位都是数值位,符号位0表示正,1表示负。这样做可以节省一位有效数字。

2025-07-16 10:30:00 897

原创 【C语言】内存函数详解与模拟实现

函数 memcpy 从 source 的位置开始向后复制 num 个字节的数据到 destination 指向的内存位置。如果 source 和 destination 有任何的重叠,复制的结果都是未定义的。若 ptr1 中的值大于 ptr2 中的值,则返回大于0的数字,若 * ptr1 == * ptr2,则返回0。它和 memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的。memset 是用来设置内存的,将内存中的值以字节为单位设置成想要的内容。

2025-02-12 23:00:22 291

原创 【C语言】字符串函数的模拟实现大全

如果 source 指向的字符串的长度小于 num 的时候,只会将字符串中到 \0 的内容追加到 destination 指向的字符串末尾。该函数时将 source 指向字符串的前 num 个字符追加到 destination 指向的字符串末尾,再追加⼀个 \0 字符。查找 str2 是否在 str1 中出现,若是,则返回起始元素地址。五颜六色的生活,不能乱七八糟的过。友友们,你们很棒了,加油!

2025-02-11 09:00:00 560

原创 【C语言】指针5——回调函数

回调函数(Callback Function)是一种常见的编程模式,本质是将一个函数作为参数传递给另一个函数,并在特定事件发生、条件满足或任务完成后被调用。它的核心思想是 “由外部定义逻辑,由内部决定何时执行”,常用于异步编程、事件处理等场景。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。

2025-02-10 09:00:00 515

原创 【C语言】指针4——函数与指针

其中第一个 int 表示这个函数的返回值是 int 类型的,(int, int)表示两个参数的定义,* 表示 pf1 是一个指针变量,指向 Add 函数。如果我们要将函数的地址存放起来,就得创建函数指针变量咯,函数指针变量的写法和数组指针是非常类似的。这表示 parr 是一个存放着 3 个函数指针变量的数组,每个指针变量指向的函数,返回值是 int,参数是(int, int)思路:我们把函数的地址装到一个函数指针数组里,通过访问函数指针数组来调用不同的函数,所以相同的代码只使用一份便可以。

2025-02-09 09:00:00 1064

原创 【C语言】指针3——数组与指针(超级详解!包懂)

由前面的内容可知,arr[i] 可改写为 * (arr + i),我们刚刚分析了,arr 在这种情况下表示首元素地址,则 arr + i 表示的就是第 i 行的地址,每一行都是一个一维数组,因此arr + i,表示的是某个一维数组的地址,对它解引用,即 * (arr + i),就得到了这个一维数组。同理 arr[i] 应该等价于 * (arr+i),数组元素的访问在编译器处理的时候,也是转换成首元素的地址 + 偏移量求出元素的地址,然后解引用来访问的。&arr 取出了整个数组的地址,放到一个数组指针里去。

2025-02-08 09:00:00 1703

原创 【C语言】指针2——高级指针

const 在 * 的左边,说明 const 是用来修饰 *p 的,*p 不能被改变,保证指针指向的地址所存放的值不能通过指针来改变,但指针指向的地址是可以被改变的。因为 p 存放着 a 的地址,所以 p 的值是 0000009484F3FA14,解引用拿到 a 的值,所以 *p 是 5。因为 m 存放着 p 的地址,解引用拿到 p 的值,所以 *m 是 5,则再解引用,拿到 a 的值,所以 **m 是 5。所以我们使用指针前,先用 assert 断言检测指针的有效性,就可以避免野指针的出现。

2025-02-07 09:00:00 1550

原创 【C语言】指针1——基础(超级详解包懂)

计算机内存(Memory)是用于临时存储程序和数据的硬件设备,CPU可直接访问,是计算机运行时的核心工作区域。CPU处理数据时,从内存中读取数据,处理后的数据也会放回内存中。它是外存与CPU沟通的桥梁,所有程序的运行都在内存中进行。通俗易懂地讲,内存是程序运行的舞台,指针是操作内存的工具。

2025-02-06 09:00:00 881

原创 【C语言】扫雷(从零开始介绍扫雷游戏及代码实现,无递归)

今天从零开始介绍扫雷游戏及代码实现。

2025-01-27 10:13:49 1025

原创 【C语言】循环结构超级详解

虽然 goto 语句尽显神奇,但我们应该尽量避免 goto 语句的使用,goto 语句如果使用的不当,就会导致在函数内部随意乱跳转,打乱程序的执行流程。这个乘法表打印到n * 5就停止了,说明当j == 5时,break终止了本层循环,而外面的for 循环还在进行,所以打印 n + 1的乘法。我们学习了 while,for,do-while 循环,这三种循环往往会嵌套在一起才能更好的解决问题,亦即循环嵌套,上代码。不管当前循环还需要循环多少次,只要执行到了 break ,循环就彻底终止。

2025-01-19 18:11:47 1136

原创 【C语言】选择结构超级详解

比如火焰柚子不久前参加了C语言期末考试,如果火焰柚子的分数>=90,则会得到一个A,如果80<=分数<90,则会得到一个B,如果60<=分数<80,则会得到一个C。,所以实际上 else 是与第二个 if 匹配的,后面的 if-else 语句其实是嵌套在第一个 if 语句里的。在 if 语句中,若条件式为假,则跳过后面的语句1,执行下一条语句。而对于 if-else 语句,若 if 后的条件式为假则执行else后的语句2,执行结束后再顺次执行下一条语句。一个复合语句是包含在大括号之间的一个以上的语句。

2025-01-18 19:37:55 911

空空如也

空空如也

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

TA关注的人

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