自定义博客皮肤VIP专享

*博客头图:

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

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

博客底图:

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

栏目图:

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

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

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

原创 数据结构复习:二叉搜索树

✅。

2026-10-03 20:18:48 174 3

原创 数据结构复习:排序

第一句:一切排序都在做「扩大有序区」这一件事,只是扩大的方式和代价不同。插入类:把新元素插进有序区(插入、希尔)选择类:从无序区挑最值放进有序区(选择、堆)交换类:通过交换把大数赶到后面(冒泡、快排)归并类:先让小段有序,再合并成大段非比较类:根本不排序,只是数出来再按顺序倒回去第二句:所有高级排序都在做同一件事——把「找位置」的代价从 O(N) 降到 O(logN)。希尔排序:用 gap 让元素跨距离移动堆排序:用堆结构让「取最值」变成O(1) 取 + O(logN) 恢复。

2026-09-30 21:30:44 284 6

原创 数据结构复习:二叉树

树是由 n(n ≥ 0)个有限结点组成的具有层次关系的集合。之所以叫树,是因为它看起来像一棵倒挂的树——根朝上,叶朝下。有一个特殊的根结点,根结点没有前驱结点。除根结点外,其余结点被分成 M(M > 0) 个互不相交的集合 T1、T2……Tm,其中每一个集合 Ti(1 ≤ i ≤ m) 本身又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有 0 个或多个后继。因此,树是递归定义的。⚠️ 注意:树形结构中,子树之间不能有交集,否则就不是树形结构。

2026-09-30 10:41:33 233

原创 linux网络:TCP原理

TCP 之所以复杂,是因为它既要保证可靠性,又要尽可能提高性能。校验和序列号(按序到达、去重)确认应答超时重传连接管理(三次握手 / 四次挥手)流量控制拥塞控制滑动窗口快速重传延迟应答捎带应答定时器(超时重传定时器、保活定时器、TIME_WAIT 定时器等)HTTP、HTTPS、SSH、Telnet、FTP、SMTP,以及你自己写 TCP 程序时自定义的应用层协议。

2026-09-22 20:49:03 352 6

原创 linux网络:UDP原理

因为在网络进行通信的时候,上层要做大量的工作,上层是非常忙的,那么我们读一个报文,上层在处理期间,我们应该让我们的操作系统具备收取UDP报文的能力,所以人家提供一个接受缓冲区不过分,目的就是为了保证上层忙的时候,操作系统底层也继续可以缓存一部分对应的报文,但这个UDP的接收缓冲区不能保证收到的UDP报文和发送的UDP报文顺序一致,满了的时候,再到它的UDP报文就会被丢弃,对于UDP来讲,他就是巨简单我们对应传输层的一个协议,可以给上层提供最简单的面向数据报的通信服务。UDP其实没有真正意义上的缓冲区!

2026-09-07 20:55:57 268 4

原创 linux网络:http补充话题

我们来讲一下这里面的思想,左边是客户端,右边是服务端,首先客户端请求登录网址,然后服务端返回了登录网址,然后浏览器再把用户名和密码发过去,此时服务端显示登录成功,它在应答中加入了Set-Cookie:name=XXX&passwd=......,此时浏览器非常的聪明啊,他在分析它的应答时,会将里面的信息提取出来,保存在cookie文件或者进程当中,下次再request时,会自动携带cookie文件,此时会自动认证,然后完成登录!,这样就不会发起二次请求,而是直接在浏览器的数据缓存区给你拿!

2026-09-06 21:35:31 306 9

原创 c++加餐复习:IO库

ifstream继承自istream,完美继承了它的所有接口,内部还封装了filebuf,负责磁盘文件字节的读取,只负责读取磁盘文件,不能写文件,从这里就可以理解了,其实cin就是从键盘中读取字节,我们来结合代码来讲讲ifstream中的几个重要接口。然后我们再偷看字符,peek(),偷看缓冲区头部,发现是\n换行,不消耗任何字符,缓冲区是不变的,但是我们在这里打印了偷看来的字符,打印之后就实现了换行,然后再get(),get能够读取第一个字符,'\n',此时缓冲区只剩下。所以最好判断一下是否打开成功。

2026-09-04 21:10:16 379 20

原创 数据结构复习:时间复杂度和空间复杂度

