https://blog.csdn.net/LLZK_/article/list/4:比较好的一个介绍知识的博客
 
1.inline有什么用,一定起作用吗?
用来将解决体积较小的函数频繁调用的问题。
只是一个建议 ,如果有循环啊啥的,就不给内联了
2.STL用得多吗?vector扩容,map用的什么实现?
扩容机制:
1.为了支持随机存取,vector存在一个连续的内存空间中。
2.vector当需要插入元素时,发现内存空间不够了 就需要进行扩容处理,分配一块更大的空间,然后将旧的元素都拷贝到新的空间中,然后把旧的空间释放掉。
3.如果每次插入一个元素就扩容一次效率很低,一般采用扩容为之前的2倍或者1.5倍的方法,gcc是2倍。倍数的选择是一个空间时间上面的权衡
成倍增长可以降低扩容的时间复杂度O(1),一次扩容一个复杂度是O(n )
 
map实现方法:红黑树。这里详细的进行了介绍
红黑树是啥:一个排序二叉树,有五个特点。根节点是黑的,到各个子孙节点的路过的黑节点是一样的。
 
 
3.段页内存管理
意义:为了实现用户方便访问:段访问、计算机内存管理便利:页管理
具体的步骤
逻辑地址<段号,偏移>  ->  虚拟地址<页号,偏移>  ->  物理地址<物理页号,偏移>
 
4.static用法,const用法
staic:1.全局static限定他在一个文件中的作用2.局部的,当3.(c++)类中定义的static(计算这个类生产了多少个对象实例)
const:1.修饰全局变量  2.修饰指针  3.防止函数输入参数被修改 4.修饰类内函数,防止这个函数修改私有变量
 
5.多态,虚函数,虚函数表
多态:多态(Polymorphism)按字面的意思就是“多种状态”。在面向对象语言中,接口的多种不同的实现方式即为多态。引用Charlie Calverts对多态的描述——多态性是允许你将父对象设置成为和一个或更多的他的子对象相等的技术,赋值之后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作。
简单的说,就是一句话:允许将子类类型的指针赋值给父类类型的指针。
其实我看到过一句话:调用同名函数却会因上下文的不同而有不同的实现。我觉得这样更加贴切,还加入了多态三要素:(1)相同函数名  (2)依据上下文  (3)实现却不同;
隐藏:就是当不符合 虚函数&&函数完全相同的 情况下,属于隐藏,隐藏其实就是派生类中不能调用基类中同名的函数的一种现象。
虚函数:virtual是让子类与父类之间的同名函数有联系,这就是多态性,实现动态绑定。
虚函数表:用来存放类中的虚函数的一个表,重写是基于这个表的
 
 
纯虚函数的作用:
定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。(就是说,我派生的类中都要对这个纯虚函数进行实例化,基类中没有这个虚函数的实现。需要在子类中重写。)
 
 
c++类中什么函数不能是虚函数。
1:只有类的成员函数才能说明为虚函数; 
2:静态成员函数不能是虚函数; 
静态函数面向的是类,而虚函数面向的是实例化的对象
3:内联函数不能为虚函数; 
内联是个静态的过程,虚函数是动态的,
4:构造函数不能是虚函数; 
因为构造函数用来构造虚指针什么的,当还没构造出来呢,找不到虚函数在哪。
5:析构函数可以是虚函数,而且通常声明为虚函数。
 
虚函数调用原理:首先子类中找不到函数的话,去父类中一级级找,找到了之后,如果这个函数调用了一个虚函数,然后还得向子类中找看看有没有重写的。最后调用函数。
 
给一道虚函数class代码,B继承A,AB都有f()函数,a,b指向B的对象的地址,问a->f()和b->f()在a::f()是函数/虚函数时分别调用哪个。结果脑子突然短路想不出来,还答错了,但最后还是改成对的了,会问为什么。
然后问上面两个类的大小
 
 
6.重写和重载有什么区别
重写是针对父类和子类,当父类中有虚函数,子类中可以对这个相同的函数进行重写。
重载是针对的同一个类中,可以定义几个不同的形参和返回参数的函数,针对不同的输入参数选择不同的函数进行重载
7.TCP UDP区别
1.TCP面向链接,UDP是无链接,TCP进行三次握手和四次挥手。UDP仅仅进行差错校验
2.tcp提供可靠的服务,无差错不丢失,不重复,有序到达。udp只管发送交付,不保证交付成果
tcp保障可靠性的措施:序号标识,滑动窗口、确认应答,重传控制(补)
3.UDP实时性好,资源要求低。
4.TCP是点对点的 而UDP可以是一对多 多对一的
 
