腾讯服务器每秒有2W个QQ号同时上线,找出5min内重新登入的qq号并打印出来。

腾讯服务器每秒有2W个QQ号同时上线,找出5min内重新登入的qq号并打印出来。
如果空间足够大,可以定义一个大的数组a[qq号],初始为零然后.这个qq号登陆了
就a[qq号]++
最后统计大于等于2的QQ号
这个用空间来代替时间
不成熟的想法
2w x 300s
所以用6000.000个桶。刪除超时的算法后面说,所以平均桶的大小是1
假设qq号码一共有1010个,所以每个桶装的q号码是1010/(6*10~6)个,
这个是插入时候的最坏效率(插入同个桶的时候是顺序查找插入位置的)
qq的节点结构和上面大家讨论的基本一样,增加一个指针指
向输出列表,后面说

struct QQstruct {
     
num_type qqnum,
timestamp last_logon_time,
QQstruct *pre,
QQstruct *next,
OutPutlist *out //用于free节点的时候,顺便更新下输出列表
}

另外增加两个指针列表
第一个大小300的循环链表,自带一个指向 QQStruct的域,循环存300秒内的qq指针。
时间一过就fee掉,所以保证所有桶占用的空闾在2wX30以内.
第二个是输出列表,就是存放题目需要输出的节点。
如果登陆的用户,5分钟内完全没有重复的话,每秒free2w个节点
不过在free的时候,要判断一下时间是不是真的超时,因为把节点入桶的时候,遇到重复的,
会更新一下最后登陆的时间。当然啦,这个时候,要把这个q号码放到需要输出的列表里面

给一个奇数阶N幻方,填入数字1,2,3.N^N,使得橫竖斜方向上的和都相同.

#inc1ude
#include
#include
usingnamespace std;
int main() 
{
     
int n;
cin>>n;
int i;
int **Matr = new int *[n]; //动态分配二维数组
for(i=0;i<n;++i)
Matr[i]=new int[n]: //动态分配二维
数组
//j=n/2代表首行中间数作为起点,即1所在位置
int j=n/2,num=1: //初始值
i=0;
while(num!=n*n+1) {
     
//往右上角延升, 若超出则用%转移到左下角
Matr [(i%n+n)%n][(j%n+n)%n]=num;
//斜行的长度和n是相等的,超出则转至下一写信.
if (num%n==0) {
     
i++;
} else {
     
i--;
j++;
}
num++;
}
for (i=0;i<n;i++) {
     
for (j=0;j<n;++j) {
     
cout << setw((int)log10(n*n)+4)<<Matr[i][j]; //格式控制
cout <<endl<<endl;//格式控制
}
}
for (i=0; i<n; ++i) {
     
delete [] Matr[i];
}
return 1;
}

IP地址的编码分为哪俩部分?
网络号和主机号。不过是要和子网掩码按位与上之后才能区分哪些是网络位哪些是主机位

描述实时系统的基本特性.
在特定时间内完成特定的任务,实时性与可靠性

Internet采用哪种网络协议?该协议的主要层次结构?
TCPP协议。应用层、传输层、网络层、数据链路层和物理层

Internet物理地址和|P地址转换采用什么协议?
地址解析协议 ARP address resolution protocol

请描述C++的内存管理方式.
在c++中内存主要分为5个存储区:
栈(Stack):局部变量,函数参数等存储在该区,由编译器自动分配和释放.栈属于计算机系统的数据结构,进栈出栈有相应的计算机指令支持,而且分配专门的寄存器存储栈的地址,效率分高,内存空间是连续的,但栈的内存空间有限。
堆(Heap):需要程序员手动分配和释放(new,delete),属于动态分配方式。内存空间几乎没有限制,内存空间不连续,因此会产生内存碎片。操作系统有一个记录空间内存的链表,当收到内存申请时遍历链表,找到第一个空间大于申请空间的堆节点,将该节点分配给程序,并将该节点从链表中删除。一般,系统会在该内存空间的首地址处记录本次分配的内存大小,用于delete释放该内存空间。
全局/静态存储区:全局变量,静态变量分配到该区,到程序结束时自动释放,包括DATA段(全局初始化区)与BSS段(全局未初始化段)。其中,初始化的全局变量和静态变量存放在DATA段,未初始化的全局变量和静态变量存放在BSS段。BSS段特点:在程序执行前BSS段自动清零,所以未初始化的全局变量和静态变量在程序执行前已经成为0.
文字常量区:存放常量,而且不允许修改。程序结束后由系统释放。
程序代码区:存放程序的二进制代码
hash表的实现,包括STL中的哈希桶长度常数。**
hash表的实现主要涉及两个问题:散列函数和碰撞处理。
1)hash function (散列函数)。最常见的散列函数:f(x) = x % TableSize .
2)碰撞问题(不同元素的散列值相同)。解决碰撞问题的方法有许多种,包括线性探测、二次探测、开链等做法。SGL版本使用开链法,使用一个链表保持相同散列值的元素。
虽然开链法并不要求表格大小必须为质数,但SGI STL仍然以质数来设计表格大小,并且将28个质数(逐渐呈现大约两倍的关系)计算好,以备随时访问,同时提供一个函数,用来查询在这28个质数之中,“最接近某数并大于某数”的质数。

hash表如何rehash,怎么处理其中保存的资源.
先想想为什么需要rehash:
因为,当loadFactor(负载因子)<=1时,hash表查找的期望复杂度为O(1). 因此,每次往hash表中添加元素时,我们必须保证是在loadFactor <1的情况下,才能够添加。
模仿C++的vector扩容方式,Hash表中每次发现loadFactor==1时,就开辟一个原来桶数组的两倍空间(称为新桶数组),然后把原来的桶数组中元素全部转移过来到新的桶数组中。注意这里转移是需要元素一个个重新哈希到新桶中的。

