本次是接着前面的例子使用模板函数来更方便的计算三个数的最大值。
template的意思是模板,typename是类型名,后面的T是一个类型参数,当然也可以是其他的字母,这里使用T的目标是为了表示类型type的意思。
2.编译系统会根据函数名 max与模板函数max进行匹配,将实参类型取代模板当中的T,这样就实现了后面的使用int代表T使用double代表T或者使用long代表T。
3.模板函数适用于参数数量相同但是类型不相同的情况。如果参数数量不相同就不可以使用模板函数了。
本次是接着前面的例子使用模板函数来更方便的计算三个数的最大值。
template的意思是模板,typename是类型名,后面的T是一个类型参数,当然也可以是其他的字母,这里使用T的目标是为了表示类型type的意思。
2.编译系统会根据函数名 max与模板函数max进行匹配,将实参类型取代模板当中的T,这样就实现了后面的使用int代表T使用double代表T或者使用long代表T。
3.模板函数适用于参数数量相同但是类型不相同的情况。如果参数数量不相同就不可以使用模板函数了。
技术交流QQ群:,欢迎你的加入! 1.Cpp中的模板template 模板是泛型编程的基础,泛...
C++ 模板简介 一、模板 使用模板的目的就是能够让程序员编写与类型无关的代码。 模板是一种对类型进行参数化的工具...
教师的《年度统计报表》中有一表是统计各岗位各薪级人数的,如果用传统的自动筛选方法来统计比较麻烦: 其实我们可以用E...
信任这个话题在我们生活中无处不在,生活中与伴侣的信任,工作中与同事领导的信任,甚至在路上偶遇的陌生人,信任也是对彼...
问题空间由类组成,对象是类在解空间的映射; 计算机语言的发证过程:机器码->汇编语言->c语言->c++-...
现在的手机有什么用,一般都不打电话了,只用QQ和微信就能聊天,而且是和不认识的人聊! 为什么不和熟人聊天呢?因为都...
我秋招就是背的这篇面经,因此分享出来,很感谢大神的面经html
某个枚举变量的值默认为前一个变量值加一
第一个枚举变量默认值为0
枚举变量值是能够重复的java
修饰变量,局部变量,全局变量,成员变量(必须初始值列表)
修饰引用做为函数参数,保护值不会改变,同时也针对常量参数
修饰成员函数,类的成员函数加上const限定能够声明此函数不会更改类对象的内容(并不牢靠)
修饰返回值,代表返回的数据是不可修改的
修饰指针,左定值,右定向,const在*左侧表示所指内容是常量,在*右侧表示指针自己是常量不可变node
C++中空类默认会产生如下6个函数:linux
使用try{} catch(){}来捕获异常,若是本级没有带适当类型参数的catch块,则不能捕获异常,异常就会向上一级传递,若是一直没有捕获,C++会使用默认的异常处理函数c++
回调函数是经过函数指针调用的函数,把函数的指针(地址)做为参数传递给另外一个函数
回调函数与应用程序接口(API)很是接近,都是跨层调用的函数,区别是API是低层给高层的调用,回调函数则相反,是高层提供给低层的调用,必须由高层来安装git
所谓内存泄漏是指因为疏忽或错误致使程序未能释放已经再也不使用的内存的状况,通常指堆内存的泄露,失去对该段内存的控制,于是形成了内存的浪费,会致使CPU资源耗尽的严重后果程序员
缓冲区是成勋运行的时候机器内存的一个连续块
当向缓冲区内填充数据位数超过了缓冲区自身的容量限制,发生溢出的数据覆盖在合法数据(数据,下一条指令的指针,函数返回地址等),解决办法是检查数据长度github
1. 构造函数中计数初始化为1; 2. 拷贝构造函数中计数值加1; 3. 赋值运算符中,左边的对象引用计数减一,右边的对象引用计数加一; 4. 析构函数中引用计数减一; 5. 在赋值运算符和析构函数中,若是减一后为0,则调用delete释放对象。
share_ptr可能出现循环引用,从而致使内存泄露redis
weak_ptr是一种弱引用指针,其存在不会影响引用计数,从而解决循环引用的问题
struct的对其系数和如下几个关系有关
在此注意自由存储区和堆
- 自由存储是C++中经过new与delete动态分配和释放对象的抽象概念,而堆(heap)是C语言和操做系统的术语,是操做系统维护的一块动态分配内存。
- new所申请的内存区域在C++中称为自由存储区。借由堆实现的自由存储,能够说new所申请的内存区域在堆上。
- 堆与自由存储区仍是有区别的,它们并不是等价。
STL内存分配分为一级分配器和二级分配器,一级分配器就是采用malloc分配内存,二级分配器采用内存池。
二级分配器设计的很是巧妙,分别给8k,16k,..., 128k等比较小的内存片都维持一个空闲链表,每一个链表的头节点由一个数组来维护。须要分配内存时从合适大小的链表中取一块下来。假设须要分配一块10K的内存,那么就找到最小的大于等于10k的块,也就是16K,从16K的空闲链表里取出一个用于分配。释放该块内存时,将内存节点归还给链表。
若是要分配的内存大于128K则直接调用一级分配器。
为了节省维持链表的开销,采用了一个union结构体,分配器使用union里的next指针来指向下一个节点,而用户则使用union的空指针来表示该节点的地址。
STL的set和map都是基于红黑树实现的
AVL是一种高度平衡的二叉树,因此一般的结果是,维护这种高度平衡所付出的代价比从中得到的效率收益还大,故而实际的应用很少,更多的地方是用追求局部而不是很是严格总体平衡的红黑树。固然,若是场景中对插入删除不频繁,只是对查找特别有要求,AVL仍是优于红黑的。
红黑树的应用:STL,epoll在内核中的实现
红黑树可以以O(log2 n) 的时间复杂度进行搜索、插入、删除操做。此外,因为它的设计,任何不平衡都会在三次旋转以内解决。固然,还有一些更好的,但实现起来更复杂的数据结构,可以作到一步旋转以内达到平衡,但红黑树可以给咱们一个比较“便宜”的解决方案。红黑树的算法时间复杂度和AVL相同,但统计性能比AVL树更高。
若是插入一个node引发了树的不平衡,AVL和RB-Tree都是最多只须要2次旋转操做,即二者都是O(1);可是在删除node引发树的不平衡时,最坏状况下,AVL须要维护从被删node到root这条路径上全部node的平衡性,所以须要旋转的量级O(logN),而RB-Tree最多只需3次旋转,只须要O(1)的复杂度。
模板分为类模板与函数模板,特化分为全特化与偏特化。全特化就是限定死模板实现的具体类型,偏特化就是若是这个模板有多个类型,那么只限定其中的一部分。
模板特化的目的就是对于某一种变量类型具备不一样的实现,所以须要特化版本。例如,在STL里迭代器为了适应原生指针就将原生指针进行特化。
(1) 建立一个新桶,该桶是原来桶两倍大最接近的质数(判断n是否是质数的方法:用n除2到$sqrt(n)$范围内的数) ;
(2) 将原来桶里的数经过指针的转换,插入到新桶中(注意STL这里作的很精细,没有直接将数据从旧桶遍历拷贝数据插入到新桶,而是经过指针转换)
(3) 经过swap函数将新桶和旧桶交换,销毁新桶。
容量扩张是一次完成的,期间要花很长时间一次转移hash表中的全部元素。
redis中的dict.c中的设计思路是用两个hash表来进行进行扩容和转移的工做,把第一个hash表全部元素的转移分摊为屡次转移,并且每次转移的指望时间复杂度为O(1)。这样就不会出现某一次往字典中插入元素要等候很长时间的状况了。
栈(Stack)和队列(Queue)是两种操做受限的线性表。
2. 插入操做都是限定在表尾进行。
3. 均可以经过顺序结构和链式结构实现。、
4. 插入与删除的时间复杂度都是O(1),在空间复杂度上二者也同样。
5. 多链栈和多链队列的管理模式能够相同。
相似问题的解决方法思路:首先哈希将数据分红N个文件,而后对每一个文件创建K个元素最小/大堆(根据要求来选择)。最后将文件中剩余的数插入堆中,并维持K个元素的堆。最后将N个堆中的元素合起来分析。能够采用归并的方式来合并。在归并的时候为了提升效率还须要建一个N个元素构成的最大堆,先用N个堆中的最大值填充这个堆,而后就是弹出最大值,指针后移的操做了。固然这种问题在如今的互联网技术中,通常就用map-reduce框架来作了。
大数据排序相同的思路:先哈希(哈希是好处是分布均匀,相同的数在同一个文件中),而后小文件装入内存快排,排序结果输出到文件。最后建堆归并。
使用hash_map或者位图,再利用归并的思想
由一个很长的二进制向量和一系列随机映射函数组成,布隆过滤器能够用于检索一个元素是否在一个集合中。
优势是空间效率和查询时间都远远超过通常的算法,缺点是有必定的误识别率(可是不会漏报)
TIME_WAIT又称为2MSL等待状态,MSL是系统中定义的最大报文生存时间,任何TCP报文在网络中生存时间超过这个值就必须被丢弃。
等待MSL的缘由是防止最后一个ACK丢失后能够进行重发,若是ACK丢失后,服务器会重发FIN。
核心思想为任意时刻,最多只能有一个未被确认的小段。 所谓“小段”,指的是小于MSS尺寸的数据块,所谓“未被确认”,是指一个数据块发送出去后,没有收到对方发送的ACK确认该数据已收到。
Nagle算法简单讲就是,等待服务器应答包到达后,再发送下一个数据包。数据在发送端被缓存,若是缓存到达指定大小就将其发送,或者上一个数据的应答包到达,将缓存区一次性所有发送。
Nagle算法是从发送端角度考虑减小了数据包的个数,时延应答从接收端角度考虑减小了数据包的个数。
目的:若是发送方把数据发送得过快,接收方可能会来不及接收,这就会形成数据的丢失。
因此流量控制是点对点通讯的控制,而拥塞控制是对整个网络内流量负载的控制
TCP的流量控制是利用滑动窗口机制实现的,接收方在返回的ACK中会包含本身的接收窗口的大小,以控制发送方的数据发送。
如上图所示A向B发送数据。在链接创建时,B告诉A接收窗口rwnd(receiver window)= 400,单位字节,所以发送方A的发送窗口不能超过400。
(能够看出,B向A发送的三个报文段都设置了 ACK = 1以保证字段有效,后面的rwnd值就是接收方对发送方的三次流量控制。)
第一次把窗口设置为300 ,第二次100 ,最后一次为 0,即不容许发送方再发送数据的状态。
可是当某个ACK报文丢失了,就会出现A等待B确认,而且B等待A发送数据的死锁状态。为了解决这种问题,TCP引入了持续计时器(Persistence timer),当A收到rwnd=0时,就启用该计时器,时间到了则发送一个1字节的探测报文,询问B是很忙仍是上个ACK丢失了,而后B回应自身的接收窗口大小,返回仍为0(A重设持续计时器继续等待)或者会重发rwnd=x。
窗口是TCP中为了解决应答机制等待时间过长而引入的方法,若是没有窗口,则TCP每发送一次数据就必须等待应答,收到应答后继续发送,若是没有收到则等待一段时间后重发,若是很长时间都没法收到应答则判断为网络断开。而使用窗口后,窗口的大小指无需等待应答能够连续发送多个数据包。
TCP窗口在每一个传输方向都有两个窗口,发送端窗口和接收端窗口,又由于TCP是全双工通讯,所以有四个窗口。
引入窗口后,TCP的应答包若是部分丢失,无需重传,由后面的应答包保证。TCP为了提升效率,采用延时再确认应答,和选择性确认应答,即收到数据包后不当即发送应答包,而是等待收到下一个或多个包后发一个应答。
网络中的链路容量、交换结点中的缓存、处理机等等都有着工做的极限,当网络的需求超过它们的工做极限时,就出现了拥塞。拥塞控制就是防止过多的数据注入到网络中,这样可使网络中的路由器或链路不致过载。
慢开始算法是指开始发送数据时,并不清楚网络的负荷状况,会先发送一个1字节的试探报文,当收到确认后,就发送2个字节的报文,继而4个,8个以此指数类推。
须要注意的是,慢开始的“慢”并非指拥塞窗口的增加速率慢,而是指在TCP开始发送报文时先设置拥塞窗口=1。
拥塞避免算法是让拥塞窗口缓慢地增大,即cwnd加1,而不是如慢开始算法同样加倍。、
根据上图的实例进行分析,一开始的慢开始算法的指数增加是很恐怖的,因此为了防止拥塞窗口cwnd增加过快须要设置一个门限ssthresh,这里是16。
在上述对拥塞窗口的描述中,咱们只是说在链接开始的时候,以指数级的速率增长,直到第一个丢失事件发生。但实际中TCP对因超时而检测到的丢包事件做出的反应与对因收到3个冗余ACK而检测到的丢包事件作出的反应是不一样的。
缘由:3个冗余ACK指示网络还具备某些传送报文段的能力;3个冗余ACK之前的超时,则更为 “严重”。
快重传是指,若是发送端接收到3个以上的重复ACK,不须要等到重传定时器溢出就从新传递,因此叫作快速重传,而快速重传之后,由于走的不是慢启动而是拥塞避免算法,因此这又叫作快速恢复算法。
若是没有快速重传和快速恢复,TCP将会使用定时器来要求传输暂停。在暂停这段时间内,没有新的数据包被发送。因此快速重传和快速恢复旨在快速恢复丢失的数据包。
与快重传配合使用的还有快恢复算法,结合下图的实例来分析,其过程有如下两个要点:
这里为何替换掉了慢开始算法呢?
这是由于收到重复的ACK不只仅告诉咱们一个分组丢失了,因为接收方只有在收到另外一个报文段时才会产生重复的ACK,因此还告诉咱们该报文段已经进入了接收方的缓存。也就是说,在收发两端之间仍然有流动的数据,而咱们不想执行慢启动来忽然减小数据流。
ARP协议是辅助链路层传输的,在已经知道下一站路由器的IP地址后,要将以太网包发送给目的地址,可是以太网须要的是目的mac地址不是IP地址,而经过ARP请求包就能够得到目的IP地址的mac地址。
ARP请求的过程:源主机以广播的形式,发送一个ARP请求包,全部与源主机在直连的主机都会收到一个请求包,以下图所示,请求包询问目的IP地址的mac地址,目的IP地址的主机收到这个请求后,发送一个ARP应答,告诉源主机本身的mac地址。
RARP以与ARP相反的方式工做。RARP发出要反向解析的物理地址并但愿返回其对应的IP地址,应答包括由可以提供所需信息的RARP服务器发出的IP地址。
100:请求者应当继续提出请求。服务器返回此代码则意味着,服务器已收到了请求的第一部分,现正在等
101(切换协议)请求者已要求服务器切换协议,服务器已确认并准备进行切换。
200:请求被正常处理
204:请求被受理但没有资源能够返回
206:客户端只是请求资源的一部分,服务器只对请求的部分资源执行GET方法,相应报文中经过Content-Range指定范围的资源。
303:与302状态码有类似功能,只是它但愿客户端在请求一个URI的时候,能经过GET方法重定向到另外一个URI上
304:发送附带条件的请求时,条件不知足时返回,与重定向无关
307:临时重定向,与302相似,只是强制要求使用POST方法
400:请求报文语法有误,服务器没法识别
403:请求的对应资源禁止被访问
404:服务器没法找到对应资源
500:服务器内部错误
http数据由请求行,首部字段,空行,报文主体四个部分组成
首部字段分为:通用首部字段,请求首部字段,响应首部字段,实体首部字段
浏览器中输入URL,首先浏览器要将URL解析为IP地址,解析域名就要用到DNS协议,首先主机会查询DNS的缓存,若是没有就给本地DNS发送查询请求。DNS查询分为两种方式,一种是递归查询,一种是迭代查询。若是是迭代查询,本地的DNS服务器,向根域名服务器发送查询请求,根域名服务器告知该域名的一级域名服务器,而后本地服务器给该一级域名服务器发送查询请求,而后依次类推直到查询到该域名的IP地址。DNS服务器是基于UDP的,所以会用到UDP协议。
获得IP地址后,浏览器就要与服务器创建一个http链接。所以要用到http协议,http协议报文格式上面已经提到。http生成一个get请求报文,将该报文传给TCP层处理。若是采用https还会先对http数据进行加密。TCP层若是有须要先将HTTP数据包分片,分片依据路径MTU和MSS。TCP的数据包而后会发送给IP层,用到IP协议。IP层经过路由选路,一跳一跳发送到目的地址。固然在一个网段内的寻址是经过以太网协议实现(也能够是其余物理层协议,好比PPP,SLIP),以太网协议须要直到目的IP地址的物理地址,有须要ARP协议。
所以,对于须要频繁交互数据的,频繁的对同一个对象进行不一样的处理,选择多线程合适,对于一些并发编程,不须要不少数据交互的采用多进程。
进程的内存布局在结构上是有规律的,具体来讲对于linux系统上的进程,其内存空间通常能够粗略地分为如下几大段,从高内存到低内存排列:
信号量:信号量用于实现进程间的互斥与同步,而不是用于存储进程间通讯数据。
管道( pipe ):管道是一种半双工的通讯方式,数据只能单向流动,并且只能在具备亲缘关系的进程间使用。进程的亲缘关系一般是指父子进程关系。
命名管道 (named pipe) : 有名管道也是半双工的通讯方式,可是它容许无亲缘关系进程间的通讯。
消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
信号 ( sinal ) : 信号是一种比较复杂的通讯方式,用于通知接收进程某个事件已经发生。
共享内存( shared memory ) :共享内存就是映射一段能被其余进程所访问的内存,这段共享内存由一个进程建立,但多个进程均可以访问。共享内存是最快的 IPC 方式,它是针对其余进程间通讯方式运行效率低而专门设计的。它每每与其余通讯机制,如信号两,配合使用,来实现进程间的同步和通讯。
套接字( socket ) : 套解口也是一种进程间通讯机制,与其余通讯机制不一样的是,它可用于不一样及其间的进程通讯。
匿名管道与命名管道的区别:匿名管道只能在具备公共祖先的两个进程间使用
mmap创建进程空间到文件的映射,在创建的时候并不直接将文件拷贝到物理内存,一样采用缺页终端。mmap映射一个具体的文件能够实现任意进程间共享内存,映射一个匿名文件,能够实现父子进程间共享内存。
slab是Linux操做系统的一种内存分配机制。其工做是针对一些常常分配并释放的对象,如进程描述符等,这些对象的大小通常比较小,若是直接采用伙伴系统来进行分配和释放,不只会形成大量的内存碎片,并且处理速度也太慢。而slab分配器是基于对象进行管理的,相同类型的对象归为一类(如进程描述符就是一类),每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其从新保存在该列表中,而不是直接返回给伙伴系统,从而避免这些内碎片。slab分配器并不丢弃已分配的对象,而是释放并把它们保存在内存中。当之后又要请求新的对象时,就能够从内存直接获取而不用重复初始化。
解决问题:频繁地请求和释放不一样大小的一组连续页框,必然致使在已分配页框的块内分散了许多小块的空闲页面,由此带来的问题是,即便有足够的空闲页框能够知足请求,但要分配一个大块的连续页框可能没法知足请求。
伴算法虽然可以彻底避免外部碎片的产生,但这偏偏是以产生内部碎片为代价的。
全部的空闲页框分组为 11 块链表,每一块链表分别包含大小为1,2,4,8,16,32,64,128,256,512 和 1024 个连续的页框。
共享内存实现分为两种方式一种是采用mmap,另外一种是采用XSI机制中的共享内存方法。mmap是内存文件映射,将一个文件映射到进程的地址空间,用户进程的地址空间的管理是经过vm_area_struct结构体进行管理的。mmap经过映射一个相同的文件到两个不一样的进程,就能实现这两个进程的通讯,采用该方法能够实现任意进程之间的通讯。mmap也能够采用匿名映射,不指定映射的文件,可是只能在父子进程间通讯。XSI的内存共享实际上也是经过映射文件实现,只是其映射的是一种特殊文件系统下的文件,该文件是不能经过read和write访问的。
明显不是,++i主要有三个步骤,把数据从内存放在寄存器上,在寄存器上进行自增,把数据从寄存器拷贝会内存,每一个步骤均可能被中断。
大端模式,是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中,这样的存储模式有点儿相似于把数据看成字符串顺序处理:地址由小向大增长,而数据从高位往低位放;这和咱们的阅读习惯一致。
小端模式,是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中,这种存储模式将地址的高低和数据位权有效地结合起来,高地址部分权值高,低地址部分权值低。
温馨提示:答案为网友推荐,仅供参考
用链表试试。不定长的。for中比较最大最小值就ok。 追问
我是初学者 希望能讲的清楚点 谢谢啦
下面那个代码不错。。。比我这个方法强。