udp如何实现可靠了解吗?
tcp保持可靠性:
1.报文长度固定,每次都是发送和之前一样长度的报文。
2.如果没收到确认信号,计时器又超时了,就重新传输报文。
3.接收端收到错误的消息(校验和不对)也会不回应,等待超时重传。
4.对于失序的进行重新排序(使用序号的作用。)
5.把重复的报文丢弃。
6.进行流控,防止报文太多了,把缓冲区冲没了。
 
在UDP上一层实现tcp一样的可靠性机制
         实现确认机制、重传机制、窗口确认机制。
         如果你不利用linux协议栈以及上层socket机制,自己通过抓包和发包的方式去实现可靠性传输,那么必须实现如下功能:
         发送:包的分片、包确认、包的重发
         接收:包的调序、包的序号确认
         目前有如下开源程序利用udp实现了可靠的数据传输。分别为RUDP、RTP、UDT。
8.进程线程区别
1.进程是资源分配的最小单位,线程是程序执行的最小单位。
2.进程有自己的独立地址空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据的,使用相同的地址空间,因此CPU切换一个线程的花费远比进程要小很多,同时创建一个线程的开销也比进程要小很多。
3.线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。
4.但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间。

扩:进程间通讯:
 
1.管道:其实就是一个文件,两个进程读写这个文件   ,只适用于父子进程。
2.FIFO(有名管道):任何进程间都能通讯(不一定父子),但速度慢    
3.消息队列:容量受到系统限制,且要注意第一次读的时候,要考虑上一次没有读完数据的问题    这个和fifo的区别就是他随机读取,不是先入先出,
4.信号量:不能传递复杂消息,只能用来同步    
5.共享内存区:能够很容易控制容量,速度快,但要保持同步,比如一个进程在写的时候,另一个进程要注意读写的问题,相当于线程中的线程安全,当然,共享内存区同样可以用作线程间通讯,不过没这个必要,线程间本来就已经共享了同一进程内的一块内存
 
线程通讯:
1.锁:
互斥锁
读写锁
 
线程内共享内存
 
信号量

 
进程应该就是一个公司 线程就是里面的员工。公司搞了一个工作的地方(分配了cpu 内存等待资源),然后招了很多员工来工作,这样一个公司(进程)就可以共同工作。员工之间(线程之间)的交流很方便,可以使用公司的公共的休息区交流(共享内存 静态变量等等),但是公司之间的交流就不方便了需要公司之间的打通交流渠道(进程间通讯 5种)。
9.内存模型
c++内存模型:堆栈全常代
linux内存模型:
10.虚拟内存和物理内存区别,自己写的代码运行在哪
1.区别:虚拟内存是不真实存在的内存,物理内存就是真实存在的内存:如内存条。
(补充1:实现机制:每个进程维护了一个页表,当所执行的内存不在物理内存中时,发生缺页请求,把需要的内存导入物理内存中)
(补充2:虚拟内存使用要有很好的空间局部性,还有就是使用多级页表,压缩了页表的大小)
2.程序实际是运行在物理内存上,但是编写程序的时候只需要关注虚拟内存,操作系统负责把虚拟内存翻译成物理内存。
(补充:)
 
 
11.内存对齐
1.不对齐的危害:会导致代码执行效率下降,读取一个4byte可能需要更长的时间,对齐之后可以提高效率节省空间
2.结构体中从小到大排列可以让内存节省。
 