定义良好的计算过程,取一个或一组的值为输入,并产生出一个或一组值作为输出。简单来说算法就是一系列的计算步骤,用来将输入数据转化成输出结果。注意:算法不一定是代码,纸上写的步骤也叫算法,代码只是算法的编程语言实现。

2026-09-02 18:22:58 192 7

原创 linux网络:Http协议

1.域名 + 路径:定位一台主机上的某个文件资源2.协议 + 端口:确定使用哪种服务来收发数据3.查询字符串:进一步筛选资源、传递参数4.所有可以用 URL 访问到的资源,属于万维网 WWW 资源。

2026-08-28 10:09:04 1244 35

原创 双指针算法精讲

但需要注意去重,去重我们的操作就是当找到一种结果后,left和right要同时跳过重复的元素,当使用完一次双指针算法之后,i也要跳过重复元素!其实这两个都是有环的,只不过快乐数里面的环都是1罢了,所以我们可以定义一个快指针和一个满指针,他们相遇一定是在环里相遇的,看看相遇的时候数是不是1即可。这时候就可以用我们的双指针算法了,但是在用双指针处理数组的时候,这里的指针其实就是数组的下标,不用慌张。这类题目也可以叫做数组划分,其实就是在特定的条件下对数组进行划分,一边符合一定的条件,另一边符合一定的条件。

2026-08-25 09:52:19 232 10

原创 Linux系统复习:权限的解析

所以无论原来的权限是0还是1,当umask为1时,都要变成0(将某位设置为0,我们要想到&)所以有1则为0而umask为0时,就不能影响原来的权限(如果用&,要想不改变,就得希望该位置是0,其他位置是1,所以可以想到~)虽然说内核不看后缀,但是软件,工具是看后缀的,例如gcc编译器,当文件为.c后缀时,gcc才能够把它当做c源码编译,但是当把.c后缀改为.txt后缀,gcc不认识.txt后缀,不知道这是c源码,直接报错,唯一的方法就是:gcc -x c t.txt,强制告诉gcc这是c源码!

2026-08-24 19:55:48 226 5

原创 linux网络:TCP套接字基础

我们的子进程在这里其实又创建了一个子进程,为了形象点,我们在这里叫做孙子进程,当fork()>0时,其实就是子进程执行的代码,直接退出了,此时我们的父进程执行完代码后压根就不需要去阻塞等待了,直接回收,而Server的任务交给了我们的孙子进程,但是孙子进程的父进程直接退出了,自己就变成了孤儿进程,孤儿进程是被系统所回收的,所以成功解决了难题!值得注意的是这里的Server我们不退,那么服务就一直进行,我们称这种服务为长服务,长服务适合多线程和多进程,短服务就是连接完,应答完,立马关掉连接;

2026-08-18 08:28:24 291 10

原创 linux网络:UDP套接字业务实现之简易聊天室

我们从易到难来一步步分析,首先我们服务端只负责收消息,我们设计一个路由消息类,让这个类去实现将消息发送给所有人,还要用这个类去记录下来在线的所有人,我们在这里将首次发消息等同为登录,所有的在线用户就是一个个的InetAddr,如果在线,就把消息一个个的放入我们的消息队列里面, 所以我们需要用vector对用户进行管理。每次在执行的时候,我们客户端的sendto是阻塞等待,也就是说,你不发消息,根本没法继续往下走收到大家的消息,所以说我们得多次按回车才能收到消息,很明显,这不符合我们日常聊天.

2026-08-13 20:20:58 485 7

原创 linux网络:UDP套接字的业务实现:字典

这期间我们只需要明白一个思想,就是服务端只负责收和发就行了,对单词的翻译处理我们就交给上层就行了,可以通过function回调来实现类和类之间的交互,比如说我们还添加了两个功能类,一个是字典下载和翻译的类,一个是实现网络序列和本地序列转换的类,我们不要给服务端添加太多的工作。我们的字典类里面有两个成员函数,一个是下载功能,一个是翻译功能,成员变量有两个,一个是路径,一个是unordered_map类型的字典,存储中英文。翻译功能其实就很简单了,我们需要知道是谁给我们发的,然后返回value值即可。

2026-08-13 15:07:30 236 4

