- 博客(37)
- 收藏
- 关注
原创 Linux篇:网络基础1
②TCP/IP五层(或四层)模型:(物理层、)数据链路层、网络层、传输层、应用层(像这样的网络协议栈命名为TCP/IP协议栈)。②协议分层:软件分层最典型的表现是:在结构体或类的设计上,做数据结构层面的分离/用回调函数的方式,在软件的逻辑上进行分层。b.几乎任何层的协议都要在报头中提供决定将自己的有效载荷交付给上层的哪一个协议的能力(报文的分用)。⑤交换机:划分碰撞域,防止报文在更大的局域网中扩散,有效降低数据在局域网中碰撞的概率。①协议是双方的约定,最终的表现形式就是具有特定字段的结构体对象。
2024-02-13 17:48:17 1852
原创 算法篇:贪心算法
再根据k-m的奇偶性(偶数直接忽略,奇数则挑选当前数组中最小的数,变成负数)。②从左往右,找到第一个递减的位置,从这个位置向前推,推到相同区域的最左端,使其减小1,后面的数全部修改成9。①状态表示:dp[i]表示:以i位置的信封为结尾的所有的套娃序列中,最长的套娃序列的长度。状态表示:dp[i]表示:以i的位置的元素为结尾的所有子序列中,最长递增子序列的长度。(x:标记%3=1的尽可能小的数,y:标记%3=2的尽可能小的数)存什么:所有长度为x的递增子序列中,最后一个元素的最小值。①每次处理一批相同的数。
2024-02-02 23:43:21 714
原创 算法篇:递归、搜索与回溯算法
②怎么实现:添加一个备忘录,把结果放到备忘录里面,在每次进入递归的时候向备忘录里查找一下。80%可以用前者的思考方式,但有些题用暴搜的时间成本太高了(暴搜只是为我们确定状态表示提供方向)。不是的,只有在递归的过程中,出现了大量的完全相同的问题时,才能用记忆化搜索的方式优化。②带备忘录的递归 vs 带备忘录的动态规划 vs 记忆化搜索?②从头开始的任意一个字串,左括号的数量>=右括号的数量。①所有的递归(暴搜、深搜),都能改成记忆化搜索吗?①左括号的数量=有括号的数量。
2024-02-02 23:29:46 1194 2
原创 Linux篇:线程
每个线程的库级别的tcb的起始地址叫做线程的tid,线程库维护的tid其实是在库中地址空间的一个描述结构体的虚拟地址,而LWP是管理底层轻量级进程的执行流(用户级执行流:内核LWP=1:1)。①输出型参数(输出thread id),②线程的属性(一般置为nullptr),③函数指针(让新线程执行传入的回调函数), ④创建线程成功,新线程回调线程函数的时候,需要参数(这个参数就是给线程函数传递的)。运行的时间越短,串行的比率降低,在临界区中线程也可以被调度,临界区的代码越短,线程被调度的概率也越低。
2024-01-26 14:10:46 985
原创 算法篇:动态规划II
匹配一个,但不舍去→dp[i][j]=dp[i-1][j]→dp[i-2][j]→dp[i-3][j]......有s1[i],有s2[j]→s1[i]==s2[j]→dp[i][j]=dp[i-1][j-1]+s1[i]选i→dp[i][j][k]=dp[i-1][j-g[i]][max(0,k-p[i])] j>=g[i]综上:dp[i][j]=max(dp[i-1][j],dp[i][j-v[i]] +w[i])→匹配一个,然后保留→p[j-1]=s[i]&&dp[i-1][j]
2024-01-10 23:18:12 1018
原创 算法篇:动态规划I
dp[i][j] = min(dp[i][j+1],dp[i+1][j])-d[i][j],由于最低健康点数为1,故dp[i][j]=max(1,dp[i][j])。③初始化:f[0][0]=-prices[0] g[0][0]=0 f[0][1]=f[0][2]=g[0][1]=g[0][2]=-0x3f3f3f3f。长度大于一:if(s[i-1]+1==s[i]||s[i-1]=='z'&&s[i]=='a') dp[i]=dp[i-1]设j为最后一个单词起始位置的下标(0
2024-01-09 01:57:26 1756
原创 Linux篇:信号
虚拟机在进行除零错误的时候,一段程序崩溃,对应的当前目录下会产生一个临时文件xxx.core,而默认云服务器上面的core功能是被关闭的(保证服务重启的功能一直有效,会形成code dump文件来冲击磁盘,影响服务)。b.键盘在硬件上可以给CPU发送硬件中断,每一个中断都有中断号,通过各中断单元向CPU特定针脚发送中断后,CPU会保存相应的中断号,从而完成了键盘向CPU,通知其数据已就绪的任务(显示器,网卡等设备同理)。导致节点丢失,内存泄漏。当我们的进程从内核态返回到用户态的时候,进行信号的检测与处理。
2023-12-15 12:56:22 1076 2
原创 Linux篇:进程间通信
创建共享内存/消息队列时,操作系统就要创建对应的数据结构,并将第一个字段的地址填入数组(结构体数据类型可以不一样,因为第一个字段的类型都一样)。同一个文件是内存级的,每个文件都存在自己的缓冲区,如果双方想向自己的缓冲区中写入,子进程就可以通过缓冲区读取,实现进程间通信。④当然,也可通过用户输入的key,找到每一个对应的ipc资源,通过比较第一个字段的ipc_perm中的key,确认进程是否已经被创建(新旧)。申请和释放PV操作——原子的:一件事情要么不做,要做就做完(两态的),没有“正在做”这样的概念。
2023-12-07 22:04:09 1365
原创 Linux篇:文件系统
文件的内容是有偏移量的!inode:inode结构体,包含单个文件的所有属性(inode number,文件类型,权限,引用计数,拥有者,所属组,ACM时间,int blocks[NUM]等),大小是128字节(一般而言,一个文件,一个inode)(文件文件名不在inode保存)。Group Descriptor Table(不会在每个组都存在):描述整个分组基本的使用情况:一共有多少个组,每个组的大小,每个组的inode数量,每个组的block数量,每个组的起始inode,文件系统的类型与名称等。
2023-11-26 20:05:48 2366 2
原创 Linux篇:文件管理
直接或者间接包含如下属性:在磁盘的位置,文件基本属性(权限,大小,读写位置,打开者),文件的内核缓冲区信息,struct file *next指针,引用计数count,文件描述符表,对应打开文件的缓冲区字段和维护信息。所以,只要拿着文件描述符,就可以找到对应的文件。程序替换并不影响文件访问!由此观之,文件描述符表的分配规则为:从0下标开始,寻找最小的没使用的数组位置,它的下标就是新文件的文件描述符。1、所有操作计算机的动作,都是以进程的形式进行操作的,所有访问文件的操作,最终都是由进程来访问文件的。
2023-11-25 13:11:14 1127 1
原创 Linux篇:进程控制
子进程main函数的返回值表征当前进程退出结果是否正确,此退出码将来会被父进程获取,通过该退出码决定子进程任务完成的好坏,如果执行失败,父进程则有其他策略。环境变量在不断给自己的每一个子进程下沉的时候,每一个子进程可以给自己定义put属于自己的环境变量,put后的环境变量会被后续的子进程再继承。wait调用会回收僵尸,释放内存泄露问题,wait调用,如果子进程不进行退出,Wait父进程也就不会返回,会一直等待,直到子进程退出。基本原理:新的可执行代码和数据,替换原先的代码和数据,并从零开始执行。
2023-11-08 01:20:01 131 2
原创 Linux篇:进程
3、任何一个进程,在加载到内存的时候,形成真正的进程时,操作系统要先创建描述进程(属性)的结构体对象PCB(process control block)---进程控制块(进程属性的集合)。②增加进程虚拟地址空间可以让我们访问内存的时候,增加一个转换的过程,在这个转化的过程中,可以对寻址记请求进行审查,所以一旦异常访问,直接拦截,该请求不会到达内存,保护物理内存。创建子进程PCB,填充PCB对应的内容,让子进程和父进程指向相同的代码,父子进程都是有独立的task struct,可以被CPU调度运行了。
2023-11-05 11:46:41 139 1
原创 C与C++的文件读写
每个被使用的文件都在内存中开辟了一个相应的文件信息区,用来存放文件的相关信息(如文件的名字,文件状态及文件当前的位置等)。sprintf:把格式化的数据,存放在(转换成)一个字符串。ferror-返回真,就说明是文件在读取过程中出错了,而结束。feof-返回真,就说明是文件正常读取到了结束标志而结束的。fseek:根据文件指针的位置和偏移量来定位文件指针。③格式化输入函数 fscanf(适用于所有输入流)stdout - 标准输出(屏幕)类型:FILE*rewind:让文件指针的位置回到文件的起始位置。
2023-10-21 12:35:25 91
原创 特殊类设计
一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。①构造函数私有化,在该类中声明,在类外定义一个自己类型的静态对象(不要直接定义一个该类的全局对象,因为类外面是调不了构造函数的)。1.同上将构造函数私有化,(但是不能将拷贝构造私有化,因为栈的传值返回需要调用拷贝构造)。①构造函数私有化,在该类中声明,在类外定义一个自己类型的静态对象指针并置空。2. 提供一个静态的成员函数,在该静态成员函数中完成堆对象的创建。
2023-10-17 20:07:09 91 2
原创 异常与智能指针
3.)C++中异常经常会导致资源泄漏的问题,比如在new和delete中抛出了异常,导致内存泄漏,在lock和unlock之间抛出了异常导致死锁,C++经常使用RAII来解决以上问题,关于RAII。1. 异常会导致程序的执行流乱跳,并且非常的混乱,并且是运行时出错抛异常就会乱跳。4. C++标准库的异常体系定义得不好,导致大家各自定义各自的异常体系,非常的混乱。抛出异常对象后,会生成一个异常对象的拷贝,因为抛出的异常对象可能是一个临时对象,1、C语言传统处理错误的方式:终止程序,退出函数,返回错误码。
2023-10-16 00:26:12 91
原创 C++11特性
错误写法如上,返回值是ret的别名,而ret正常销毁,不会将ret识别成将亡值(只有传值返回才会触发编译器的优化)(引用返回只要不是在栈区上均可)。2.)对于拷贝构造和移动构造对象而言,emplace_back是直接构造了,push_back是先构造,再移动构造。ret2:编译器也进行了优化处理,把str识别成了右值--将亡值,先移动构造,再移动赋值。str(左值)先拷贝构造(深拷贝)后移动构造(浅拷贝),Func的返回值是右值。连续的构造/拷贝构造,合二为一,编译器把str识别成右值--将亡值。
2023-10-14 21:37:06 98 3
原创 STL篇:哈希原理以及实现
不扩容,不断插入,某些桶越来越长,效率得不到保障。解决方式:闭散列开放定址法:当前位置被占用了,按规则找下一个位置(占用别人的位置)但是会引发哈希冲突碰撞不同的值可能会映射到同一个位置,值和位置是多对一的关系。3、哈希表不能满了再扩容,控制负载因子(0.7~0.8)到一定值就扩容。负载因子越小,冲突概率越小,空间利用率越低(空间浪费越多)1、载荷/负载因子=填入表中的元素个数/散列表的长度。负载因子越大,冲突概率越大,空间利用率越高。1、直接定值法(值的分布范围集中)2、除留余数法(值的分布范围分散)
2023-09-24 21:37:35 293 2
原创 STL篇:搜索二叉树,AVL树和红黑树的模拟实现
更新后parent平衡因子=0,说明parent所在的子数的高度不变,不会再影响祖先,不用再继续(沿着到root的路径)往上更新。更新后parent平衡因子=-1/1,说明parent所在的子数的高度变化,会影响祖先,需要继续(沿着到root的路径)往上更新。更新后parent平衡因子=-2/2,说明parent所在的子树的高度变化且不平衡,对parent所在的子树进行旋转,使之平衡。b.左右子树高度之差(简称平衡因子)的绝对值不超过1(平衡因子=右子树的高度-左子树的高度)b.黑色节点占比>=1/2。
2023-09-17 10:40:52 279 4
原创 Linux篇:开发工具
如果我们修改了原文件,历史上曾经还有可执行,那么原文件的最近修改时间,一定要比可执行程序要新!只需要比较,可执行程序的最近修改时间和源文件的最近修改时间:.exe新于.c源文件,不需要重新编译,.exe老于.c源文件,需要重新编译。xxx.o:可重定位目标二进制文件,简称目标文件,obj文件。多文件时操作时,底行中vs打开多个文件编辑窗口,窗口光标切换,光标在哪一个窗口里面,就对哪一个窗口进行操作。3、在Linux中,如果按照静态链接的方式形成可执行程序,需要添加static选项,提供静态库。
2023-09-09 16:22:52 214 4
原创 Linux篇:权限
有的时候我们多个用户想进行文件数据的共享,我们所创立的共享文件不能在任何一个人的家目录下。sudo command:对一条指令进行暂时提权,以root的身份运行(目前我们用adduser新建的用户没有颁发执行sudo,系统不信任你,除非未来将普通用户添加到系统的信任白名单里)粘滞位:目录设置,一般是共享目录,大家可以在目录进行各自文件的增删查改,只允许文件拥有者或者root能删这个文件,其他人一概不允许。t是一种特殊的x权限。1、默认给普通文件的起始权限其实是666,默认给目录文件的起始权限其实是777。
2023-09-07 22:25:57 116 7
原创 Linux篇:基本指令
6、Linux下一切皆文件,比如显示器(向显示器打印->fwrite,fread(){}),键盘(向键盘进行读取->fread(){}),普通文件(fwrite(),fread())……echo x>y.txt:没有在显示器显示,这个数据被写到了文件中(向目标文件进行写入的时候覆盖写入:清空文件并写入新内容)13、cat不适合看大文本,more可以(逐行下翻),不过一般用less(不加载整个文件,可随意浏览)(.tar是打包后缀,.gz是压缩后缀,XXX.tar.gz可简写为XXX.tgz)。
2023-09-06 20:37:50 133 1
原创 尽信书不如无书,用实践学透继承与多态底层
答,不能因为静态成员函数没有this指针使用类型成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表,无法实现出多态,也就没有意义,所以语法会强制检查。答:首先,如果是普通对象是一样快的,如果是指针对象或者引用对象,则调用的普通函数快,因为构成多态运行时调用虚函数,需要到虚函数表中去查找。虚函数的重写(覆盖):派生类中有一个跟基类完全相同的虚函数(即派生类虚函数与基类虚函数的返回值类型函数名字参数列表完全相同),称子类的虚函数重写了基类的虚函数。什么场景下,虚构函数是虚函数?
2023-08-08 21:04:30 223 5
原创 STL篇:堆与优先级队列
向下调整建堆条件是左右子树均是大/小堆(所以从倒数第一个非叶子节点开始调整),这种方法的效率比向上调整建堆效率高。向下调整建大堆:从倒数第一个非叶子节点开始调整(大的向上调整,小的向下调整)(时间复杂度:logn)5、topk问题:找最大的前k个数,要(将前k个数)建小堆,交换头尾,再将头向下调整。错误:建小堆,如果挪动删除,剩下的看作堆,选次小的,但是关系乱了,得重新建堆。正确方式:交换头尾,pop掉尾,头向下调整(哪个儿子大,调哪个)正确:建大堆,交换,向下调整(跟删除数据一样的思路)
2023-08-05 20:15:40 331 3
原创 STL篇:用容器适配器实现栈和队列
3、头尾插删两者都不错,但中间插入删除deque很拉胯(所以deque用来适配stack和queue的默认容器再合适不过了)stack(后进先出)和queue(先进先出)均为容器适配器,适配器的本质是复用。deque:通过中控(指针数组)控制数据。若指针数组满,则中控指针扩容即可。2、[]不够机极致,需计算在哪个buff数组,在哪个buff数组的第几个。链表:任意位置插入删除都可以,按需申请释放,不支持下标随机访问。顺序表:下标随机访问扩容问题。1、极大地缓解了扩容问题/头插头删问题。
2023-08-05 15:15:15 102 1
原创 STL篇:vector的用法注意事项以及模拟实现
vector是深拷贝,但是vector空间上存的对象是string的数组,使用memcpy导致string对象的浅拷贝。string:要求最后有“\0”,更好地兼容c接口,它有很多它的专用接口(+=,比较大小等)3、错误用法:有空间不一定能访问(reserve,resize之前必须初始化)1、vector的用法与string相似,不再赘述。4、二维数组vector5、迭代器区间:左闭右开[first,last)vector:没有“\0”,比较大小无意义。
2023-08-04 11:51:54 152 3
原创 STL篇:list的用法注意事项以及模拟实现
forward iterator单向(++):forward_list(单链表)/unordered_xxx(哈希)Random access iterator随机(++/--/+/-):vector/string/deque。4、迭代器对象不写析构函数,因为迭代器仅用于访问容器,节点不属于迭代器,不需要迭代器释放。bidirectional Iterator双向(++/--):list/map/set。3、迭代器根据性质(容器底层结构)决定。insert后,迭代器it不失效。
2023-08-03 22:16:35 137 3
原创 STL篇:string的用法及模拟实现
在VS2019中,若字符串size=16,则存在_ptr指向的堆空间中。2、一个对象修改影响另一个(延迟拷贝解决):写的时候引用计数如果不是1,则进行深拷贝,再修改。1、析构两次(引用计数解决):最后一个管理此块空间的对象对其析构(最后一个走的人关灯)push_back(尾插字符),append(尾插字符串)与assign(覆盖)clear:只清数据,底层判断是否缩容(看编译器)(一般不缩)insert(插入)与erase(清除)
2023-08-02 20:32:15 84 3
原创 模板:编程界的活字印刷术
1、函数模板根据调用,自己推导模板参数的类型,实例化出对应的函数(自定义类型也可以)而用类模板实现栈时,需类里定义,类外声明(模板参数也要声明)显然,template的作用范围是模板下面第一个类/函数。2、通过实参传递的类型推演T的类型,可能会推导歧义。解决方法:显示实例化:Add<int>()(有些函数无法自动推,只能显示实体化)(不分离也可以,就是难看概况)普通类,类名和类型是一样。类模板,类名和类型不一样。类型:Stack<T>
2023-08-01 15:48:36 90 2
原创 new和delete——动态内存管理的新玩法
6.申请自定义类型对象时, malloc/free只会开辟空间, 不会调用构造函数与析构函数, 而new 在申请空间后会调用构造函数完成对象的初始化, delete在释放空间前会调用析构函数完成空间中资源的清理。5. malloc申请空间失败时,返回的是NULL,因此使用时必须判空, new不需要, 但是new需要捕获异常(面向对象语言处理失败,不喜欢用返回,更建议用抛异常)。4. malloc的返回值为void*, 在使用时必须强转, new 不需要,因为new后跟的是空间的类型。malloc:开空间。
2023-07-26 11:03:41 106 9
原创 隐式类型转换、static成员、匿名对象
静态成员变量,属于类,属于类的每个对象共享,存储在静态区。静态成员,没有this指针(不能访问非静态成员),只要突破/指定类域和访问限定符/友元,就 可以访问。静态不可以调用非静态(非静态的成员函数调用需要this指针,而静态没有),非静态可以调用 静态。静态成员变量不能给缺省值(因为他没有初始化列表)(缺省值是给初始化列表的)。静态成员在类里面声明,类外面定义,且不受访问限定符的限制。成员变量属于每个类对象,存储在对象里。静态成员函数和静态成员变量配套出现。
2023-07-23 20:51:28 80
原创 用日期计算器通杀运算符重载
Date和MyQueue不需要我们自己实现赋值重载,Date是内置类型成员,Myqueue是自定义类型成员。赋值运算符只能重载成类的成员函数,不能重载成全局函数(否则冲突)(就像亲儿子只能在家吃饭)(也可以在类里面给声明,类外面给定义)总结:只要成员函数内部不修改成员变量,都应该加const,这样const对象和普通对象都可以调用。用户没有显式实现时,编译器会生成一个默认赋值运算符重载,以值的方式逐字节拷贝,相当于拷贝构造。cin是istream类型的对象(流提取和流插入一样,不能用const修饰)
2023-07-21 20:43:45 90 3
原创 探究全自动化机器——构造与析构的奥秘
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个,所以无参构造函数、全缺省构造函数,我们没写编译器默认生成的构造函数都可以认为是默认构造函数,不传参就可以调用的,就是默认构造函数。类的6个默认成员函数(我们不写,编译器自动生成):构造函数,析构函数,拷贝构造,赋值重载,普通对象和const对象取地址。我们不写,编译器默认生成的构造函数,内置类型不做处理(有些编译器也会处理),自定义类型会去调用他的默认构造。没有动态申请的资源,不需要写析构,需要释放资源的成员,不需要写析构。
2023-07-21 14:35:58 102 2
原创 类和对象一镜到底
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整体大小就是所有最大对齐数(含嵌套结构体的对齐数)的整数倍。this指针(形参)存在栈上,作为栈帧的一部分。类中成员变量若不开空间则为声明,若开空间则为定义(整体定义)(类实例化对象/对象定义)2、声明与定义分离:声明放在类的头文件(.h)中,定义放在类的实现文件中(.cpp)注意:对齐数=编译器默认的一个对齐数与该成员大小的较小值(VS中默认的对齐数为8)空类:没有成员变量的类(大小为1,为了占位,表示对象存在)
2023-07-20 23:24:29 98 8
原创 宏函数与内联函数的爱恨情仇
默认debug模式下,inline不会起作用,否则不方便调试(汇编中没call说明未否决)3、inline对于编译器仅仅是一个建议,最终是否成为inline,编译器自己决定。不需要建立栈帧,提高调用效率,简单,不易出错,可读性好,容易调试。1、宏函数:不传参,无return,不加“;2、内联函数inline(适用于短小的频繁调用的函数)内联函数声明和定义不能分离(直接全写在.h中)缺点:复杂,容易出错,可读性差,不能调试。优点:不需要建立栈帧,提高调用效率。缺点:代码膨胀(可执行程序变大)
2023-07-20 21:49:44 80 1
原创 C++入门级教程:引用的超超超详细攻略
局部对象用引用返回(不会报错,就像越界不一定报错):销毁空间,归还使用权后,后续相当于野指针访问,结果打印为随机值(如果函数结束,栈帧销毁,但没有清理栈帧,那么结果侥幸是正确的)如:(栈帧覆盖)谨慎用引用做返回值,出了函数作用域,对象不在了就不能引用返回,还在或全局对象或malloc就可以用引用返回。3.引用在初始化时引用一个实体后,就不能再引用其他实体,而指针可以在任何时候指向任何一个同类型实体。6.引用自加即引用的实体增加1,指针自加即指针向后偏移一个类型的大小。3、引用做返回值(减少拷贝提高效率)
2023-07-20 21:24:41 152 4
原创 C++入门级教程:我将告诉你有关域的一切
注:若展开了命名空间域,则该命名空间域暴露于全局,若与原全局域中变量同名,则不能同时存在。注:默认先从局部搜索,若局部没有,则全局搜索,如果两个都存在,则访问全局域时,要使用::(域作用限定符)1、局部域—>全局域—>展开命名空间域or指定访问命名空间域(默认:不指定是不会去命名空间域搜索的)而展开命名空间域是指,编译时去命名空间中搜索(相当于把墙拆了)在C++中,如果想访问全局域,则需要使用::(域作用限定符)几种常见的域:类域、命名空间域、局部域、全局域。2、常见误区:展开命名空间域≠include。
2023-07-20 17:00:04 321 2
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人