12.图的最小生成树
prim算法https://blog.csdn.net/d5__j9?t=1图论好好补一补
克鲁斯卡 Kruskal
明天编写一下程序
13.http什么的知道吗
这里是一篇介绍http的比较好的文章https://www.cnblogs.com/ranyonsue/p/5984001.html
1.简单了解:http是超文本传输协议,是服务器和客户机之间的数据传输规范。
2.使用的是tcpip链接,没有状态的传输,不能记录之前的状态,使用cookie解决这个问题。
3.URL:网络资源标识符
4.请求方法post get put head
5.使用方法:首先DNS得到ip 使用端口号80建立tcp链接。发送http读取文件请求
浏览器得到服务器的文件进行解析显示。
14.LINUX的VFS
1.什么是VFS VFS就是一个管理多个不同文件系统的软件。比如一个系统有fat文件系统和EXT3文件系统,我可以用一个VFS实现对两个文件系统的统一管理。
2.vfs原理:首先读取superblock 和inode表和filedata表构建vfs自己的 dentry 和inode表,目录项dentry 就是存储了这个文件的位置,根目录啊什么的,inode就是存的是文件的信息,比如在磁盘的位置啊,大小啊,权限之类的。superblock存的是这个磁盘文件系统的所有信息,包括所有的inode都要在上面的队列注册,还有第一个就是所有的superblock的队列,以及磁盘大小,文件系统的类型等等。
LRU:http://flychao88.iteye.com/blog/1977653这里介绍了LRU的实现原理
(问题)内存里加载了10个资源,有10个新资源等待加载,怎么调度
两种调度方法:FIFO LRU
FIFO简单暴力,先来的先走,不管这个那个的
LRU要先判断一下,内存里有没有最老的,把最老的踢了,换上新来的。
因为VFS的inode和dentry是放在内存中的,如果所有的都放内存里面内存扛不住,所以使用LRU算法把长时间不用的给剔除内存。一般是用个链表实现。
需要多维护一个队列。
linux使用的是链表实现这个数据结构。
 
 
15.指针和引用区别,作参数区别
1.(扩展)指针和引用之间的区别:
(1)当引用被创建时,它必须被初始化。而指针则可以在任何时候被初始化。
(2)一旦一个引用被初始化为指向一个对象,它就不能被改变为对另一个对象的引用。而指针则可以在任何时候指向另一个对象。
(3)不可能有NULL引用。必须确保引用是和一块合法的存储单元关联。
2.作为函数参数时候的区别
引用不会生成一个副本,(好像是我指针引用是我把仇人地址给你发过去了,而引用是我把仇人给你送过去了)
16.快速排序,复杂度多少
写一下代码,nlogn
快排优化:选取第一个点的位置
对于大的、乱序串列一般认为是最快的已知排序
17.什么是稳定排序
好像就是排序之后 相等的值位置保持不变
一般不稳定排序都是由 于交换造成的
希尔排序:
桶排序:
18.模板和重载的区别
Template:解决函数重用问题
用一个函数,根据模板定义的不同的类型和值,来生成一个具体的函数。
以上厕所为例子:模板就是男女厕所公用,重载就是弄了一个男厕一个女厕。
用法:template<class T>
         void max(T a,Tb){         
         }
编译器处理模板的方法:模板实例化过程是迟钝的,即只能用函数的定义来实现实例化。
模板编译必须是有实例化的模板,然后根据其中的类型,将模板中的类型替换成具体的类型。
 
1. 模板编译时,以每个cpp文件为编译单位,实例化该文件中的函数模板和类模板
2. 链接器在链接每个目标文件时,会检测是否存在相同的实例;有存在相同的实例版本,则删除一个重复的实例,保证模板实例化没有重复存在。
 
模板的参数推导
这个东西就是模板函数通过形参推导出模板实参的过程。需要注意下面三种情况无法推导。
    1、模板的形参必须与模板函数的形参在位置上存在一一对应的关系
template<typename T1, typename T2>
int get_max_type(char a, T2 b)(这个就不行)
    2、与模板函数返回值相关的模板参数无法进行自动推导
template<typename T1, typename T2>
T1 get_max_type(char a, T2 b)
    3、需要推导的模板参数必须是连续位于模板参数列表的尾部,中间不能有不可推导的模板参数。
(最后这个我模板里面有几个 ,函数里面必须有几个,要不然会报错)
 