原创 c++复习:c++11:function包装器

1、对于静态成员函数的包装,需要指明类域,具体的格式就是&Plus::plusi。

2026-08-11 10:39:37 207 4

原创 c++复习:c++11:lambda表达式

其实仿函数使用起来和lambda表达式的效果是一样的,其实对于编译器来说,并没有什么lambda表达式,其实在他眼里也是仿函数(就跟他眼里没有范围for而只有迭代器一样),实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()。第二个是利用捕获列表,但用的是值捕捉,无法达成交换的效果,因为函数处的栈出完作用域就销毁了。第三个是利用捕获列表,这次用的是引用捕捉,可以达成交换的效果。

2026-08-10 19:13:19 236 8

原创 c++复习:C++11:新特性&右值引用&移动语义

在2003年C++标准委员会曾经提交了一份技术勘误表(简称TC1),使得C++03这个名字已经取代了C++98称为C++11之前的最新C++标准名称。不过由于C++03(TC1)主要是对C++98标准中的漏洞进行修复,语言的核心部分则没有改动,因此人们习惯性的把两个标准合并称为C++98/03标准。从C++0x到C++11,C++标准10年磨一剑,第二个真正意义上的标准珊珊来迟。相比于C++98/03,C++11则带来了数量可观的变化,其中包含了约140个新特性,以及对C++03标准中。

2026-08-10 16:25:15 427 4

原创 c++复习:智能指针

当我们进行抛异常时,如果自己new了一个资源出来,一个不小心就很容易造成内存泄漏,如果说是一个类,有析构函数倒无所谓,我们之前讲过一个办法是重新抛出,一个catch接受另一个catch之前先释放资源,但是这样不治根啊,而且也会很麻烦,因此为了解决抛异常之后可能存在的内存泄露的问题,C++提出了智能指针来解决这个问题,他的思想是RAII。下面我们讲RAII来理解什么是智能指针。一些指针必须手动去释放内存,但是如果我们将这个指针变成自定义类型,他会在栈帧销毁的时候去调用对应的析构函数。

2026-08-07 17:11:35 316

原创 c++复习:c++11:异常的捕获和处理

都能抛。这边工程开发时,推荐抛出异常类对象(2)throw抛出的是临时副本,也就是说,抛出的是一个临时对象,不是变量本身。(3)throw可以写在任意的位置:普通代码块、if、函数内部、循环里都可以;一旦执行。

2026-08-07 11:01:31 255 2

原创 c++复习:map和set的使用

比如说1 2 3 4 5 8 9 10,如果我们想插入一个7,那么如果我们传的是5或者8的迭代器,此时就是一个高效的插入(因为相邻),但是如果我们传的迭代器是9,那么此时就不是一个高效的插入,因为找到9之后,还隔着一个8。用来表示一一对应关系的一种结构,一般由两部分构成,一个是key,另一个是value,key是唯一的标识,用来查找,排序和匹配,value是我们真正存放的数据,依附于键而存在,序列式容器靠的是位置访问,而关联式容器靠的是键值对访问。我想是的,如果有[]呢?,和 value 无关;

2026-08-06 21:07:38 254 3

原创 c++复习:Priority_queue的模拟实现

2、优先队列被实现为容器适配器,容器适配器即将特定容器类封装作为其底层容器类,queue提供一组特定的成员函数来访问其元素。LeetCode 原题:合并 K 个有序链表 / 合并多个有序数组 思路: 每个有序序列拿出第一个元素放进优先队列,每次取出最小元素,再把该序列下一个元素入堆。1、priority_queue又叫做优先队列,属于容器适配器(底层默认依赖vector),本质其实就是堆,不保证整体有序,只保证堆顶元素是极值。3、底层容器可以是任何标准容器类模板,也可以是其他特定设计的容器类。

2026-08-06 14:58:58 203 3

原创 c++复习::深入理解多态

当你创造出B的对象时,p->test()时,因为B中没有test,所以用了从A中继承下来的test(),这里满足父类的指针调用,满足多态然后再调用func,又因为A中的func和B中的func构成了函数重写,然后this会根据你动态绑定的对象查询虚表,调用B::func(int),在编译期发生替换,将形参改成静态绑定的A中func函数的形参,也就是int val=1,最后执行B中的函数体,cout<<"B->"<<val<<endl;因为类里面只要出现了虚函数,就一定存在虚函数表指针指向虚表。

