自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 Linux如何设计一个线程池

这里的命名方式都是使用前_代表类内成员,我们将构造函数的参数设计的简单一点,方便后面实施,然后用_args代表要喂给线程的参数,_func代表回调函数。接下来负责写线程池,线程池中肯定要有一系列线程,还有一个队列用于拿任务,还要有一个互斥锁和条件变量。在设计线程池之前,我们可以对线程进行简单的封装这样子在线程池中就可以少一点调用接口,就像搭积木一样,一层一层的搭上去。线程池里面肯定要有线程,不过在此之前我们可以写一个Task的类方便后面测试,我这里写一个示例。这是一个简单的算术任务类。

2024-03-05 00:37:53 512

原创 C++进阶语法:异常

异常是面向对象语言中处理错误的一种方式,在C语言中当遇到错误时,我们有两种方式去处理1、返回错误码 2、终止进程。第一种方式,当我们调用函数堆栈很深时,我们就需要层层返回,很麻烦。下面来介绍异常的用法:先要知道,throw语句可以抛出任何类型的对象。这里要注意异常安全问题,就比如在前面new了一段空间,后面还没有delete就抛出异常了,就会导致内存泄露,所以一定要注意异常安全。下面来介绍一些公司会自己定义基类,让其他人去继承这个类,之后就只需要捕获这个基类就行。

2024-02-17 21:56:46 402

原创 C++:哈希表的哈希桶(模拟实现)

哈希捅和线性探测的区别就在于,哈希桶的结构体中的vector,存的是指针,而线性探测存的的是状态和信息。在这里不赘述哈希表的相关性质有兴趣的参考线性探测,这里直接贴代码。

2024-02-05 21:57:55 509

原创 C++:哈希表的线性探测(模拟实现)