redis的主从复制怎么做的?
Redis旧版复制功能只有同步和命令传播。新版复制功能加入了部分同步的功能。
1)同步:
2)命令传播:
当主服务器会将自己执行的写命令,也即是造成主从服务器不一致的那条写命令,发送给从服务器执行,当从服务器执行了相同的写命令之后,主从服务器将再次回到一致状态。
3)部分同步:(断线后重复制)
复制偏移量:通过对比主从服务器的复制偏移量,程序可以很容易地知道主从服务器是否处于一致状态。
复制积压缓冲区:主服务保存最近的写命令到复制积压缓冲区,是一个先进先出队列
服务器运行ID:从服务器记录上次同步的主服务器的Id。

ubuntu开机的时候系统做了什么?

  1. 加载BIOS
    BIOS程序首先检查,计算机硬件能否满足运行的基本条件,这叫做”硬件自检”。硬件自检完成后,BIOS把控制权转交给下一阶段的启动程序。
  2. 读取MBR
    计算机读取该设备的第一个扇区,也就是读取最前面的512个字节。如果这512个字节的最后两个字节是0x55和0xAA,表明这个设备可以用于启动;如果不是,表明设备不能用于启动,控制权于是被转交给”启动顺序”中的下一个设备。
  3. Bootloader
    在这种情况下,计算机读取”主引导记录”前面446字节的机器码之后,不再把控制权转交给某一个分区,而是运行事先安装的”启动管理器”(boot loader),由用户选择启动哪一个操作系统。
    Boot Loader 就是在操作系统内核运行之前运行的一段小程序。通过这段小程序,我们可以初始化硬件设备、建立内存空间的映射图,从而将系统的软硬件环境带到一个合适的状态,以便为最终调用操作系统内核做好一切准备。
    Boot Loader有若干种,其中Grub、Lilo和spfdisk是常见的Loader。Linux环境中,目前最流行的启动管理器是Grub。
  4. 加载内核
    内核的加载,内核加载后,接开始操作系统初始化,根据进程的优先级启动进程。

程序什么时候应该使用线程,什么时候单线程效率高。
1 耗时的操作使用线程,提高应用程序响应
2 并行操作时使用线程,如C/S架构的服务器端并发线程响应用户的请求。
3 多CPU系统中,使用线程提高CPU利用率
4 改善程序结构。一个既长又复杂的进程可以考虑分为多个线程,成为几个独立或半独立的运行部分,这样的程序会利于理解和修改。
其他情况都使用单线程。

介绍一下模板和容器。如何实现?(也许会让你当场举例实现)
模板可以说比较古老了,但是当前的泛型编程实质上就是模板编程。 它体现了一种通用和泛化的思想。 STL有7种主要容器:vector,list,deque,map,multimap,set,multiset.

C语言同意一些令人震惊的结构,下面的结构是合法的吗,如果是它做些什么?
inta=5,b=7,c;c=a+++b;
这个问题将做为这个测验的一个愉快的结尾。不管你相不相信,上面的例子是完全合乎语法的。问题是编译器如何处理它?水平不高的编译作者实际上会争论这个问题,根据最处理原则,编译器应当能处理尽可能所有合法的用法。因此,上面的代码被处理成: c = a++ + b; 因此, 这段代码持行后a = 6, b = 7, c = 12。 如果你知道答案,或猜出正确答案,做得好。如果你不知道答案,我也不把这个当作问题。我发现这个问题的最大好处是:这是一个关于代码编写风格,代码的可读性,代码的可修改性的好的话题

#include与#include“file.h”的区别?
前者是从Standard Library的路径寻找和引用file.h,而后者是从当前工作路径搜寻并引用file.h。

内存的分配方式有几种?
1)从静态存储区域分配。内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在。例如全局变量。
2)在栈上创建。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
3)从堆上分配,亦称动态内存分配。程序在运行的时候用malloc或new申请任意多少的内存,程序员自己负责在何时用free或delete释放内存。动态内存的生存期由我们决定,使用非常灵活,但问题也最多。

如何让局部变量具有全局生命期。
具体的生命期的概念我觉得我还要好好深入的学习一下,但是这个题目还算比较简单,即用static修饰就可以了,但是只是生命期延长,范围并没有扩大,除非把这个变量定义在函数体外的静态区,不过那样就变成全局变量了,仿佛不符合题目要求。

strtok函数在使用上要注意什么问题。
这个问题我不知道能不能回答全面,因为实在是用的很少。这个函数的作用是分割字符串,但是要分割的字符串不能是常量,这是要注意的。比如先定义一个字符串:char array[]=”part1,part2″;,strtok的原形是char *strtok(char *string, char *delim);,我们将”,”作为分隔符,先用pt=strtok(array,”,”);,得到的结果print出来就是”part1″,那后面的呢,要写成pt=strtok(NULL,”,”);,注意,要用NULL,如果被分割的字符串会被分成N段,那从第二次开始就一直要用NULL。总结起来,需要注意的是:被分割的字符串和分隔符都要使用变量;除第一次使用指向字符串的指针外,之后的都要使用NULL;注意使用这个函数的时候千万别把指针跟丢了,不然就全乱了。

推荐自己的Linux、C/C++技术交流群:【960994558】整理了一些个人觉得比较好的学习书籍、大厂面试题、有趣的项目和热门技术教学视频资料共享在里面(包括C/C++,Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等等.),有需要的可以自行添加哦!~

你可能感兴趣的:(C/C++,面试,linux,c++)