2026-08-06 10:37:34 243 1

原创 Queue和Stack的模拟实现

(1)如果我们假定buff每个数组大小一样大,那么随机访问的效率就会高,因为我们减掉该层的当前元素,然后/10可以跳层,再%10就可以跳到该层对应的位置,但是需要中间的插入和删除的话,那么为了维持每层的数组大小,就可能需要挪动一堆数据。1.不适合遍历,因为在遍历时,deque的迭代器要频繁的去检测其是否移动到某段小空间的边界,导致效率低下,而序列式场景中,可能需要经常遍历,因此在实际中,需要线性结构时,大多数情况下优先考虑vector和list。使用者完全感知不到切换了内存块,以为内存是连续的。

2026-08-05 10:16:31 211 5

原创 c++复习:模拟实现list来更好的理解和应用list

1. list是可以在常数范围内在任意位置进行插入和删除的序列式容器,并且该容器可以前后双向迭代。2. list的底层是双向链表结构,双向链表中每个元素存储在互不相关的独立节点中,在节点中通过指针指向其前一个元素和后一个元素。3. list与forward_list非常相似:最主要的不同在于forward_list是单链表,只能朝前迭代,已让其更简单高效。4. 与其他的序列式容器相比(array,vector,deque),list通常在任意位置进行插入、移除元素的执行效率更好。

2026-08-04 16:45:26 280 7

原创 c++复习:模拟实现vector来更好的应用vector

在string的模拟实现中,我们访问数据大多使用下标进行访问,但是需要注意的是下标只能访问连续的数据,因为他是通过遍历来实现的,当遇到不连续的数据时,用下标完全就是错误的,即使在vector中,数据是连续的,我们可以用下标访问,但是呢很多接口还是只允许使用迭代器的,所以我们的vector准备用大量的迭代器来实现,为后面的内容做准备。首先来看看源码。

2026-08-03 18:52:51 231 4

原创 linux网络<UDP>初阶

第一个参数文件描述符,第二个参数数据缓冲区,第三个参数数据缓冲区大小,第四个参数是接受形式,第五个参数是一个输出参数,内核自动填充客户端地址,第六个参数是输出参数类型的大小。我们定义了一个buffer数据接收缓冲区,当客户端给我们发消息时,客户端的地址会被peer所拦截,并对结构体进行填充,此时我们再用函数recvfrom,来接受对应的消息。原因:一个端口号,只能被一个进程bind,为了避免client端口冲突,client端的端口号是几,不重要,只要是唯一的就行!把字符串形式的端口数字转为整数,存入。

2026-07-24 12:56:06 287 5

原创 网络编程基础

(1)首先从技术角度绝对是可以的,但是如果我们把网络和系统都用这个pid,那么一旦系统改了,网络也要跟着改(牵一发而动全身),所以不如单独设计一套专属于网络的数据来让系统和网络功能解耦(有点像生活中,我们有唯一的身份证,但是在学校要有学号,在公司要有工号) ,也就是说,我们存在的意义相似,但这并不代表我就得和你一样!连接就好比我们打电话的时候,会先“喂”,其实就是确保连接了之后我们的沟通才是有效的,而无连接就好比我们发送邮件,要么不发要么就发一整块,反正我发了就行,至于你收到没有我并不关心!

2026-07-23 21:18:48 459 9

原创 万字讲解操作系统硬件,进程的部分概念

任何平台,进程都是具有独立性的,就是我结束了一个进程并不会影响其他的进程,所以父进程和子进程在共享代码的时候,由于代码不能修改,所以是没有问题的,你读你的我读我的,相互之间并不影响,但是如果是数据就不一样了,数据是可以修改的所以我改了可能你也会改,因此从理论上来说,我们的子进程必须想办法拷贝一份相同的数据且独立的数据出来!

2026-05-17 23:08:44 491 9

原创 深度挖掘哈希表的模拟实现