哈希表的增删查改的效率很高,是O(1),比搜索二叉树要快很多。那么他是怎么实现的呢?他与计数排序有点相似就是通过映射的方式实现。不过在哈希表中不需要开这么的数据,它只需要开一部分空间然后使用除留余数法去实现,这个方法的缺点就是会导致哈希冲突很集中。并且哈希表是不能满的,因为哈希表要控制他的负载因子(负载因子 = 表中数据/表的大小 衡量哈希表满的程度。负载因子越大,增删查改的效率越低。一般负载因子在0.7左右开始增容。但是负载因子越小,浪费空间越多,以下是代码实现。

2024-02-05 21:55:31 388

原创 Linux下线程的部分接口的使用

创建一个线程太简单了。我这里给创建一系列进程的方式,这里不使用自己定义的缓冲区的方式,是因为会出错误,创建好一个线程以后,他的缓冲区的因为cpu速度的问题会直接变成最后一个。其中我还定义了一个返回的类,用于接受返回值,这里的返回值很有意思,他需要在外面定义一个指针,将指针的地址传进去,在再外面已知他的类型再强制他。这个接口我在上面也是用了,主要是用于回收PCB等内核资源的接口函数。这个接口用的少,取消了线程以后他会把返回码返回出来并且设置为-1。这个接口我在上面使用了和return一个原理。

2024-02-04 21:59:34 674

原创 Linux下对线程的理解(上)

要理解线程首先要理解页表和进程地址空间,我是这样子理解的,1、进程地址空间是进程访问资源的窗口。2、页表是规定进程地址空间中哪些属于进程。3、合理的使用进程地址空间+页表可以对资源进行划分。进程是接受OS分配的资源的实体。而进程就是cpu调度的最小单位(线程就是进程的一个执行流),在Linux下没有严格意义上的线程,他把所有的进程都划分为了轻量化进程。说通俗一点就是,进程一次会向线程申请一大堆空间,而线程负责在进程内部将拿到的资源各自划分,分成不同的执行流来完成任务。

2024-02-04 21:47:34 432

原创 在Linux中如何理解页表和进程地址

我们知道程序被加载到进程中,会产生相应的PCB,并且会有虚拟地址空间,虚拟地址空间通过页表就可以对应到物理内存中,这里我们以4g内存为例, 操作系统将地址划分为三个部分,前十个为页表的目录存的地址,中间十个是通过前十个找到的页表地址,后十二个记录的是对应的页表的物理内存的偏移量,其中物理内存会被分解为一个一个4KB的页帧,刚好就是2的12次方,也就是最后十二个比特位所能达到的最大地址。3、合理的对进程地址空间+页表进行资源划分,就可以对进程的资源进行分类。1、进程地址是进程读取资源的窗口。

2024-02-03 19:01:46 374

原创 Linux系统编程之信号(上)

生活当中有很多的信号,例如:上课铃声、发令枪等。从这些中我们可以提炼出三个点,1、我们必须要认识信号 2、我们收到信号会做出相应的动作 3、我们听到信号会在适合的时候去完成。在技术当中也是这样子,进程收到信号也会满足这三个条件。例如:当我们在Linux中写了一个死循环程序,这时需要按下ctrl -c 才可以暂停程序。所有的信号我们可以通过kill -l 来查看。

2024-02-02 21:20:29 327

原创 Linux系统编程之信号(下)

在聊这个之前首先要了解一些术语实际执行信号的处理动作称为信号递达(Delivery)信号从产生到递达之间的状态,称为信号未决(Pending)。进程可以选择阻塞 (Block )某个信号。被阻塞的信号产生时将保持在未决状态,直到进程解除对此信号的阻塞,才执行递达的动作.注意,阻塞和忽略是不同的,只要信号被阻塞就不会递达,而忽略是在递达之后可选的一种处理动作。

2024-02-02 21:20:22 476

原创 数据结构进阶:二叉搜索树

二叉搜索树的拥有很快的查找速度,查找的效率为O(logN),也就是说如果把全国的人放到二叉搜索树中,最多只需要31次就可以 找到你,这是一种很快的搜索方式,他还有两种模型一种是key模型,还有是key/value模型接下来我将一步一步的带你实现二叉搜索树,以key/value为例,首先是他的结点。最难的就是删除了,删除需要注意三个地方,如果左子树为空、如果右子树为空和如果左右子树都不为空。(很抽象,一定要画图!先把结点定义好,在写插入函数 (注意事项已经写进代码了)

2024-01-25 22:54:41 711

原创 C++进阶:多态(下)

多态之所以可以实现,主要是因为虚函数表的存在,虚函数表用于记录虚函数的地址,他是一个函数指针数组,在类中用一个函数指针数组指针来指向数组,子类继承了父类的虚函数表,当有重写的情况发生时,他就会覆盖掉重写的函数地址。可以看打印的东西就知道是8+8+4,其中还有一个函数在第一个虚表的下面。打开监视窗口会得到 ,继承下来的没有重写的函数,位置相同,虚函数表相同。单继承的虚函数表,以下是类的实现。多继承的虚函数表 (代码实现如下)

2024-01-23 22:28:55 639

原创 C++进阶:多态(上)

多态就是多种形态,去完成一个事情,不同的对象获得不同的结果。多态要实现的两个条件:1、被调用的函数必须是虚函数,且子类完成了其的重写。2、调用函数必须是父类的指针或者引用来调用,才能构成多态。具体用法如下:(一定要继承)在C++11中有两个关键字,一个是override一个是final 前者是用于检查子类的虚函数是否完成重写,后者用于这是最后一次继承,之后不想在被别人继承。

2024-01-23 22:13:17 424

原创 C++进阶:继承

继承就是可以复用class类或者struct类的代码!其中被继承的叫做基类或父类,继承的叫做子类或派生类。

2024-01-22 23:48:53 487

原创 C++进阶:模板进阶

模板的分离编译如果直接分离编译,当进行到链接的时候,编译器就会发现你给的定义的地址并没有演化出来的函数,所以在模板分离编译时需要将模板函数放在一起,如下图所示。在C++中我们一般使用模板参数来代替函数类型让编译器自己去演算具体的类型,除此之外还有非类型的模板参数,但是用的比较少,具体用法如以下所示。在一些特定的场景下,需要使用到的函数不能正确的演算出来的话,就需要考虑用模板的特化。用法很简单,要注意不能用于作为非类型模板参数的类型:1.浮点数类型 2.自定义类型。

2024-01-22 23:17:53 359

原创 Linux系统中进程的背景(只从数据层面和硬件层面分析)

从这个图我们可以看出cpu在数据层面不直接和输入输出设备打交道,只和储存器打交道,这里的储存器可以理解为内存,举一个例子:在发送信息的时候,输入设备就是我们的键盘,输出设备就是网卡,存储器就是我们的内存。管理的本质就是对数据进行管理,就像大学中的校长一样,它不需要见到你,只需要对你的数据进行管理就行。计算机也是如此,只需要对内容先描述后组织即先定义一个类,类中存放主要信息,再为类选择一种数据结构,对该类进行管理。操作系统中有分为内存管理、进程管理、文件管理和驱动管理其中驱动管理就是用于对硬件进行管理的。

2023-12-10 11:38:57 48

原创 进度条、git常见指令以及gdb的常用指令

进度条是笔者所接触的第一个更加贴近于系统的小玩意,主要是要理解回车、换行、换行回车和缓冲区的概念。回车是回到当前行的第一个光标位置,换行是换到下一行但是光标还在原来的位置,换行回车就是键盘上面的回车键是回到下一行的第一个光标位置,缓冲区是一个很小的区域用于缓冲即将输出或输入。我们所输入的东西都会先在缓冲区中,但是缓冲区并不是实施刷新的,这个时候就要用到一个函数fflush(标准输出流)补充知识:我们的电脑会自动打开标准输出流、标准输入流和标准错误流。

2023-11-19 14:26:31 245

原创 C++(适配器):stack和queue的底层实现,以及优先级队列和仿函数

下面来讲他的底层实现,底层可以使用很多容器去实现他比如vector、只需要注意这两个适配器都不允许遍历。他的底层实现主要是来自于一个新的容器deque(双向队列)这是一个集合了vector和list的优点的容器,仿函数主要是写一个类重载operator()(参数)函数,使得这个类的实例化对象可以像函数一样去使用,这就是仿函数,例如。优先级队列和普通队列主要的不同就在于,出的顺序。这两个类实例化的对象就是调整大堆和小堆的关键,他还在排序算法中被使用。,这样子方便弹出优先级高的数据,写一个堆主要是写。

2023-11-16 23:55:31 311

原创 每日一题:逆波兰表达式求值(后缀表达式)

这个题比较难理解的就是逆波兰表达式是什么东西,上面我贴了定义,这个题本身不难,只需要运用迭代器逐个访问,当为数字是存入栈中,是算符时就要取数出来进行运算,先取出的是右操作数,取出来以后用stoi来转化为整型。

2023-11-13 23:56:23 136

原创 list的const迭代器的实现

在这个迭代器类中,我们定义了三个模板参数,其中第一个是为了传递list存放数据的类型,接下来两个是为了定义接下来的const迭代器在通过list代码中我们可以知道const迭代器传了两个const对象过去,通过传const对象去获得const迭代器,并且通过返回值来是返回的也是const对象,这就是const迭代器的封装类。在这里面我用了三个模板参数去传递,这为之后定义const迭代器埋下了伏笔,接下来实现普通迭代器。接下来是实现list类。

2023-11-12 23:28:55 653

原创 vector的模拟实现和memcpy的深浅拷贝问题

要实现的接口有:构造和拷贝构造函数、析构、赋值运算符的重载、begin()、end()、reserve()、push_back()、pop_back()、insert()、erase()、operator[]、resize。首先要定义的是vector中的成员变量,这里我们使用迭代器去定义,这里可以方便后续的操作,且vector的迭代器底层实现就是指针,更加方便我们去使用,下面是成员变量,以及接下来遍历需要用到的一些接口定义完成员变量就要来遍历成员函数了我的习惯是先定义四个默认成员函数。

2023-11-09 19:42:37 563

原创 每日一题:只出现一次的数字I、II和III

这个题就难在这个要求 ,看题干我们可以知道,只有一个数出现了一次其他都出现了两次,我们可以考虑位运算,异或操作符,两个相同的数异或以后为零,这里遍历一遍数组,将所有的数异或,既可得到。

2023-11-07 23:40:06 182

原创 C++中的STL标准库的vector常见接口

STL中的vector类似于c语言中的支持动态增长的数组,我们现在先不讨论底层原理,下次文章再讨论vector的底层实现。我们可以分成多个测试函数,分别测试不同的接口,写一个test_vector1用于测试,构造函数,拷贝构造,赋值运算符,test_vector4(),用于insert和erase vector中没有头插头删,因为效率太低了。test_vector5()用于使用算法find和sort(底层实现是快排),用于删除想要删除的元素。其中test_vector2(),用于测试数组中的写权限。

2023-11-06 23:18:28 181

原创 STL中string类的简单模拟实现

默认函数成员函数中还有拷贝构造和赋值运算符重载没有写,他会默认浅拷贝,这里如果浅拷贝的话就会导致报错,因为浅拷贝也叫值拷贝,如果用字符串去拷贝构造的话,他们会指向同一个数据段的首字符,当调用析构函数时会释放两次,导致报错。在命名空间中再写测试函数test_string1,用于检测我们的构造函数是否正确,还要写一个获取大小的函数,用于遍历、析构函数用于释放空间避免内存泄露,[]是用于遍历,c_str用于返回c语言习惯中的字符指针。string类的简单模拟实现,不需要太复杂,这里主要考察的是深浅拷贝。

2023-11-04 23:19:24 566

原创 力扣热题一百道:环形链表

原题链接:https://leetcode.cn/problems/linked-list-cycle/description/?这个题只需要使用快慢指针就可以解决。

2023-11-04 00:00:11 33

原创 力扣热题一百道:移动零和盛最多水的容器(用c语言解题)

原题链接:https://leetcode.cn/problems/move-zeroes/description/?这个题目也是运用双指针的思路,定义左右两个指针,去分别找最大的两个数组,因为一开始就是从左右开始的这时的宽是最大的,只需要关注长的变化即可,与此同时,定义宏可以降低时间复杂度。这个题有两种思路,一个就是定义两个指针,一个快指针一个慢指针,当快指针走到非零时交换与慢指针的位置,再让慢指针走一步,快指针一直往前走。另一种思路就是覆盖零,遇到非零就覆盖前面的位置,后面的位置都置为零,

2023-11-01 23:43:37 166

原创 每日一练:反转字符串II和III以及找出字符串中第一个出现一次的数字

这里可以参考计数排序算法的思维,创建一个数组,用数字访问的方式遍历字符串,将得到的减去字符a,再作为数组的访问数,将该数加一,之后再遍历一遍数组,得到的第一个为一的就返回这个字符,如果走出这个循环,还没有返回,那就返回-1;这个题可以用类似于快慢指针的玩法,定义两个迭代器,让快的迭代器一直往前走走到空格时停下,在反转慢迭代器和快迭代器之间的所有字符,反转以后再将快迭代器赋值给慢迭代器,循环这个过程,知道慢迭代器等于结尾的迭代器。这个题目是简单的题目,只需要运用迭代器,将迭代器作为限制范围去解题即可。

2023-10-31 23:16:31 124 1

原创 每日一练:字符串相加与字符串相乘

这个题目算是上一个题目的进阶版本,有两种思路,一个是用num1个num2相加,另一个是用其中一个按照每一位进行分布相乘得到数相加,这里用第二种方式来解决。这个题限制条件说明了这个题只能通过字符串逐位计算,要从正常情况、特殊情况两个方向去思考,下面的代码中有注释。

2023-10-30 23:59:38 164 2

原创 C++:string类中的常见接口

s1 += ' ';//+=既可以尾插字符串也可以尾插字符s1 += s2;//写i++)s1[i] += 1;//读i++)这里就和数组的访问方法一样(最推荐)

2023-10-29 23:33:17 518

原创 c语言中比较容易忽视的点

1.sizeof(数组名)这个数组名代表整个数组的地址,计算的是整个数组的大小,单位是字节2.&数组名 这里的数组名是整个数组,取出的是整个数组的地址。允许指向数组指针与指向的元素的最后一个元素的后一个内存位置的指针进行比较,但是不允许与第一个位置之前的内存位置的指针进行比较。正数的三个码相同,负数的反码等于原码的第一位符号位不变,其他的反转(即1变0,0变1)补码就是把反码的最后一位加1。函数传参时要分清楚传的是什么,如果传的是数组、字符串,那么传的就是首元素的地址,应该用指针去接收。

2023-10-25 23:00:12 149 1

原创 cpp的初阶模板结尾和STL简介

STL(standard template libaray-标准模板库) 是c++库中的重要组成部分,他是数据结构和算法的软件框架。

2023-10-24 23:30:26 149

原创 每日一题剑指offer: 在o(1)时间删除链表结点

题目:给定单向链表的头指针和一个结点指针,定义一个函数在o(1)时间删除该结点。一般的思路肯定是定义两个指针,一前一后,当找到要删除的结点时,后面的指针再往后走一个,在数组中我们知道,可以用覆盖的方式去删除元素,在这里可以借鉴这个思路,使用覆盖的方式,然后再将前面的指针指向后面的指针,如下实现。但是时间复杂度是o(n),显然不符合题意。

2023-10-23 23:48:30 113 1

原创 cpp的内存管理和模板初级

在c语言中有malloc、realloc、free函数来进行动态内存上的管理,在cpp中产生了new,delete操作符来分配动态内存,为什么会出现new和delete呢,主要是因为cpp是面向对象的语言他需要更加规范的使用。接下来来分析new和malloc的区别。

2023-10-22 22:49:14 136 1

原创 cpp:类和对象中比较杂的知识(上)

除了类中的六个默认成员函数以外还有许多比较杂的知识,不方便以后的复习,所以笔者在这里记录下来方便复习。

2023-10-05 18:10:38 26

原创 c++入门:类和对象(上)

语言主要是分为面向对象和面向过程两种,c语言就是面向过程的语言,他关注的是过程,分析解决问题的步骤,通过函数调用去逐步解决问题。c++是面向对象的语言,他关注的是整个事件,所需要的对象,依靠对象和对象之间的互相联系去解决问题。

2023-09-28 22:31:15 93 1

原创 c++入门:类和对象的一小部分以及前言

关键字的使用,namespace所定义的空间可以定义变量,可以定义函数,主要是为了将标识符的名称进行本地化,避免名字污染和冲突。引用主要是在同一块区域命另一个名字,共用同一块空间,引用的底层是通过指针来实现的, 引用要注意在定义的时候就要初始化,一个变量可有多个引用,一个引用一旦确定下来就不会有其他实体。这里主要是因为c++中有独特的一套函数命名规则, 而c语言中没有,定义的是什么名字就是什么名字,具体可以Linux系统下面来看具体命名规则,我在这里不赘述。第三种就是引来用,这里所打印的就是10.

2023-09-27 22:13:18 113 1

原创 用c语言实现二叉树的遍历

该题是一个io型的题目,需要全部自己写,因为c语言没有树,所以需要自定义一个结构体来写出树的结点以及创建树、中序排列、销毁树三个函数。

2023-09-22 23:10:34 122

原创 剑指offer:平衡二叉树(初阶+进阶玩法)

原题链接。

2023-09-20 23:06:29 84 1

原创 剑指offer:最小的k个数(topk问题)

看到这个题的第一眼是不是想直接排序?但是一般排序的时间复杂度都是o(n²),想到堆排序时时间复杂度也有o(n*logn),还有一种办法就是制造一个N个数的堆每次pop一下堆顶的数据,这个的时间复杂度是o(n*logk),这个的时间复杂度也很高。在这里我们用一种时间复杂度相对较低的只有o(k*logn)。当要求最小的数的话我们建立的大堆堆顶就是下面k个数的最大值,如果外面还有比堆顶小的数就可以进来,在进行一次向下调整,在组件成堆。这个算法的时间复杂度相对较小。在这里要先建立一个为大小k的堆。

2023-09-19 22:18:43 80

原创 如何用c语言设计一个循环队列

原题链接;由于设计的是一个固定的队列所以我们选择使用数组来实现,首先先定义一个结构体需要包含指向数组的指针、队头指针、队尾指针以及数组大小四个变量。数组种总是要有一个空位置这样子才可以分辨数组是否为空或满。

2023-09-18 22:38:01 101

原创 剑指offer:合并两个排序的链表、链表中倒数第k个结点

这个题是属于比较简单的,代码自然而然的也会简洁很多,这个题可以考虑创建一个新链表,再利用双指针,来比较哪个小来进行尾插,不过这里要注意第一个位置需要单独进行头插,或者建立一个带哨兵的链表来一直尾插,这个题目也很简单,这里就可以引用快慢指针来进行操作定义一个快指针fast,定义一个慢指针slow快指针要比慢指针多走k步,这样子返回慢指针就达到要求了。

2023-09-15 22:29:59 87

空空如也

空空如也

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

TA关注的人

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