19.STL vector
1.vector的实现方式是一段连续的内存,使用模板创建。可以用普通指针进行迭代器操作
2.vector 的空间分配见上面,由于是将过去的空间直接给废除,之前的迭代器都不能用了。类似的操作有 resize pushback 
3.vector 插入insert 是把插入位置的后面的都往后边移动完了之后,把要插入的复制到指定位置
4.erase
5.insert :有空间(插入的数量小于后面的   大于后面的)  没空间 
list(链表)支持快速的插入和删除,但是查找费时;
vector支持快速的查找,但是插入费时。
20.unordered map
1.是一种c++11出来的一种map,他和map不同,不会根据key值得顺序进行排列,
21.hash
1.哈希表里面有list  vector  还有一个pair
2.字符串比较不了,自己写一个函数进行比较操作
3.解决碰撞,使用比较函数
4.哈希满了咋办?

 
hashtable的设计与遍历?
 
 
22.互斥锁,读写锁,信号量
信号量:可以有多个任务同时获取这个信号量,每次获取-1,然后如果是负值就不能获取信号量。如果信号量初值是1应该就是互斥锁。
互斥锁: 同时只能有一个线程获取,别的线程就直接睡眠,应该是一种特殊的信号量。
读写锁:(共享独占锁)
  • 是一种特殊的互斥锁,这种锁不会直接阻塞任务,先判断任务的属性。
  • 读模式下的加锁,写模式下的加锁,不加锁。
  • 适合读很多写比较少的情况。
  • 写锁是独占锁,只要有写锁就不能进行其他锁操作。
  • 读者优先算法会发生饿死写者现象。当有写者一直等着读者,而读者又读不到东西,就回一直等待。所以用写者优先
23.malloc new delete free
1.malloc是库函数,需要.h /// new是关键字需要的是编译器支持
2.new不用指定大小
3.new返回的就是指定的指针  而mallc返回的是void需要进行强制类型转换
4.new失败了有异常,而mallac只是返回一个null
5.new会调用
6.c++可以让new delete重载  而malloc不能重载
7.内存区域,malloc是在堆中进行分配,而new是在自由存储区
(自由存储区和堆的关系)
从技术上来说,堆(heap)是C语言和操作系统的术语。堆是操作系统所维护的一块特殊内存,它提供了动态分配的功能,当运行程序调用malloc()时就会从中分配,稍后调用free可把内存交还。而自由存储是C++中通过new和delete动态分配和释放对象的抽象概念,通过new来申请的内存区域可称为自由存储区。基本上,所有的C++编译器默认使用堆来实现自由存储,也即是缺省的全局运算符new和delete也许会按照malloc和free的方式来被实现,这时藉由new运算符分配的对象,说它在堆上也对,说它在自由存储区上也正确。但程序员也可以通过重载操作符,改用其他内存来实现自由存储,例如全局变量做的对象池,这时自由存储区就区别于堆了。
 
24.给4MB空间,每次请求分配1K/2K或4K空间,怎么分配比较好
这里我觉得用首次适应算法,因为1k 2k都比较小的。
伙伴算法是把空间分成了1 2 4 … 1024 可是我不需要这么大个的空间,所以不用这个方法
slab算法是基于对象的一个算法,就是根据结构大小分配不同大小的内存。所以不适合这个例子
 
25.用 c 实现重载 用 C 模拟虚函数 
1.函数指针:
#include<stdio.h>
void func_int(void * a)
{
printf(“%d\n”,*(int*)a); //输出int类型,注意 void * 转化为int
}
void func_double(void * b)
{
printf(“%.2f\n”,*(double*)b);
}
typedef void (*ptr)(void *); //typedef申明一个函数指针
void c_func(ptr p,void *param)
{
p(param); //调用对应函数
}
int main()
{
int a = 23;
double b = 23.23;
c_func(func_int,&a);
c_func(func_double,&b);
return 0;
}
2.用virtrul_arg
extern int open(const char *__file, int __oflag, …) __nonnull ((1));
函数里面就判断有啥,然后调用不同的函数。
 
后来一种方式是控制编译选项。

c语言实现虚函数(后面看看 网上没什么好的思路)
 
 
26.创建派生类对象时 构造函数调用顺序
虚基->基->构造函数
顺序不会因为赋值顺序而改变
不能再里面分配内存,只可以声明。
 
 
27.拥塞控制
1.拥塞是啥?
网络中对资源的需求超过了资源的数量。
拥塞控制
防止大规模流量同时进入一个网络中,需要整个网络中的各个单元协同工作。
流量控制:要做到端到端中的发送端可以降低速度,使得接收端来得及接受数据。
拥塞控制代价:需要额外的信息交互,占用网络中的资源。
2.拥塞控制方法
慢开始( slow-start )、拥塞避免( congestion avoidance )
这两个方法都是维护一个拥塞窗口。拥塞窗口应该就是发送方维护的一个数据表示自己能发多少消息最多。就是如果拥塞了,就减小窗口,如果顺畅就增大窗口。
慢开始:开始不知道阻塞不,先用小的探测一下。上来是一个MSS(TCP两边允许的最大长度)每次都加倍
拥塞避免:每次+1
 
    当 cwnd < ssthresh 时,使用上述的慢开始算法。
    当 cwnd > ssthresh 时,停止使用慢开始算法而改用拥塞避免算法。
    当 cwnd = ssthresh 时,既可使用慢开始算法,也可使用拥塞控制避免算法
