- 博客(116)
- 收藏
- 关注
原创 【C++笔记】异常与智能指针
其实在C语言阶段我们就接触过异常了,例如C语言中的assert断言判断程序错误以及errorno异常编号。而C++中把异常设计成了一个类,如果要使用C++中的异常,就要引入exception这个头文件:这个头文件中就是C++标准库提供的异常类的实现。当然,在实际应用中,一般都不是在try的代码块中直接抛出异常,可能是在try的代码块中调用了某些函数,而这些函数内部出现了异常,则直接在函数内部抛异常也是可以的。
2024-03-29 23:42:16 861
原创 【Linux笔记】进程间通信之管道
大家在学习C++的时候可能听说过空间配置器,也可能听说过进程池,但可能并不真正理解这些到底是个什么东西。通俗的理解,我们可以将进程池理解成一个内存储备库。我们在学习C语言的时候用过malloc,学习C++的时候用过new,它们两个的作用都是申请一块内存空间供用户使用。而且我们也知道操作系统是内存的管理者,所以分配内存资源的工作只能有操作系统来做,而我们要访问操作系统只能通过系统调用。那么如果我们要频繁使用malloc或new来申请空间,难道是每次都要调用系统调用吗?
2024-02-14 01:33:57 1220
原创 【Linux笔记】动静态库的封装和加载
我们在学习C语言阶段其实就已经知道一个可执行程序的形成过程分为预处理、编译、汇编、链接这四个阶段,而且也知道我们程序中使用的各种库其实是在链接的阶段加载的。可我们那时候并不知道库是怎么被加载的,或者库是怎么形成的,所以今天我们就要好好的来聊一下,库的形成。
2024-02-10 00:21:05 1387
原创 【Linux笔记】文件系统与软硬链接
硬连接和软连接其实和他们的名字一样,只是起到了一个“链接”作用而已。先来看软连接:如果我们想要在系统中创建一个软连接,可以用ln -s指令:然后我们可以像使用原test.txt文件一样使用test.soft,对它们两个其中任意一个的任何操作都是一样的:我们可以看到,对于它们两个中任意一个写入,两个文件中的内容都是一致的,那这是不是说明他们两个是同一个文件呢?
2024-02-06 22:50:52 1255
原创 【Linux笔记】缓冲区的概念到标准库的模拟实现
缓冲区”我们简单的理解就是一个数据暂存库,当我们要将数据从一个地方传送到另一个地方的时,可以先将数据暂存到这个暂存库中,等时机到了再将数据传送到目标地点。这就好比我们生活中的快递站,当我们要把一个东西送给另一个人时,就可以先将数据放到快递站,快递站到了时间就会发货,以送往目的地。而我们的操作系统会为每一个被打开的文件创建一个缓冲区。
2024-02-04 21:38:05 1424
原创 【C++笔记】C++11一些重要的新特性
C++11第一个比较好用的特性就是”列表初始化",它可以大大的节省我们初始化对象的时间(特别是对象数组),虽然有些地方用起来有点儿奇怪,但是总的来说利大于弊。
2024-01-20 22:45:17 1045
原创 【刷题之路Ⅲ】LeetCode 827. 最大人工岛
我们在枚举0的上下左右四方方向时,如上图左边和下边相邻的岛屿是同一个,这就重复计算了,所以我们还得用一个哈希表来记录每个0格子累加过的岛屿编号,从而避免重复计算。我们可以在bfs的过程中对每个岛屿进行编号(其实是对一个岛屿的每个格子都编号),然后用哈希表来记录每个岛屿编号对应的面积。开始时先对每个岛屿进行编号并统计面积,然后在枚举数字为0的格子,计算与它相邻(上下左右四个方向相邻)的岛屿的面积。右上角和左下角的两个0的相邻岛屿其实是同一个,如果这种重复相邻的岛屿很多的话,很可能就会超时,
2024-01-14 16:10:00 515
原创 【Linux笔记】自定义一个简单的shell
在Linux中,有一些命令是一定要父进程来执行的,不能由子进程来执行,这些命令就被称为“内建命令”。就拿上面所提到的“cd”命令来说,它的本质是程序的工作目录发生了改变,之后执行任何指令都是在这个工作目录下执行。那它就必定不能交给子进程来执行,因为子进程一执行就退了,所以就算子进程的工作目录改变了也没用。所以"cd"命令一定要是父进程执行。Linux中其实有很多的内建命令,今天我们实现的是一个简易的shell,所以我这里只实现三个:cd、export,echo。
2024-01-13 17:48:06 1123
原创 【Linux笔记】进程等待与程序替换
execl这个接口可以为我们执行进程替换的工作,所谓的进程替换其实并不是创建新进程,而是将进程的代码和数据替换:它的第一个参数表示你要替换的进程的路径+文件名,而后面的可变参数列表则表示你想要怎样执行这个进程,因为各种进程执行所对应的执行选项不同,所以这里需要用可变参数列表,需要注意的是在可变参数列表的最后,一定要传一个NULL,表示参数传递完毕。先拿我们最常用的“ls”这个指令来演示:这样我们就可以在我们自己写的C语言代码中调用我们系统的指令了。然后我们再来看一个现象:
2024-01-12 15:54:36 1020
原创 【C++笔记】红黑树封装map和set
好像这样确实已经可以了,但是我们不能忽略了一个重要的问题,map中存的是一个键值对pair,而我们在插入或查找的时候进行比较都是只针对pair中的K的,也就是pair中的first成员,那pair本身重载的比较方法是否也是只针对fist呢?同理在向上走的过程中,只要遇到当前节点是其父亲的右孩子的情况,其父亲也一定是被遍历过的,只有遇到当前节点是其父亲的左的情况,才说明其父亲是没有被遍历过的。我们知道中序遍历的顺序是“左中右”,并且是递归的形式进行的,所以对于每一个节点都会先去遍历它的左子树。
2023-12-01 22:01:10 225
原创 【C++笔记】红黑树的简易实现
红黑树本质上也是一颗搜索二叉树,但它在搜索二叉树的规则上有新添了一些额外的规则,使得它比普通的搜索二叉树甚至是AVL树的性能更好。红黑树是一棵搜索二叉树,它的每个节点上增加了一个存储位来表示每个节点的颜色,颜色要么是红色要么是黑色。并且树中没有连续的红色节点,且红黑树中确保没有任何一条路径长度会大于其他路径的两倍。1. 每个结点不是红色就是黑色2. 根节点是黑色的3. 如果一个节点是红色的,则它的两个孩子结点是黑色的(即没有连续的红节点)
2023-11-29 21:18:52 366 1
原创 【C++笔记】AVL树的模拟实现
/ 定义AVL树节点int _bf;// 平衡因子// 构造,_val(key),_bf(0){}// AVL树public:// ……
2023-11-13 18:21:49 300
原创 【C++笔记】二叉搜索树的模拟实现
如果我们想要将新的节点连接上parent,要执行parent->_right = cur,这其实是将cur放到parent->_right指向的 **“空间”**,也就是要用到parent->_right的 **“左值”**(**“左值”表示空间,“右值”表示数据**)。
2023-11-12 18:11:17 391
原创 【C++笔记】优先级队列priority_queue的模拟实现
优先级队列可能听名字就能想到它的功能,就是按优先级排的队列。可他到底是个什么呢?它的底层有时由什么实现的?我们可以先翻翻文档看看:从文档中我们也可以看出它其实也是一个类模板。其中的Container这个模板参数是一个容器适配器,默认使用vector作为其底层存储数据的容器。其实优先级队列在底层就是我们以前学过的堆,它在vector上使用了堆heap的算法将vector中元素构造堆的结构,默认情况下是大堆。
2023-11-11 21:30:58 338
原创 【Linux笔记】Linux环境变量与地址空间
如上图,其实我们在运行我们自己所写的程序时候也可以传入一些参数,而系统会将我们呢传递的这些参数以空格为分隔,将它们转化成字符串放入argv数组中,然后我们就可以在程序中打印出这些字符串了,而第一个字符串是程序的名字,这是怎样都会存在的。我们知道,父子进程的代码是共享的,而数据是个自有一份的,并且观察以上的结果我们可以推断出变量的值不一样,说明进程中的变量绝对不是同一个变量。其本质目的就是为了操作系统能直接找到对应的软件或者指令,也可以理解成是在操作系统环境中的一个变量,所以操作系统能直接的找到它。
2023-11-09 19:39:20 327
原创 【Linux笔记】Linux进程概念与进程状态
进程(Process)是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。进程是被加载到内存中的程序,或者运行起来的程序就叫做进程。
2023-11-02 17:00:26 787 1
原创 【C++笔记】C++多态
在编程语言和类型论中,多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。多态类型(英语:polymorphic type)可以将自身所支持的操作套用到其它类型的值上。计算机程序运行时,相同的消息可能会送给多个不同的类别之对象,而系统可依据对象所属类别,引发对应类别的方法,而有不同的行为。简单来说,所谓多态意指相同的消息给予不同的对象会引发不同的动作。多态也可定义为“一种将不同的特殊行为和单个泛化记号相关联的能力”。多态可分为变量多态与函数多态。
2023-10-29 19:14:07 582
原创 【C++笔记】C++继承
C++是支持多继承的,也就是一个类可能会存在多个直接父类,例如下面这个例子:他们之间的继承关系如下图所示:而如果这些关系再复杂一点儿,就会变成“菱形继承”了:在这样的继承状态中,处于中间的A、B两个类是没有什么问题的,问题就出在最下面的C这个类:从代码中我们并不能看出问题出在哪里,我们得到监视窗口中才能看出:从内存中我们可以看到c1中竟然存了两个_o(一个是A继承的,一个是B继承的),这也就是为什么报错提示访问不明确的原因。
2023-10-24 20:44:31 518
原创 【C++笔记】模板进阶
也就是说我们在Stack.cpp中所写的可以比作一个骨架,从中只能得到这个函数的实现逻辑,所以在编译Stack.cpp的时候并不能生成具体的函数地址,这样main函数在调用的时候就自然找不到了。这其中的原因是因为函数模板比普通函数多了一个步骤:实例化,因为函数模板其实和具体函数其实是一个一对多的关系,一个函数模板可以实例化出很多个功能相近但参数和返回值类型不同的函数。但这种方法并不是一种很好的方法,因为它每一次只能解决一种类型,而且每一种类型都得要显示声明一次,这会是代码用于。直到C++20版本才引入。
2023-10-19 20:04:02 315
原创 【Linux笔记】Linux基础权限
将权限掩码002转化成二进制为:000 000 010,按位取反后为:111 111 101,所以和普通文件的默认权限110 110 110 和目录文件的默认权限111 111 111 按位与后就得到了110 110 100和111 111 101,也就是664和775。新建一个文件的权限其实是默认权限减去该用户的权限掩码,也就是将权限掩码中有的权限减去。如上图举例:该文件的拥有者对该文件有读写和执行权限,所属组有读和执行权限,其他人有读和执行的权限(‘-’ 就表示该用户没有对应的权限)。
2023-10-19 09:19:04 221
原创 【C++笔记】C++ list类模拟实现
但在开始实现构造之前,我们必须先得实现一个“空初始化”,因为我们设计的链表是带头结点的,并且这个头结点是不算入有效数据的。因为链表的哨兵头节点是私有的,并且链表也不支持随机访问(不能实现方括号重载),所以我们遍历链表的方式就只剩一种——迭代器。对于其他容器而言,链表的拷贝构造我想是最简单的了,因为它的空间本身就不连续,也就不必申请新的一段连续的空间再拷贝数据了。因为链表的空间不是连续的,所以我们就不能直接用原生指针来模拟了。因为我们所写的是带头链表,所以在list类里就只需要顶一个头节点和size即可。
2023-09-19 17:48:39 260
原创 【C++笔记】C++STL vector类模拟实现
start就是指向的数据段开始位置,但是_finish却是只指向的最后一个有效数据的下一个位置,这也是为了之后我们插入数据的时候更方便,也符合了迭代器的要求。随机删除判断pos位置是否合法就和insert不一样了,这里的判断是pos不能大于等于end(),因为end()即是_finish,而_finish指向的是最后一个有效数据的下一个位置,这个位置并不是有效数据的位置。所以我们这里使用的是依次使用赋值的方式就行拷贝,因为库中的自定义类型是一定重载了赋值运算符的,也一定是进行深拷贝的。
2023-09-10 15:58:19 239
原创 【C++笔记】C++string类模拟实现
也就是’\0’的位置:然后循环操作_str[end + 1] = _str[end],并让end–直到end与pos重合为止。
2023-09-09 09:22:10 295
原创 【C++笔记】C++内存管理
在C语言中我们需要动态申请空间的时候我们通常都是用malloc函数,但是malloc函数对自定义类型是没什么问题的,但是对于自定义类型就不那么适用了。如果是像栈这样的有额外申请空间的类,没有初始化这将是一件很危险的事情,因为我们后面向栈中插入数据的时候就一定会出错(野指针)。我们会发现其实里面还是用到了malloc和free的,至于其他的那些看不懂的都是跟异常现相关的。我们现在可以不理会。所以为了解决这样的问题,C++就设计了套新的动态内存申请的方案,即new和delete。
2023-08-29 19:46:09 405
原创 【C++笔记】C++之类与对象(下)
初始化列表是每个成员定义的地方,所以有了初始化列表之后,在就如构造函数的函数体之前就会去走初始化列表,然后再去走函数体。我们通过调试就可以看出:事实上,不管你写不写每个成员都要走初始化列表,这个我们可以通过为成员加上缺省值来验证,因为成员的缺省值就是给初始化列表用的:可以看到,虽然我们并没有在初始化列表里面写上_month的定义,但是当走到_day的定义的时候,_month就已经定义成了我们所给的缺省值了。这就说明了_month其实也走了初始化列表。
2023-08-27 22:36:44 334
原创 【C++笔记】C++之类与对象(上)
既然类是结构体的“升级”,那么内在结构体中定义的东西也一定能在类中定义,所以类中能定义的包括:各种变量:数组:还有枚举和结构体等等:几乎可以定义所有的东西:但C++的类除了可以定义以上这些东西之外,还一个定义一个类独有的东西:“成员函数”,有了成员函数,我们在管理结构体中的各个成员的时候就可以更方便,而不需要每写一个函数就需要传参。例如栈这个类的初始化:这是因为类划分了一个“类域”,在成员函数被调用的时候,就回到类中去寻找各个变量,这就不需要我们老是传递参数了。
2023-08-15 20:47:35 285
原创 【C++笔记】C++启航之为C语言填坑的语法
缺省参数还有一点需要注意的是,缺省参数不能声明和定义同时给:这样做的目的主要是为了防止声明和定义给的缺省值不一致,从而导致调用存在歧义。
2023-08-08 15:25:40 311
原创 【数据结构】由完全二叉树引申出的堆的实现
关于“堆”,百度百科上是这么说的:——————————引自百度百科由上面可知,我们可以将堆理解成一个数组,也可以理解成一个完全二叉树。其实由于完全二叉树的特殊性,其本身就可以使用一个数组来存储。在之前的二叉树的实现中,我们已经知道完全二叉树的最后一层的叶子节点一定是连续的:而之所以完全二叉树能用数组存储,是因为完全二叉树的以下这些性质:对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对若i>0,i位置节点的双亲序号:(i-1)/2;
2023-06-04 17:49:16 422
原创 【刷题之路Ⅱ】LeetCode 739. 每日温度
而当遍历到的温度大于栈顶下标对应的温度时,我们需要连续地将栈顶下标取出,记为index,连续的当前遍历到的温度是否大于index所对应的温度,如果大于就将栈顶下标弹出栈,并将答案数组的answer[index]赋值为i - index。时间复杂度:O(n),n为数组长度,我们需要顺序遍历一遍数组,而每一个下标最多也只有一次出栈和进栈的机会,故总的时间复杂度还是O(n)。空间复杂度:O(n),最坏情况下,n - 1个温度都会累积在栈中,故空间复杂度为O(n)。这样但我们遍历完了数组,我们的答案也就出来了。
2023-06-02 15:39:11 872 3
原创 【数据结构】难度上一个台阶的二叉树实现
树”在现实生活中大家都知道是什么,但在计算机界中却另有所指,指的是一种数据结构。树是一种数据结构,它是由n(n≥0)个有限节点组成一个具有层次关系的集合。把它叫做“树”是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:每个节点有零个或多个子节点;没有父节点的节点称为根节点;每一个非根节点有且只有一个父节点;除了根节点外,每个子节点可以分为多个不相交的子树。————————————————引自百度百科一个节点含有的子树的个数称为该节点的度;如上图:A的为6。
2023-06-01 20:49:06 767
原创 【刷题之路Ⅱ】LeetCode 1823. 找出游戏的获胜者(约瑟夫问题)
确切地说,从第 i 名小伙伴顺时针移动一位会到达第 (i+1) 名小伙伴的位置,其中 1
2023-05-31 13:16:16 998 1
原创 【刷题之路Ⅱ】迷宫问题升级版——找最短路径
也是因为可能存在多条通路,所以我们在某一条路上头不通或者体力消耗尽了。当我们往回返的时候还需要将这些走过的坐标再改成可通行的坐标,就如下面的这个用红圈圈起来的坐标:我们发现红色和绿色的两条路都经过了这个坐标,而红色的那条是走不通的(体能不够),而如果我们在红色的那条路上往回返的时候没有吧走过的坐标再改成可通行的坐标,那到后面在走绿色那条路的时候就没法在通过红圈圈的这个坐标了,那我们也就找不到可行的通路了。好了,这就是这些就是这一题的重点思路了,剩下的就是代码实现了。
2023-05-29 18:43:01 1906 1
原创 【刷题之路Ⅱ】百度面试题——迷宫问题
我们在GetPath函数里递归调用上下左右四个方向的找通路,如果当前被调用的坐标等于出口坐标就可以返回,而主要上下左右有任何一个方向的递归调用找到了通路就可以返回(同时最重要的是要先判断坐标的有效性)。:因为这里是io型的oj题,所以我们没必要在main函数中最开始就将栈初始化,如果是接口型的oj题,就一定要在main函数中先将栈初始化,不然最多只能过一个测试用例。它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的路线。
2023-05-28 20:26:01 1194
原创 【刷题之路】LeetCode 2073. 买票需要的时间
所以当第k个人买完票时,如果他们中的每一个最多能买到的票数为tickets[k] - 1,而如果小于tickets[k] - 1,那就能买完。而如果他要买的票数大于或等于第k个人需要买的票数,那么在第k个人买完票时他能买到的票数也和第k个人的相同。那么在第k个人买完票的时候,其他的所有人能买到的票数,也即买票的时间也就已经确定了(包括买完票和未买完票)。有题目所述我们得知,每个人买到的票数即是每个人所花的时间,所以我们可以先统计完每个人所花的时间,然后再算出这些事件的总和,最后返回这个总和即可。
2023-05-28 17:51:32 799 4
原创 【刷题之路】LeetCode 面试题 03.02. 栈的最小值
我们可以借助一个辅助的栈minStack,来存储当前栈中最小的值当我们每次执行push时候,就相应的将当前栈中最小的值也入到minStack中。既然题目应经明确要求了,min操作的时间复杂度必须为O(1),那我们想用遍历的方法来找到最小值的想法也就不现实了,那我们应该怎样解决这个O(1)的问题呢?而当我们执行Pop弹栈操作时,则需要让Stack和minStack同步弹栈,以确保在任何情况下minStack的栈顶元素都为Stack中的最小值。--> 返回 -3.--> 返回 -2.
2023-05-27 16:49:37 1099 1
原创 【刷题之路】LeetCode 1700. 无法吃午餐的学生数量
给你两个整数数组 students 和 sandwiches ,其中 sandwiches[i] 是栈里面第 i 个三明治的类型(i = 0 是栈的顶部), students[j] 是初始队列里第 j 名学生对三明治的喜好(j = 0 是队列的最开始位置)。因为队列的规则是先进先出,所以我们每次只能知道队头学生喜欢的三明治类型,而不能知道具体每个学生的喜好,而且根据题目描述队列的长度有可能时时在变化,所以我们也不能单纯的统计个数。的个数为队列长度的学生都不喜欢栈顶的三明治。
2023-05-27 14:29:58 1509
原创 【刷题之路Ⅱ】LeetCode 622. 设计循环队列
但又因为单链表的局限性,我们不能直接找到rear的前驱。其实很简单,我们可以使用(rear - 1) + (k + 1)对k + 1取余,正常情况下rear - 1 > 0的时候,加上一个k + 1在对k + 1进行取余其实对结果没什么影响,而当rear - 1= -1时候,加法也就变成了减法,所以就变成了k对k + 1取余,其结果是k,正好是最后一个下标。设计你的循环队列实现。而取队尾这个接口就不同了,因为我们设计的rear是指向队尾元素的下一个元素,所以我么其实要返回的是rear的前一个位置的元素。
2023-05-16 18:06:40 468 1
原创 【刷题之路Ⅱ】LeetCode 475. 供暖器
故合并的复杂度为O((n+m)logn)。如上图,题目中描述的场景大致如上图所示,假设地平线就是一根数轴,那么在这些数轴的坐标上分布着一些房子和供暖器,这些房子可能包围着一些供暖器,也有可能同一个坐标上同时有房子和供暖器,而这些供暖器也有可能不在房子的范围内。如上图所示,离坐标为3的房子最近的是坐标为0的供暖器,那么对于下一个坐标为5的房子,离它最近的房子就只有可能是坐标为0的供暖器或者在坐标为0的供暖器右端的供暖器,这里很明显就是在在右端的坐标为7的供暖器。解释: 在位置1, 4上有两个供暖器。
2023-05-16 09:43:03 338
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人