- 博客(82)
- 收藏
- 关注
原创 数据结构-线性表
设置快慢指针 fast 和 slow 最初都指向链表头 head。slow每次都一步,即 slow = slow->next;fast 每次走两步,即 fast = fast->next->next。fast 比 slow 走得快,若有环,则 fast 一定先进入环,而 slow 后进入环。两个指针都进入环后,经过若干操作后两个指针定能在环上相遇。这样就可以判断一个链表是否有环。从头节点到环的入口点的距离等于 n 倍的环长减去环入口点到相遇点的距离。
2024-05-18 11:28:22 902
原创 链表编程题题解
链表的题基本都可以转化为数组,去操作,但是这篇博客没有这种操作,我更建议去体会链表自身的奇妙操作。链表中倒数最后k个结点我们只需要用双指针维护一个大小为K的区间,然后让R指针走到最后即可。
2023-09-25 21:09:41 322 12
原创 进程,线程切换
由于每个进程都有自己的虚拟地址空间,那么显然每个进程都有自己的表,那么当进程切换后页表也要进行切换,页表切换后TLB就失效了,cache失效导致命中率降低,那么虚拟地址转换为物理地址就会变慢,表现出来的就是程序运行会变慢,而线程切换则不会导致TLB失效,因为线程线程无需切换地址空间,因此我们通常说线程切换要比较进程切换块,原因就在这里。因为每个进程都有自己的虚拟地址空间,而线程是共享所在进程的虚拟地址空间的,因此同一个进程中的线程进行线程切换时不涉及虚拟地址空间的转换。这里说的是相同进程下的线程。
2023-09-20 10:35:22 427 16
原创 TOP-K问题
先输入K个数,建立一个大小为K的最小二叉堆,接着每输入一个数,与堆的根节点进行比较,如果比根节点还小,说明不可能为最大的K个数之一,如果比根节点大,那么替换根节点的值,接着下沉根节点,维护二叉堆的性质。这种情况下,关键在于不能消耗太大的内存,无法通过数组的简单排序来求取最大的K个数,于是我们应该想到堆排序,求最大的K个数,就采用大小为K的最小二叉堆来实现;这种情况,由于可以操作存储数据的数组,所以我们采用排序的方式进行求解,但一般的排序时间复杂度也挺高,题目只求最大的K个数,不需要完全排序;
2023-09-11 18:25:08 226 8
原创 memmove
函数说明:memmove用于从src拷贝count个字节到dest,如果目标区域和源区域有重叠的话,memmove能够保证源串在被覆盖之前将重叠区域的字节拷贝到目标区域中。函数原型:void *memmove(void *dest, const void *source, size_t count)参数说明:dest,src分别为目标串和源串的首地址。count为要移动的字节的个数。返回值说明:返回指向dest的void *指针。他其实就是比memcpy, memcpy多了。
2023-09-11 12:16:10 152
原创 MySQL中的锁机制
为了面对由于并发引来的一些问题,在数据库中有「锁」的概念,即当并发事务同时访问一个资源时,有可能导致数据不一致,因此需要一种机制来将数据访问顺序化,以保证数据库数据的一致性,为了通俗地理解锁的概念,以写作作为比喻:在一个博客平台上写作和发布时,对于已经发布的文章可以允许所有人同时阅读,而对于正在修改的文章,我们并不希望读者看到我们修改的过程,同时也不希望其他的编辑对我们正在修改的文章有任何的修改,所以我们将文章暂时地下线进行修改,修改完成后再次上线到页面上。原子性(Atomicity)
2023-09-11 11:51:40 346
原创 死锁
线程死锁是指由于两个或者多个线程互相持有对方所需要的资源,导致这些线程处于等待状态,无法前往执行。当线程进入对象的synchronized代码块时,便占有了资源,直到它退出该代码块或者调用wait方法,才释放资源,在此期间,其他线程将不能进入该代码块。当线程互相持有对方所需要的资源时,会互相等待对方释放资源,如果线程都不主动释放所占有的资源,将产生死锁。
2023-09-10 08:39:39 161 1
原创 互斥锁,自旋锁,读写锁
互斥锁的初始化mutex 指向要销毁的互斥锁的指针对共享资源的访问, 要对互斥量进行加锁, 如果互斥量已经上了锁, 调用线程会阻塞, 直到互斥量被解锁. 在完成了对共享资源的访问后, 要对互斥量进行解锁。函数释放有参数mutex指定的mutex对象的锁自旋锁它是为为实现保护共享资源而提出一种锁机制。其实,自旋锁与互斥锁比较类似,它们都是为了解决对某项资源的互斥使用。无论是互斥锁,还是自旋锁,在任何时刻,最多只能有一个保持者,也就说,在任何时刻最多只能有一个执行单元获得锁。两者在调度机制上略有不同。
2023-09-10 08:18:07 282 11
原创 进程
进程是 Unix 和 Linux 系统中对正在运行中的应用程序的抽象,通过它可以管理和监视程序对内存、处理器时间和 I / O资源的使用。程序被触发后,执行者的权限与属性、程序的程序代码与所需数据等都会被加载内存中,操作系统并给予这个内存内的单元一个标识符 (PID),可以说,进程就是一个正在运作中的程序。进程,是计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位或者linux操作系统最小的资源管理单元。进程与程序对比。
2023-09-09 11:06:13 182 18
原创 布隆过滤器
比如“张三”和“李四”都添加到位图中后,当有人要使用“王五”这个昵称时,虽然“王五”计算出来的三个位置既不和“张三”完全一样,也不和“李四”完全一样,但“王五”计算出来的三个位置分别被“张三”和“李四”占用了,此时系统也会误判为“王五”这个昵称已经被使用过了。在注册账号设置昵称的时候,为了保证每个用户昵称的唯一性,系统必须检测你输入的昵称是否被使用过,这本质就是一个key的模型,我们只需要判断这个昵称被用过,还是没被用过。
2023-08-30 09:55:10 105 7
原创 哈希表哈希桶
为了避免出现这种极端情况,当桶当中的元素个数超过一定长度,有些地方就会选择将该桶中的单链表结构换成红黑树结构,比如在JAVA中比较新一点的版本中,当桶当中的数据个数超过8时,就会将该桶当中的单链表结构换成红黑树结构,而当该桶当中的数据个数减少到8或8以下时,又会将该桶当中的红黑树结构换回单链表结构。与闭散列不同的是,这种将相同哈希地址的元素通过单链表链接起来,然后将链表的头结点存储在哈希表中的方式,不会影响与自己哈希地址不同的元素的增删查改的效率,因此开散列的负载因子相比闭散列而言,可以稍微大一点。
2023-08-30 09:23:09 107 2
原创 C++17
正常情况下,lambda表达式中访问类的对象成员变量需要捕获this,但是这里捕获的是this指针,指向的是对象的引用,正常情况下可能没问题,但是如果多线程情况下,函数的作用域超过了对象的作用域,对象已经被析构了,还访问了成员变量,就会有问题。C++17增加std::variant实现类似union的功能,但却比union更高级,举个例子union里面不能有string这种类型,但std::variant却可以,还可以支持更多复杂类型,如map等。
2023-08-30 07:53:33 556 7
原创 C++14
C++14通过std::shared_timed_mutex和std::shared_lock来实现读写锁,保证多个线程可以同时读,但是写线程必须独立运行,写操作不可以同时和读操作一起进行。C++14中增加了deprecated标记,修饰类、变、函数等,当程序中使用到了被其修饰的代码时,编译时被产生警告,用户提示开发者该标记修饰的内容将来可能会被丢弃,尽量不要使用。返回类型推导可以用在递归函数中,但是递归调用必须以至少一个返回语句作为先导,以便编译器推导出返回类型。就是给字符串加上双引号。
2023-08-29 21:30:18 264 6
原创 C++内存模型
堆内存空余内存地址是一个链表的结构存储的,当一个程序请求过来的时候(此时所需的内存大小已经计算好),就会开始遍历这个链表找个比这个程序所需内存大的节点用来给你程序执行所用,此时就会在链表的节点上删除这个即将被占用的内存节点,因为new对象的这个过程是比较缓慢的而且链表上的每个节点内存大小也是不确定的所以就会产生内存碎片,不过用起来非常方便。(2)申请相对应的空间,如果没有足够的空间或其他问题且没有定义_new_hanlder,那么会抛出bad_alloc的异常并结束程序。(7)返回申请到的内存的首地址。
2023-08-25 16:31:33 590 10
原创 C++11的四种强制类型转换
4、使用dynamic_cast进行转换的,基类中一定要有虚函数,否则编译不通过,类中存在虚函数,就说明它有想要让基类指针或引用指向派生类对象的情况,此时转换才有意义。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。换句话说,它可以在执行期决定真正的类型,如果基类指针真的指向了子类对象,它便返回指子类对象的指针值,否则,则返回空指针。1、其他三种都是编译时完成的,dynamic_cast是运行时处理的。
2023-08-23 21:44:55 1166 13
原创 select、poll、epoll
使用 struct pollfd结构体来存放被监听的文件描述符,它比select“聪明”的地方就在于它把文件描述符和与其关联的事件都定义在这个结构体中了,从而使得编程接口变得简洁很多,同时内核每次修改的都是pollfd结构体的revents成员,而events成员保持不变,因此下次调用poll()函数时应用程序无须重置pollfd类型的事件集参数。2、与select一样,每次poll系统调用时,需要在内核遍历传入的整个文件描述符集合,逐个检测,查看是否有就绪的文件描述符,然后返回就绪文件描述符的个数。
2023-08-17 14:15:21 129 5
原创 面向接口编程
面向接口编程就是先把客户的业务逻辑线提取出来,作为接口,业务具体实现通过该接口的实现类来完成。当客户需求变化时,只需编写该业务逻辑的新的实现类,通过更改配置文件(例如Spring框架)中该接口 的实现类就可以完成需求,不需要改写现有代码,减少对系统的影响。
2023-08-16 22:25:29 1072
原创 云备份
项目名称:云备份系统项目功能:搭建云备份服务器与客户端,客户端程序运行在客户机上自动将指定目录下的文件备份到服务器,并且能够支持浏览器查看与下载,其中下载支持断点续传功能,并且服务器端对备份的文件进行热点管理,将长时间无访问文件进行压缩存储。开发环境:centos7.6/vimg++gdbmakefile以及技术特点:http客户端服务器搭建,json序列化,文件压缩,热点管理,断点续传,线程池,读写锁,单例模式项目模块:服务端:数据管理模块:内存中使用hash。
2023-08-14 22:26:03 663 19
原创 OSI七层模型及TCP/IP四层模型
网络层的还有一个任务就是选择合适的路由,使源主机运输层所传下来的分组,能通过网络层中的路由器找到目的主机。互联网使用的网络层协议是无连接的网际协议(Internet Prococol)和许多路由选择协议,因此互联网的网络层也叫做IP层。在互联网中应用层协议很多,如支持 Web 应用的 HTTP 协议,支持电子邮件的 SMTP 协议等等。(User Datagram Protocol)——提供无连接的,尽力而为的数据传输服务(不保证数据传输的可靠性)。可以把网络接口层看作是数据链路层和物理层的合体。
2023-08-13 18:17:07 1805 1
原创 IP协议
IP地址是唯一标记互联网中计算机的标识,IP地址共占用4个字节,使用点分十进制表示。IP地址和MAC地址都是一种标识,IP地址标记网络中的计算机,MAC地址标记网络硬件设备。
2023-08-13 15:32:03 469 10
原创 MySQL索引和事务
由于B+树的数据都存储在叶子结点中,分支结点均为索引,方便扫库,只需要扫一遍叶子结点即可,但是B树因为其分支结点同样存储着数据,我们要找到具体的数据,需要进行一次中序遍历按序来扫,所以B+树更加适合在区间查询的情况,所以通常B+树用于数据库索引。书的目录确定了,后续每次对书的内容进行调整时,都可能会影响到目录的准确性,就需要重新调整目录,同理,数据库的索引也是一样的,当进行增删查改时,往往也需要同步的调整索引的结构。在联合索引中,如果想要命中索引,需要 按照建立索引时的字段顺序挨个使用,否则无法命中索引。
2023-08-11 00:06:59 454 6
原创 DNS、ARP
如果存在一个大型的网站,此时可能存在多台服务器来提供服务,此时存在一个域名对应着多个服务器的ip地址,此时当用户请求DNS解析时,此时会请求到多个ip地址,在每一个请求中会循环的将这些ip地址排序,然后取出第一个返回给用户。指攻击者利用其他攻击手段,篡改了某个域名的解析结果,使得指向该域名的IP变成了另一个IP,导致对相应网址的访问被劫持到另一个不可达的或者假冒的网址,从而实现非法窃取用户信息或者破坏正常网络服务的目的。当某一个DNS服务器接受到一个DNS响应时,此时就会缓存到本地存储器中。
2023-08-10 01:47:18 416 9
原创 八大排序
对待排序数组中的元素进行分组,从第一个元素开始,按照数组下标中间隔为gap大小的元素分为一组,对每一组进行排序,重新选择gap的大小使得原始数据更加有序,当gap=1的时候就是插入排序。为了避免这种情况,选取头尾和中间元素,比较大小,找大小处于中间的元素为key值,实现对快排的优化,时间复杂度仍为O(nlog^n),每次调用排序的时候把key置一下.这里的分组比较不是分开进行的(第一组比完第二组在比),而是多组同时进行比较,从第gap个元素开始,逐渐往前比较,每次和自己和自己gap距离的元素比较。
2023-08-09 19:24:19 550 7
原创 多态总结
所谓多态,就是同一个操作,作用在了不同的对象上,就会有不同的解释,进而产生不同的执行结果。使用时,是采用父类指针指向子类对象的方法。其中,重载和重写是常见的实现多态的手段。
2023-08-08 19:45:31 262 3
原创 Linux常见指令
堆栈向量检测方法可以帮助程序员更容易地检测出任何运行时堆栈中出现的问题,可以有效地定位潜在的非法操作和漏洞,以帮助改善程序的性能和安全性。如果希望看到详细的当前栈帧的信息,如函数地址、调用函数的地址、被调用函数的地址、当前函数由哪种编程语言编写、函数参数地址及形参值、局部变量的地址等,可以使用 info frame 命令(缩写形式 i f)。内存栈区 (stack) 由编译器自动分配和释放,用于存放函数的形参值、局部变量的值、函数返回地址等数据,其操作方式与数据结构中的栈一致,都是后进先出的原则。
2023-08-08 19:23:42 322
原创 C++内存泄漏
内存泄露是指:内存泄漏也称作"存储渗漏",用动态存储分配函数动态开辟的空间,在使用完毕后未释放,结果导致一直占据该内存单元。直到程序结束。(其实说白了就是该内存空间使用完毕之后未回收)即所谓内存泄漏。
2023-08-08 00:06:43 267 2
原创 TCP和UDP
服务器第一次收到客户端的 SYN 之后,就会处于 SYN_RCVD 状态,此时双方还没有完全建立其连接,服务器会把此种状态下请求连接放在一个队列里,我们把这种队列称之为半连接队列。当然还有一个全连接队列,就是已经完成三次握手,建立起连接的就会放在全连接队列中。如果队列满了就有可能会出现丢包现象。
2023-08-07 23:50:21 1364
原创 进程、线程、协程
协程调度切换时,将寄存器上下文和栈保存到其他地方,在切回来的时候,恢复先前保存的寄存器上下文和栈,直接操作栈则基本没有内核切换的开销,可以不加锁的访问全局变量,所以上下文的切换非常快。5)协程并不是取代线程, 而且抽象于线程之上, 线程是被分割的CPU资源, 协程是组织好的代码流程, 协程需要线程来承载运行, 线程是协程的资源, 但协程不会直接使用线程, 协程直接利用的是执行器(Interceptor), 执行器可以关联任意线程或线程池, 可以使当前线程, UI线程, 或新建新程.。6)线程是协程的资源。
2023-08-07 22:33:04 550 1
原创 HTTP和HTTPS
1.优点:(1)使用HTTPS协议可认证用户和服务器,确保数据发送到正确的客户机和服务器;(2)HTTPS协议是由SSL+HTTP协议构建的可进行加密传输、身份认证的网络协议,要比http协议安全,可防止数据在传输过程中不被窃取、改变,确保数据的完整性。(3)HTTPS是现行架构下最安全的解决方案,虽然不是绝对安全,但它大幅增加了中间人攻击的成本。(4)谷歌曾在2014年8月份调整搜索引擎算法,并称“比起同等HTTP网站,采用HTTPS加密的网站在搜索结果中的排名将会更高”。
2023-08-07 21:16:42 1119 2
原创 在线五子棋对战
⽽实现玩家匹配的思想⾮常简单,为不同的档次设计的各自匹配队列,当⼀个队列中的玩家数量⼤于等于2的时候,则意味着同⼀档次中,有2个及以上的⼈要进⾏实战匹配,则出队队列中的前两个用户,相当于队⾸2个玩家匹配成功,这时候为其创建房间,并将两个用户信息加⼊房间中。数据库中有可能存在很多张表,每张表中管理的数据⼜有不同,要进⾏的数据操作也各不相同,因此我们可以为每⼀张表中的数据操作都设计⼀个类,通过类实例化的对象来访问这张数据库表中的数据,这样的话当我们要访问哪张表的时候,使⽤哪个类实例化的对象即可。
2023-08-03 22:01:15 2053 6
原创 c++异常
C++没有垃圾回收机制,资源需要自己管理。异常对象定义好了,相比错误码的方式可以清晰准确的展示出错误的各种信息,甚至可以包含堆栈调用等信息,这样可以帮助更好的定位程序的bug。返回错误码的传统方式有个很大的问题就是,在函数调用链中,深层的函数返回了错误,那么我们得层层返回错误码,最终最外层才能拿到错误。很多的第三方库都会使用异常,比如boost、gtest、gmock等等常用的库,如果我们不用异常就不能很好的发挥这些库的作用。C++标准库的异常体系定义得不够好,导致大家各自定义自己的异常体系,非常的混乱。
2023-08-03 10:35:12 183
原创 C++11
捕获方式 [a,b]: 以值的方式捕获父作用域中的a和b [=]: 以值的方式捕获父作用域中的所有变量 [&a,&b]: 以引用的方式捕获父作用域中的a和b [&]: 以引用的方式捕获父作用域中的所有变量 [=,&b]: 以值的方式捕获父作用域中的所有变量,但是b以引用的方式捕获 不能重复捕获 [=,a] 或者[&, &a]属于重复捕获,编译失败。auto_ptr C++98: 资源转移 C++11之前:资源管理权限的转移----对资源释放的权限 C++11:又恢复到---资源转移。
2023-08-03 10:33:03 211
原创 C++ 第六弹 STL
STL(standard template libaray-标准模板库是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。通俗说:实际就是将常见的数据结构以泛型的方式封装,并且添加一些常用的通用算法与类型无挂与具体的数据结构无关算法非常灵活,有些算法只是一个框架(半成品),算法具体做什么事情,需要用户来定制。
2023-08-03 10:17:26 147
原创 基于多设计模式下的同步&异步⽇志系统
本项⽬主要实现⼀个⽇志系统, 其主要⽀持以下功能:•⽀持多级别⽇志消息•⽀持同步⽇志和异步⽇志•⽀持可靠写⼊⽇志到控制台、⽂件以及滚动⽂件中•⽀持多线程程序并发写⽇志•⽀持扩展不同的⽇志落地⽬标地。
2023-07-29 09:27:12 949
原创 多线程
一个线程如果被分离了,这个线程依旧要使用该进程的资源,依旧在该进程内运行,甚至这个线程崩溃了一定会影响其他线程,只不过这个线程退出时不再需要主线程去join了,当这个线程退出时系统会自动回收该线程所对应的资源。主线程是产生其他子线程的线程。调用该函数的线程将挂起等待,直到ID为thread的线程终止,thread线程以不同的方法终止,通过pthread_join得到的终止状态是不同的。线程是进程的执行分支,线程出异常,就类似进程出异常,进而触发信号机制,终止进程,进程终止,该进程内的所有线程也就随即退出。
2023-07-16 20:36:48 138
原创 进程通信与信号
消息队列实际上就是在系统当中创建了一个队列,队列当中的每个成员都是一个数据块,这些数据块都由类型和信息两部分构成,两个互相通信的进程通过某种方式看到同一个消息队列,这两个进程向对方发数据时,都在消息队列的队尾添加数据块,这两个进程获取数据块时,都在消息队列的队头取数据块。进程间通信的本质就是,让不同的进程看到同一份资源,使用匿名管道实现父子进程间通信的原理就是,让两个父子进程先看到同一份被打开的文件资源,然后父子进程就可以对该文件进行写入或是读取操作,进而实现父子进程间通信。命名管道创建失败,返回-1。
2023-07-16 16:33:12 155
原创 基础IO
创建文件时,索引块的所有指针都设为空。软链接又叫做符号链接,软链接文件相对于源文件来说是一个独立的文件,该文件有自己的inode号,但是该文件只包含了源文件的路径名,所以软链接文件的大小要比源文件小得多。链接文件的inode号与源文件的inode号是相同的,并且硬链接文件的大小与源文件的大小也是相同的,硬链接文件就是源文件的一个别名,一个文件有几个文件名,该文件的硬链接数就是几,与软连接不同的是,当硬链接的源文件被删除后,硬链接文件仍能正常执行,只是文件的链接数减少了一个,因为此时该文件的文件名少了一个。
2023-07-15 23:50:49 136
原创 进程概念与进程控制
printf,scanf,fopen,fclose,fgetc,fgets,fprintf,fsacnf,fputc,calloc,free,malloc,realloc,strcat,strchr,strcmp,strcpy,strlen,strstr等,需要包含stdio.h,string.h,alloc.h,stdlib.h等头文件。作用:等待任意子进程。产生的原因:如果子进程先于父进程退出,同时父进程太忙了,无瑕回收子进程的资源,子进程残留资源(PCB)存放于内核中,变成僵尸(Zombie)进程。
2023-07-15 22:08:59 266
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人