- 博客(307)
- 资源 (4)
- 收藏
- 关注
原创 B+树的原理图解
B+树是B树的变体,也是广泛应用于数据库和文件系统中的一种自平衡的树形数据结构。与B树不同的是,B+树所有的键值都保存在叶子节点中,内部节点仅作为索引使用。这种结构使得B+树在查找、范围查询等操作中比B树更加高效。
2024-10-17 12:47:07 1306
原创 B树的原理与CPP实现
B树是一种自平衡的多叉树数据结构,广泛应用于数据库系统和文件系统中。其设计初衷是为了在存储设备上实现高效的读写操作,特别是在磁盘存储或其他大规模存储场景下。B树的每个节点可以有多个子节点,这与二叉树不同,B树能有效减少树的高度,从而减少数据检索时磁盘的I/O操作次数。本文将详细介绍B树的性质,以及它的查找、插入和删除操作。
2024-10-17 12:46:40 1392
原创 布隆过滤器的原理
布隆过滤器(Bloom Filter)是一种用于检验某个元素是否在集合中的概率性数据结构。它由布隆于1970年提出,具有很高的空间利用效率,但其结果存在一定的不确定性:要么说明该元素肯定不在集合中,要么说明该元素可能在集合中。因此,它经常用于需要快速检索但允许小概率误判的场景。
2024-10-16 18:17:52 983
原创 跳表的原理与cpp实现
8+4+2=n-2。如果每两个结点会抽出一个结点作为上一级索引的结点,那第一级索引的结点个数大约就是 n/2,第二级索引的结点个数大约就是 n/4,第三级索引的结点个数大约就是 n/8,依次类推,也就是说,第 k 级索引的结点个数是第 k-1 级索引的结点个数的 1/2,那第 k级索引结点的个数就是。:从最高层开始,如果该层中存在目标节点,则将其从链表中删除,更新前驱节点的指针,使其指向目标节点的后继节点。实现,在实现的时候,每层节点并不是一个结构存储的,而是一个节点就是一个结构存储,类似下面这个图。
2024-10-16 13:52:33 1059
原创 无锁队列实现(Michael & Scott),伪代码与c++实现
c++的实现就直接看上述的伪代码跟着实现即可,这里的一些atomic操作也可以看我之前写的博客。可以看到,多线程下可以顺利的插入与找到数据。
2024-10-16 13:51:38 389
原创 C++中的六种内存序详解
C++11中的内存序(Memory Order)为开发者提供了工具,帮助控制多线程程序中不同线程之间的内存操作顺序,从而避免由于编译器或处理器优化导致的指令重排问题。这些内存序提供了从无序到严格一致的内存访问保证,让程序员能够在性能和安全性之间进行权衡。本文将详细介绍C++中的六种内存序,并通过实际例子补充说明它们的应用场景。
2024-10-14 15:00:39 713
原创 C++11中的原子操作及其底层缓存一致性
C++中的原子变量通过无锁的原子操作来保证多线程环境下的线程安全,并提供多种内存顺序模型供开发者根据需求进行性能调优。使用原子变量可以有效避免数据竞争,并简化多线程编程中的同步问题。
2024-10-14 14:03:19 1576
原创 c语言位域详解
位域是一种可以让结构体的成员变量以位为单位进行存储和操作的特性。位域允许我们精确控制数据的存储方式,而不像普通的整型变量那样固定使用系统规定的字节大小。通过位域,我们可以在一个整型数据中指定具体的位数来表示某些信息。比如,如果我们只需要一个变量的某些位来表示状态,我们可以用位域来减少存储空间。位域操作看上去很好,但是其实处处受限,其跨平台性很差,使用时应该谨慎。
2024-10-09 18:56:20 586
原创 使用双向链表和哈希表实现LRU缓存
通过以上的实现,我们可以看到LRU缓存可以通过双向链表和哈希表的结合高效实现。双向链表用于维护缓存项的顺序,哈希表用于快速查找缓存项。每次访问或插入时,都将对应项移动到链表的头部,而当缓存超出容量时,淘汰链表尾部的最久未使用数据。这种设计使得LRU缓存的查找插入删除操作都能在 O(1) 时间内完成,非常适合在高频率数据访问场景下使用。
2024-09-27 17:58:57 1215
原创 快速选择算法--无序数组中寻找中位数 O(n)的算法及证明
快速选择算法有点类似于快速排序,可以帮助我们快速找到数组中的第k个元素。但是快速排序的时间复杂度是。最差时间复杂度就可以看做每一层选择的值都很差,都需要和剩下的n-1个值比较。这就很简单,没什么说的了,只需要注意如果数组为偶数需要求两个数的平均值。排序的算法是最容易想到的,但是即使是快排,平均复杂度也只有。2、将数组分为三个部分,小于基准,等于基准,大于基准。其中k是递归深度,直到n变为1。1、随机选择一个元素作为基准。为什么快速选择算法就是。
2024-09-27 17:09:44 975
原创 系统在哪些情况下会触发缺页中断
这意味着当程序访问某个内存地址时,如果该页尚未被加载到物理内存中,则会触发缺页中断。当程序再次访问这些已被交换到磁盘上的内存页时,会发生缺页中断。操作系统会将这些页从磁盘交换回物理内存。这时,如果该内存页尚未映射到物理内存,操作系统会触发一个缺页中断,并将对应的页映射到物理内存。当一个程序尝试访问一个虚拟内存地址,而该地址没有映射到物理内存(即该地址没有分配有效的物理内存页),操作系统会发生缺页中断。如果程序试图访问一个被标记为只读或禁止访问的内存区域(例如,写入一个只读页面),也会触发缺页中断。
2024-09-19 21:32:37 509
原创 C++中move和forword的区别
move用于将一个对象的资源所有权从一个对象转移到另一个对象,以避免不必要的复制。它是一种类型转换,表示你希望将一个对象视为一个右值,从而可以被“移动”而不是“复制”。forward用于完美转发模板参数。它确保在将参数传递给其他函数时,保留参数的值类别(即是左值还是右值)。这对于实现通用函数模板尤其重要。
2024-09-19 20:53:39 456
原创 多个线程如何轮流输出1到100
当线程需要等待某个条件变成真时,它会获取一个互斥锁,然后在条件变量上等待,等待期间会自动释放互斥锁。另一个线程在满足条件后会获取相同的互斥锁,并调用条件变量的 notify_one() 或 notify_all() 函数来唤醒等待的线程。是用于线程间协调的强大工具。这个面试问题主要考察如何让线程同步,首先线程同步必会用到的就是互斥锁,互斥锁保证多个线程对数据的同时操作不会出错。(条件变量)是 C++11 中提供的一种多线程同步机制,它允许一个或多个线程等待另一个线程发出通知,以便能够有效地进行线程同步。
2024-09-07 15:20:01 525
原创 C++内存泄露检测-Windows平台VLD
我们复制出来的vld文件,CmakeLists.txt,以及我们的程序main.cpp。第二部分是函数调用栈,可以看到在我们的代码中发生泄露的地址是main()+0xA的地址。第二部分是函数调用栈,可以看到在我们的代码中发生泄露的地址是main()+0xA的地址。安装过程就一路next即可,如果自定义安装目录的话,需要记住安装的目录,默认目录。然后我们在相同的文件路劲下创建build文件夹,用来存放编译过程的中间文件。第三部分是发生泄漏的内存的值,现在全部被覆盖为CD。,这个目录下的三个文件夹。
2024-08-14 17:11:27 531
原创 C++哪些变量在没有显式初始化的情况下会被初始化为0
首先,我们需要明白C++程序编译链接后会包含以下几个主要段(Section)。.text.data.bss.rodata.dynamic.plt.got.symtab.strtab从上述的编译后分段就可以看出来,只有BSS段的内容会被自动初始化为0,那么C++中的哪些数据会再编译链接后放入BSS段呢?就是全局变量和静态变量。
2024-08-14 09:57:33 307
原创 为什么父类的析构函数要定义为虚函数
在C++中,通过基类指针或引用访问派生类对象时,如果基类的析构函数不是虚函数,那么在删除基类指针时,只会调用基类的析构函数,而不会调用派生类的析构函数。这可能导致派生类中特有的资源没有被正确释放,从而引发资源泄露。
2024-07-12 14:22:12 508
原创 容器是线程不安全的,如果多线程下不加锁直接使用容器会发什么
这种情况下,容器的内部状态可能会被破坏,从而导致未定义行为。例如,容器的内部指针或迭代器被破坏,导致非法内存访问,从而引发段错误(Segmentation Fault)。由于多线程竞争条件的不可预测性,程序可能表现出随机性错误。某些情况下,错误可能不会立即显现,但在特定条件下可能会触发。中添加元素时,如果没有适当的同步,可能会导致内部数组的重新分配和指针失效。容器的内部数据结构可能会被多个线程同时修改,从而导致数据不一致。可以看到这里是引发了访问冲突,其实这种行为即使是重复也会出现不一样的结果。
2024-07-12 14:02:49 354
原创 delete删除new[]创建的数组会发生什么
举个例子class Tpublic:int main()delete p2;return 0;这段代码只会执行数组中第一个对象的析构函数,后面的对象就会有发生内存泄露的风险。比如后面的对象申请了一块内存,此时这块内存就再也收不回来了。运行一下,会报warning。
2024-07-12 13:38:10 541
原创 C++ 中多态的实现原理-虚函数表详解
编译时多态(Compile-time Polymorphism):也称为静态多态性,是在编译时确定的多态性。C++中的函数重载和模板(Templates)是编译时多态的例子。函数重载允许定义多个同名函数,但它们的参数列表不同,编译器根据参数类型或个数来决定调用哪个函数。模板允许编写通用的代码,以适用于不同类型的数据。运行时多态(Run-time Polymorphism):也称为动态多态性,是在运行时确定的多态性。C++中的虚函数和继承是运行时多态的例子。
2024-05-16 18:50:49 1265
原创 C++11 新特性 常量表达式 constexpr
为了解决常量无法确定的问题,C++11在新标准中提出了关键字constexpr,它能够有效地定义常量表达式,并且达到类型安全、可移植、方便库和嵌入式系统开发的目的。
2024-05-15 17:47:44 522
原创 C++11新特性 lambda表达式
lambda表达式是现代编程语言的一个基础特性,比如LISP、Python、C#等具备该特性。而C++在C++11标准才正式支持lambda表达式。
2024-05-12 21:20:11 850
原创 C++11新特性 右值引用详解
C++引入右值引用以及与之相关的移动语义和完美转发,C++的语义变得更加丰富和合理,与此同时它的性能也有了更大的优化空间。对于这些优化空间,C++委员会已经对标准库进行了优化,比如常用的容器均已支持移动构造函数和移动赋值运算符函数。
2024-05-11 15:50:01 847
原创 C++指针常量和常量指针的区别
常量指针是定义了一个指针,这个指针指向一个对象,不能通过常量指针来修改这个对象。指针常量是指定义了⼀个指针,这个指针的值只能在定义时初始化,其他地⽅不能改变。
2024-05-11 15:48:16 307
原创 Linux中的日志系统简介
在的Linux系统上使用的日志系统一般为rsyslogd。rsyslogd守护进程既能接收用户进程输出的日志,又能接收内核日志。
2024-05-10 10:04:34 1110
原创 Linux网络编程(四) 同时处理一个端口的UDP与TCP连接
服务器如果要同时监听多个端口,就必须创建多个socket,并将它们分别绑定到各个端口上
2024-05-09 13:30:10 412
原创 Linux网络编程(三)IO复用二 poll系统调用
GNU为poll系统调用增加了一个POLLRDHUP事件,它在socket上接收到对方关闭连接的请求之后触发。poll系统调用的返回值,成功时返回就绪(可读、可写和异常)文件描述符的总数,如果在超时时间内没有任何文件描述符就绪,select将返回0。由XOPEN规范定义。fds参数是一个pollfd结构类型的数组,它指定所有我们感兴趣的文件描述符上发生的可读、可写和异常等事件。成员告诉poll监听fd上的哪些事件,它是一系列事件的按位或;
2024-05-08 09:43:44 884
原创 Linux网络编程(三)IO复用一 select系统调用
I/O复用使得程序能同时监听多个文件描述符。需要指出的是,I/O复用虽然能同时监听多个文件描述符,但它本身是阻塞的。并且当多个文件描述符同时就绪时,如果不采取额外的措施,程序就只能按顺序依次处理其中的每一个文件描述符,这使得服务器程序看起来像是串行工作的。如果要实现并发,只能使用多进程或多线程等编程手段。
2024-05-08 09:42:46 1161
原创 Linux网络编程(一) 网络基础
向一个TCP连接写入数据时,内核中的TCP模块首先把这些数据复制到与该连接对应的TCP内核发送缓冲区中,然后TCP模块调用IP模块提供的服务。UDP则不同,UDP是不可靠的服务,当一个UDP数据报被成功发送之后,UDP内核缓冲区中的该数据报就被丢弃了。其工作原理是:主机保存了一份IP地址和MAC地址的映射高速缓存,先从表中查询,查询不到的话,主机向自己所在的网络广播一个ARP请求,该请求包含目标机器的网络地址。各层协议依次处理帧中本层负责的头部数据,以获取所需的信息,并最终将处理后的帧交给目标应用程序。
2024-05-07 14:55:42 1567
原创 Linux多线程(三) 线程池C++实现
我们使用线程的时候就去创建一个线程,这样实现起来非常简便。但如果并发的线程数量很多,并且每个线程都是执行一个时间很短的任务就结束了,这样频繁创建线程就会大大降低系统的效率,因为频繁创建线程和销毁线程需要时间。线程池就是为了让线程可以复用,不在线程的创建和销毁上浪费时间。线程池主要分为三个部分任务就是函数与参数组成的结构体。
2024-04-27 19:38:06 568 1
麦克风阵列资料.zip
2020-09-06
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人