1.哈希的定义:哈希(hash)⼜称散列,是⼀种组织数据的⽅式。从译名来看,有散乱排列的意思。本质就是通过哈希函数把关键字Key跟存储位置建⽴⼀个映射关系,查找时通过这个哈希函数计算出Key存储的位置,进⾏快速查找。2.直接定址法的概念与代码实现:当关键字的范围⽐较集中时,直接定址法就是⾮常简单⾼效的⽅法,⽐如⼀组关键字都在[0,99]之间,那么我们开⼀个100个数的数组,每个关键字的值直接就是存储位置的下标。

2026-04-06 20:21:28 519 5

原创 c++多态的全面理解

我们在分析代码的时候,假如这两个析构函数不构成重写会是什么样子,也就是说在~A的前面不加virtual,当我们主函数delete p2的时候,此时只会调用A中的析构函数来析构B中继承的A的资源,导致B中开的空间并没有完全释放,造成内存泄漏情况,加上virtual之后,两个析构函数构成了多态,就直接调用B中的析构函数了,这样在delete p2的时候就会调用B中的析构函数。派⽣类的虚函数表中包含,(1)基类的虚函数地址,(2)派⽣类重写的虚函数地址完成覆盖,派⽣类⾃⼰的虚函数地址三个部分。

2026-03-16 15:39:59 568

原创 c++继承全面剖析

我们来分析这张图片,上面我们用Student定义了sobj这个对象,因为子类可以赋值给父类对象,指针和引用,所以我们用Person和Person*以及Person&定义了三个对象,其中pobj仅仅获得了sobj中继承的Person这个类中的切片,而pp也仅仅指向了sobj中Person类中的内容,同理,rp也仅仅引用sobj中Person的内容。多继承:⼀个派⽣类有两个或以上直接基类时称这个继承关系为多继承,多继承对象在内存中的模型是先继承的基类在前⾯,后⾯继承的基类在后⾯,派⽣类成员在放到最后⾯。

2026-03-14 18:28:24 627

原创 二叉树-堆

通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址。堆的创建既可以用向上调整法,又可以用向下调整法进行建堆,但是堆的排序需要将堆顶与最后一个元素交换后,再用向下调整法。这是孩子兄弟表示法的代码,可以看出我们用cur只指向父母的左孩子结点,然后再挨着向右遍历,不断找到左孩子的右兄弟结点,直到全部遍历。假设父亲的坐标为i,那么左孩子的坐标就是2*i+1,右孩子坐标是2*i+2。:一个结点含有的子树的根结点称为该结点的子结点;

2026-02-02 22:10:32 516 1

原创 超详细内存函数及其模拟实现。

如果dest>src,那么我们就从后往前打印,看上面的图,蓝色是dest,橙色是src,此时需要从后往前拷贝,num是20个字节,所以我们可以将src强转为char(*)类型,然后+num,就可以得到src中的最后一个要交换的字节,dest同理,然后将src中的最后一个字节拷贝到dest中,依次num--,最后全部拷贝成功。此时destination指向数组的首元素地址要小于source指向的数组首元素的地址,我们要从前往后拷贝,将3给1处,将4给2处,将5给3处,将6给4处,将7给5处。

2026-01-18 17:12:27 723 1

原创 超详细qsort函数的使用及模拟实现

这是仿照qsort来的,因为我们不知道指向的数组是什么类型,所以这里我们填void *base,是void*类型的指针,然后size_t sz代表的是数组的元素个数,又因为类型不知道,所以每个数组元素的字节大小也不确定,无法直接用sizeof(arr[0])来计算,所以我们用的是width来表示,最后就是定义了一个函数指针了,因为你也不知道这个指针指向的函数的参数是什么类型的,所以我们用void*来表示,这个函数指针类型是int(*)(const void*,const void*)

2026-01-17 15:01:53 847 2

原创 c语言函数指针变量

看上面这个图片,pf就是函数指针变量,是用来存放函数地址的,而前面int和int*取决于指向函数的类型,不难看出,Add类型是int的,而test的类型是int*的,而(int,int)与(int,char*)取决于指向函数形参的类型,只需要写类型即可,不需要写变量。这是打印的结果,可知&Add与Add的效果是一样的,也就是说函数名也是函数的地址,而pf中存放着Add的地址,pt中存放着test的地址,所以函数的地址是存在的。总得来说这就是一次函数的调用,调用的是0地址处的一个函数。

2026-01-16 21:25:19 531 6

空空如也

空空如也

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

TA关注的人

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