每次拥塞之后,计算出一个新的ssthresh 这个值要比之前的低
 
 
这个方法并不能避免拥塞,只是减少拥塞的发生而已。
 
快重传( fast retransmit )和快恢复( fast recovery )。
快重传就是:本来发送方每次发送一个都要受到一个确认消息,然后如果超时了,说明没收到。现在是直接如果接收方没收到正确的报文,就立马发送重复请求,连发四个,当发送方收到了连着仨重复发送报文就立马重新传丢失那个。
如果和快重传配合使用的话,
1.如果收到仨重复,立马慢启动门限减半
2.而且窗口不是成为1,是成为门限的一半大小,每次+1
 

 
滑动窗:
1.就是两个缓冲区,接受缓冲区和发送缓冲区。
2.接受缓冲区告诉发送我要多少个,多大窗口,然后发送缓冲区用窗口圈出一个大小,进行发送 如果没有收到确认就不动 好进行超时重传
3.作用:可以进行流控。
 

time wait状态
1.如图:time wait状态一般在主动断开的一端
2.为啥需要?:就是因为让前一个连接的数据包都在网络中消失掉,防止新的连接收到了上一个连接的数据,破坏了tcp的可靠性。
还有就是如果主动停止方发出的ACK丢了,不等一会 ,万一另一边没收到,这边已经下班了,那就没办法重传了。
28.dynamic_cast static_cast
 
c++除了能使用c语言的强制类型转换外,还新增了四种强制类型转换:static_cast、dynamic_cast、const_cast、reinterpret_cast,主要运用于继承关系类间的强制转化。<>里面是new type
1.static_cast。和c语言里面强制类型转换差不多 ,类转换注意下行转换不安全。而且不能改变变量的const 和volital
void *d = static_cast<void*>(c);
 
2.dynamic_cast具有类型检查的功能,比static_cast更安全。dynamic_cast是唯一无法由旧式语法执行的动作,也是唯一可能耗费重大运行成本的转型动作。
应该是用于上下行转换更安全可靠。
 
3.const_cast,用于修改类型的const或volatile属性。 
我曹,可以把常亮弄成非常量。
 
4.reinterpret_cast:
new_type必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。
 
 
29.new相关
定位new:就是让new对象存在特定的位置的运算(可以让new的东西在那对其)
new 操作符的执行过程
  (1). 调用operator new分配内存 ;
  (2). 调用构造函数生成类对象;
  (3). 返回相应指针。

 
new不分配内存:
Test* test = new(gMemoryCache) Test();
使用的placement new
因为如果直接new的话,是要调用默认的构造函数,但是默认构造函数贼jb慢,我直接用这个方法在buffer区分配一个。这样不会费内存空间,获取内存的时间复杂度为常数。
 
 
 
30.epoll?实现原理?
select poll 都是用来处理多个句柄的函数
select/poll 缺陷:
1.只能支持1024个句柄,可以增加但是会增加系统负担,因为采用的是轮训的方式。
2.要复制大量句柄,巨大开销
3.返回的值是一大堆句柄,需要遍历才能获取其中的信息。
4.select的触发方式是水平触发,应用程序如果没有完成对一个已经就绪的文件描述符进行IO操作,那么之后每次select调用还是会将这些文件描述符通知进程。
 
      与select相比,epoll分清了频繁调用和不频繁调用的操作。例如,epoll_ctrl是不太频繁调用的,而epoll_wait是非常频繁调用的。这时,epoll_wait却几乎没有入参,这比select的效率高出一大截,而且,它也不会随着并发连接的增加使得入参越发多起来,导致内核执行效率下降。
原理: mmap 红黑树 链表
 
31.内核态?用户态?
    内核态就是拥有资源多的状态,或者说访问资源多的状态,也称为特权态。相对来说,用户态就是非特权态,访问的而资源将受到限制。如果一个程序运行在特权态,该程序就可以访问计算机的任何资源,它的资源访问权限不受限制。如果一个程序运行在用户态,其资源需求将受到各种限制。如:要访问操作系统的内核数据结构,如进程表,则需要在特选态下才能办到。如果要访问用户程序里的数据,在用户态即可。
 
