- 博客(126)
- 收藏
- 关注
原创 多线程同步
比如有两个进程A和B,它们共享一个固定大小的缓冲区,A进程产生数据放入缓冲区,B进程从缓冲区中取出数据进行计算,那么这里其实就是一个生产者和消费者的模式,A相当于生产者,B相当于消费者。
2024-09-18 02:06:50
758
原创 STL标准模板库
容器适配器:封装了一些基本的容器,使之具备了新的函数功能,比如把deque封装一下变为一个具有stack功能的数据结构容器分类:sequence Containers:顺序容器Associative Containers:关联容器一般底层是:红黑树带了multi的意思是:key值可重复unordered Containers:底层是是基于哈希表实现的,每一个元素是一个key-value对: 其内部,容量不足(超过了阀值)时,同样会自动增长。哈希表最大的优点就是。
2024-09-16 01:56:04
999
原创 IO多路复用
(1)同步阻塞IO 传统的IO模型。整个IO请求的过程中,用户线程是被阻塞的,这导致用户在发起IO请求时,不能做任何事情,对CPU的资源利用率不够。(2)同步非阻塞IO 默认创建的socket都是阻塞的,非阻塞IO要求socket被设置为NONBLOCK。 虽然用户线程每次发起IO请求后可以立即返回,但是为了等到数据,仍需要不断地轮询、重复请求,消耗了大量的CPU的资源。一般很少直接使用这种模型,而是在其他IO模型中使用非阻塞IO这一特性。(3)
2024-09-04 13:34:39
1345
原创 链接:动态库和静态库
-o不仅可以指定输出的可执行文件,还可以指定中间文件的输出要想程序能够被gdb调试,必须在编译时加上调试信息,也即是加上选项😄库的定义:😄在项目中使用库一般有两个目的:汇编后得到的主程序的.o文件和库文件通过链接得到最后的可执行程序要使用库一定是由三个部分组成:库文件、头文件、文档说明一般这个库本身就是函数的定义头文件就是函数声明例子:但是一定不能把main.cpp指定在自己定义的库文件之后静态库特点总结:动态库在程序编译时并不会被连接到目标代码中,而是在程序运行时候才被载入。动态链接库是程序运行时加载
2024-08-30 02:00:20
832
原创 三种智能指针
new出来的必须delete,不然内存泄漏,会导致程序崩溃delete后的内存不能再次使用不要对同一个内存多次deletedelete p;*p = 300;//释放之后使用会出错,最好置成NULL//p=NULL;new和delete都是运算符,不是函数。new和delete相比于malloc和free可以干更多事—在堆上分配一个对象时,new和delete会自动调用类的构造和析构函数也就是存在初始化能力,malloc和free没有这个能力😄A a;sizeof(a);
2024-08-28 18:01:59
937
原创 简单的Tcp服务器
源代码文件目录(src)这里有main.cpp,是服务器端程序头文件目录(include)各种.h文件实例程序文件目录(test)这里写一个客户端连接程序项目构建文件(Makefile)完成项目的编译。
2024-08-26 13:59:24
774
原创 基于赋值兼容的多态
甲乙丙三个班都是高二年级,他们有基本相同的属性和行为,在同时听到上课铃声的时候,他们会分别走向3个不同的教室,而不会走向同一个教室。和以前一样:构造时候调用自己构造函数前会调用基类构造函数,运行结束,程序会自动先析构派生类对象再析构基类对象。用派生类赋值基类,基类实现相同的虚函数接口,但是实现的是派生类覆写的功能。C++中的多态是指:由继承而产生的相关的不同的类,其对象对。虚函数是多态在运行时链接,但是内联函数是编译时候链接的。派生类的对象引用指针可以赋值给基类,但是基类只能访问。
2024-08-25 23:44:49
816
原创 Makefile简单使用
在含有Makefile文件下直接make就可以编译。这样增加了cpp文件连makefile都不用修改。每次-c都是链接成一个-o文件,最后把所有的。patsubst函数返回被替换过后的字符串。:显示指定路径下指定文件类型的所有文件。但是一般多文件都是用.o文件来链接的。链接在一起生成main。makefile编译。
2024-08-25 01:36:20
427
原创 右值引用+移动构造和赋值
在很多情况下会发生对象拷贝的现象,对象拷贝之后就被销毁了,在这种情况下,对象移动而非对象拷贝。 只有一个类没有自己的拷贝构造函数或拷贝赋值运算符,而且类的。这里这个临时对象就是隐式的,看不见,只是内部编译运行的逻辑是这样的。一般临时对象是看不见的,严格来说:obj并不算真正的临时对象。自己需要进行拷贝或者释放对象,系统默认要自己移动对象。,而且有些类都不能被共享资源,这些类型的对象**1个调用拷贝构造,1个调用移动构造,传参的区别。
2024-08-23 03:20:39
848
原创 c++ 继承
B继承A,C继承Bclass A{public:private:int x;//B继承Aclass B:public A{//公有继承public:showA();class C:public B{//公有继承public:showB();私有继承和保护继承都可以让派生类访问基类的非私有成员,但是私有继承会影响多次继承对基类的访问不管什么继承方式,派生类内部都不能访问基类的私有成员;不管什么继承方式,
2024-08-18 17:18:00
1076
原创 排序题+贪心
则:枚举1~nums[index]的所有可能,然后选择到达位置后,下一个位置的最远距离。这种情况是,遍历到下一个孩子之前,需要不断放弃尺寸小饼干,直至找到满足当前孩子胃口饼干后,接着遍历。把孩子和饼干按照升序排序,然后遍历孩子,如果孩子胃口值<=当前大饼干,就把饼干分配给他。不然的话,:也就是饼干小于胃口,放弃当前孩子,寻找下一个更小的孩子。遍历一次左一半数组,每次第一个不满足的j值,之前就是符合要求的。这样天然的满足i<j的条件,因为i在左一半数组,j在右一半数组。
2024-06-10 13:36:57
824
1
原创 BST+二分
第一个等于【1,4,4】等于的时候也要缩小r,如果r恰好在等于前一个位置时说明找到了,此时l==r然后运行一次,把l值+1即可int l = 0;//闭区间:[l,...,r]//等于时候也要缩小r才能找到第一个等于}else{//l值对应正确的结果return l;最后一个等于思路类似,只是要不断扩大l,使得l指向第一个大于目标值的位置int l = 0;
2024-04-22 01:37:56
1006
原创 static+单例模式+类的复合继承
handle类包含handleImpl类的指针,handle类的notify()只是一个接口,真正的实现是:handleImpl类的notify(),如果采用简单的浅拷贝,则两类中的两个指针将指向同一个地址,当对象快结束时,会调用两次析构函数,而导致指针悬挂现象。所以这时必须采用深拷贝。在对象复制时,只对对象中的数据成员进行简单的赋值,默认拷贝构造函数执行的也是浅拷贝。隐藏了声明类A的对象,因为由于包含的原因,类B已经有类A的对象的声明了。既然是包含关系,那么大的字节数是它包含的类的字节数加上自己的成员。
2024-04-17 02:28:57
1050
原创 记忆化搜索+堆+优先队列
结构上要求:必须是完全二叉树父节点大于等于孩子结点或父节点小于等于孩子结点堆有大顶堆和小顶堆两种类型也可以叫:大根堆,小根堆只有父子结点有数值上的关系,兄弟间大小无要求堆也可以用其他数据结构实现,用二叉树实现堆的性质的堆叫二叉堆二叉堆的本质----满足父子数值关系的一种完全二叉树堆:从根到叶子的一条路径满足单调性是包含在头文件中基本操作:top()访问对头元素empty()队列是否为空size()返回队列内元素个数push()插入元素到队尾,并排序emplace()
2024-04-12 02:52:13
621
原创 回溯dfs和分支限界bfs
所以递归参数需要数字i,表示当前访问的第i个数字。用map记录字符串,第一次出现的就是最小的,用map存储后,后续不同位置变化出的相同字符串的层数不会更新。这里要从边界出发,从四周的O出发,把所有相连的O找到做好标记,这些O是不能被替换成X的。,那么对于每个点进行上下左右遍历,只要值大于它,也就是满足了单调递增的条件,就指向它。每一次都从图中删除没有前驱的顶点,这里并不需要真正的删除操作,通过设置入度数组。每一轮都输出入度为 0的结点,并移除它,同时修改它指向的结点的入度(−1-即可)
2024-03-30 02:33:50
1111
原创 图和树的路径问题
这里需要存储三个元素:节点,路径和余下值,由于pair是二元组,存储三个元素要么pair复合使用,要么使用tuple。0—>10->15->18->16----找和为1,看sum-target在mp中是否存在。本题就是,每次增加一条边,然后对图进行遍历,当新加入的边使得图成环,则该边为所求。这里:起点不同,但是必须是在自己的子树下面查找,也就是更换根,然后借助函数去找路径。0—>10->15->18->21----21-10就是:5->3->3。下图:绿色是父节点,红色是当前结点,紫色背景代表结点以访问。
2024-03-22 22:51:36
1086
原创 分治算法和树
解法一:利用map记录二叉树的所有结点的父节点(该题无重复元素),然后把其中一个结点的路径用set记录下来,那么遍历另一个节点时,只要相遇(就是该节点第一次遍历到上一个结点走过的,也就是set记录过),则该点就是所求点。区别就在于判断的是当前结点的孩子结点是否为x,避免NULL->val,需要先判断存在。:递归或迭代地将原问题分解为各个的子问题(性质相同的、相互独立的子问题)比如对于5:5的父节点是9,9的父节点是7,组成路径:597。子问题之间是没有重叠的,互相没有依赖,可以被独立解决。
2024-03-15 02:22:27
940
原创 递归与回溯2
比如{1,2,3}中{1,3}和{3,1}是重复的,所以元素只能以该元素为起点,向后递归,不能往前选。但是组合规定了个数,只要在结果处存储正确的符合条件的结果即可,在所有路径提前剪去不符合要求的。这里是传入新变量,当然也可以用ans,但是需要pop_back(),防止影响结果。也就是变动原数组,选择一个就把自己的选择去掉,然后递归,回溯的时候补上元素。是隐式递归结束变量,也可以单独用一个参数,但是要注意。当然也可以用减法实现,size==0一样可以结束递归。分为排列,子集,组合,后一种分别是前一种的子集。
2024-03-02 20:07:30
993
原创 字符数组+自定义string类+lambda+for_each//find_if
public://构造函数,带有默认参数0//拷贝构造函数:没有返回值,而且参数是本类对象的引用//拷贝赋值函数:重载运算符=,返回值类引用//返回类私用成员函数//析构函数private:char *cstr;按值捕获的外部变量,其值都是在lambda中之前的值auto m = [=]() -> string{//有返回值,()不可省//c100这里是5而不是10,因为5被赋值了改成&后,值是修改后的。
2024-02-27 18:15:51
883
原创 递归与回溯(一)
发现迭代写法的特点,每次for的时候都会放入当前下标的值nums[下标],然后for结束前,也就是内层循环回退到外层循环时,都需要pop也就是放弃已选的元素。则n=2的可能:{1,1},{1,2},{1,3},{2,1},{2,2},{2,3},{3,1},{3,2},{3,3}如何放弃重复的元素不选,也就是直接跳过这次结果,方法:设置标记,如果标记后,for不执行本次结果。[1,2,3] 的子集可以由 [1,2] 追加得出,[1,2] 的子集可以由 [1] 追加得出。
2024-02-26 21:50:31
884
原创 哈希+set+map
散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度映射函数叫做散列函数存放记录的数组叫做散列表一般选用模N取余来获得要插入的位置对不同的关键字可能得到同一散列地址,即k1≠k2,而,这种现象称为冲突一般有拉链发和开放定址法来处理冲突//map按key降序,set降序排列//key可以重复mp[val]++;//输出集合set//输出映射map。
2024-02-20 02:06:05
1069
原创 双指针和单调栈
sort()第三个参数可以自己自定义,注意函数要用bool返回值,而且传参时不要加()int age;//按姓名升序//按年龄降序//迭代器初始化数组指针初始化stu + 1stu + 4参数的函数无括号sort(vec.end()cmp_age。
2024-02-09 02:47:03
865
原创 前缀和与差分
给定一个数组nums,其差分数组diff就是第一个元素不变,其余:diff[i]=nums[i]-nums[i-1] ( i>=1)为了不用分类讨论,一般设置前缀和数组第一个元素为0,这样:nums[0]=pre[0+1]-pre[0]可得到。发现对原数组需要进行[l,r]的操作,但是在差分数组只需要对l和r+1位置做出改变,这样在效率上会提高。设S[i,j]是(0,0)位置到(i,j)位置的和,a[i,j]是(i,j)位置上的值。注意:[i,j]之间的和:包含j且j最大的和-不包含i且i-1最大的和。
2024-02-04 17:42:06
965
原创 指针数组与数组指针
由于普通类型int,double没有指向首尾字符的指针,需要借助end(),begin()函数。然后定义一个类型为数组的指针指向它:int* (*parr)[]=&arr;动态数组区别于静态数组,其不具备begin(),end()操作。p)[m]=new int[n] [m] 这里:n就是。首先得存在一个元素类型是指针的数组:int* arr[]数组元素的类型 (*指针名)【】=&数组名。元素数据类型为 int* 的数组 int*[ ]首先: int (*p)[数组元素个数]=数组名。
2024-01-21 01:35:11
476
1
原创 服务器基本框架+两种事件驱动模型
主线程执行数据读写操作,读写完成之后,主线程向工作线程通知这一”完成事件“。那么从工作线程的角度来看,它们就直接获得了数据读写的结果,接下来要做的只是对读写的结果进行逻辑处理。主线程只负责监听文件描述符,有事件发生就把读写事件放入请求队列,由工作线程负责读写数据,接受新的连接,处理客户请求。但是数据的收发不一定在 I/O 处理单元中执行,也可能在逻辑单元中执行,具体在何处执行取决于。**有两种高效的事件处理模式:**Reactor模式和Proactor模式。实现 Reactor 模式,异步 I/O 模型。
2023-03-31 10:57:37
322
原创 线程的概念+线程函数API
1:进程最大的优点:独占内存空间(虚拟内存实现);也同时带来最大的缺点:切换进程开销大效率低,数据共享困难2:多进程间的通信的本质:通过os来传递数据3:线程的实现目的:并发多线任务;线程不可以脱离进程独立存在4:线程有自己独立的线程号,错误号,task_struct结构体,切换状态和函数栈(局部变量)5:线程库不再由操作系统提供6:c中注册为线程控制函数后就立即启动,c++,,java需要启动函数7:pthread_exit:线程退出;pthread_join:回收线程资源;
2022-12-02 14:30:16
1089
原创 信号量的使用
1.信号量用于资源保护,可以实现同步或互斥2.信号量本质,通过加锁,让通信双方得知操作状态3.信号量使用:semget()创建;semctl():SETVAL设初值;semop():pv操作;semctl(,0,IPC_RMID)4.同步,时间顺序,一般涉及多组二元信号量
2022-11-25 18:28:14
1766
原创 ipc----共享内存
1.共享内存就是OS在物理内存中开辟一大段缓存空间,直接使用地址来读写缓存2.实现思想:让各自进程空间与开辟出的缓存空间建立映射关系3.使用shmget(ftok生成的key,指定shm的大小,0664|IPC_CREAT);shmat(shmId,NULL,0);则返回映射地址 shmdt(shmaddr); shmctl(shmId,IPC_RMID,NULL);
2022-11-23 15:25:41
863
原创 System V IPC+消息队列
system v ipc,不同于管道是内核以文件形式操作,是内核提供的全新API。一定有个类似文件标识符的ipc标识符。消息队列:双向链表,每个节点:消息编号+内容通信过程:先封装一个msgbuf的消息包,然后接收发送注意api:msgget(),msgsnd(),msgrev()
2022-11-21 18:44:17
1017
2
原创 套接字+网络套接字函数+客户端大小写程序
sockaddr_inhtonl,htonsC/S模型socket()bind()listen()connect()accept()
2022-11-20 22:31:01
515
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人