类似这种解释:内核就是国家政府,用户就是普通老百姓,老百姓好多东西都不能用,比如不能指挥警察去干啥,还有房价的上涨下降,如果p民想要修改政府(内核)的资源,那么必须用上访(系统调用、陷阱)来交给操作系统,操作系统统一管理,实现稳定性。
32.如何突破private的限制
1.指针。
2.友元声明;
3.用模板
 
33.有一个头文件声明的全局变量,其他文件导入这个头文件,那么他们访问的是一个全局变量吗?
实验代码一直没编译过
34.系统堆栈的区别
1.内核堆栈用来保存 中断 还有系统调用的一些信息
2.用户堆栈存储的事函数调用的现场信息,
3.如果只用用户堆栈不能对需要保护的程序进行很好地保护。
4.如果只用内核,容易造成通过修改内核栈,达到突破系统限制的作用。而且内核栈比较小,只有少量优先级,用户空间大量的函数调用都要一个优先级,很快就没了
 
35.extern “C”
extern “C”的主要作用就是为了能够正确实现C++代码调用其他C语言代码。加上extern “C”后,会指示编译器这部分代码按C语言的进行编译,而不是C++的。由于C++支持函数重载,因此编译器编译函数的过程中会将函数的参数类型也加到编译后的代码中,而不仅仅是函数名;而C语言并不支持函数重载,因此编译C语言代码的函数时不会带上函数的参数类型,一般之包括函数名。
 
36.递归的本质?
本质就是把一个大任务转化成很多小任务,任务之间有依赖关系
广义递归是一个函数A->B->C这样的依赖关系。
狭义的是A->A->A
如果转化成迭代要用栈来进行。
37.最大最小堆问题:
最大或最小)堆了解吗?给你一个无序数组,怎么调整成一个堆,时间复杂度是多少(O(N))。我问能用优先队列吗?ans:笑着说,当然不能。
1.堆:一种基础数据结构:由完全二叉树组成。然后可以进行四种操作使他变成排序的最大堆和最小堆。c++中默认的是一个大头堆,可以指定排列函数对他进行顺序的制定。。
2.堆是用数组保存的,因为是完全二叉树,所以可以用坐标来代表每一个位置,在堆中,若设父亲的索引为i,左儿子的索引刚好等于2i,而右儿子的索引等于2i+1。这个公式会大量地出现在下边的程序中。
3.大根堆,小根堆:就是根节点是最大还是最小值。最大堆就是每个父节点都比孩子节点大。最小堆是每个节点都比孩子节点小。
下沉:(O(lgn))就是和自己的孩子结点比,如果比孩子结点小 就往下面走
删除:(O(lgn))就是先把最后一个元素放在要删除的位置,然后让这个结点下沉
push:先把元素放到最后,然后用上浮的方法进行置换。(O(lgn))
堆的构建:(O(n))在后面插入然后上浮
堆的作用:做优先级队列(FIFO)https://www.cnblogs.com/cielosun/p/5654595.html
这里介绍的额是优先级队列的用途。
 
38.介绍一下红黑树
39.说说你最擅长的三个方面
40.B+、B-树了解吗?(不太了解,知道avl树和红黑树)
41.主从服务器问题
主从服务器如何同步?如何发现主服务器掉线?谁来发现?如何实现?哪个服务器来实现?(????懵)
1主服务器故障,在从服务器中如何选举一个新的主服务器?
(a:从服务器直接向邻居拉选票;q:会出现死锁,怎么解决?a:发送的数据包带时间戳;q:时钟不同步呢?a:那就根据各个从服务器的数据状态。)
2.
42.socket编程?
 
 
C++11?移动语义?move有什么用   智能指针了解吗
手写shared_ptr
 
设计模式
工厂模式:
简单工厂模式:就是在类里面进行判断要生产什么,输入一个参数,返回一个对象(这个和一个函数有啥区别呢?)一个工厂产好几种东西
工厂方法模式:弄好几种工厂生产,一种工厂产一个。
抽象工厂模式:应该就是工厂方法模式的扩展,就是一类工厂可以
 
单例模式知道吗?手写一下(写完继续问,为什么构造函数要private,为什么要双重判断,等等等等一系列的问题,我真是佛了,我一开始写的pthread_once_t,他说你这样我不让你过,强行让我改另一个版本)

版权声明:本文为ray5wang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/ray5wang/p/11108609.html