一些笔试题目

题目按照章节来,每个题目含解析(A)及相关知识(引)

数据库

(1)查询年龄在20-30之间的用户
A:
select *from 表 where datediff(year,出生日期,getdate())<20 20岁以下的
select *from 表 where adtediff(year,出生日期,getdate()) between 20 and 30 20-30岁
select *from 表 where adtediff(year,出生日期,getdate())>30 30岁以上的

(2)sum和count区别
A:
SUM是对符合条件的记录的数值列求和
COUNT 是对查询中符合条件的结果(或记录)的个数

例如:

表fruit

id name price

1 apple 3.00

2 pear 4.00

select count(price) from fruit; —-执行之后结果为:2 (表示有2条记录)

select sum(price) from fruit;—执行之后结果为:7:00(表示各记录price字段之和为7.00)

数据结构

- 完全二叉树

(1)若某完全二叉树包含200个结点,那么这颗完全二叉树中有多少个叶子结点?

A:完全二叉树除了最后一层,其他层都是满结点的。
总结点为200个,是偶数,可以判断度为1的结点仅1个,即n1=1;
根据二叉树性质n0=n2+1;叶子结点数=度为2的结点数+1
200=n0+n1+n2;
200=n0+n1+n0-1;
2*n0=201-n1=201-1=200;
n0=100;
叶子结点数为100

引:
完全二叉树的定义
满二叉树的定义

(2)用数组存储完全二叉树时,结点的索引(数组下标)与其父子结点索引的关系

A:若下标从1开始存储,则编号为i的结点的主要关系为:
双亲:(i/2)下取整
左孩子:2i
右孩子:2i+1

若下标从0开始存储,则编号为i的结点的主要关系为:
双亲:((i-1)/2)下取整
左孩子:2i+1
右孩子:2i+2

引:
数组顺序存储二叉树
完全二叉树通常采用数组而不是链表的存储,其存储结构如下:
对于tree[i],有如下特点:
(1)若i为奇数且i>1,那么tree的左兄弟为tree[i-1];
(2)若i为偶数且i < n,那么tree的右兄弟为tree[i+1];
(3)若i>1,tree的父亲节点为tree[i div 2];
(4)若2*i<=n,那么tree的左孩子为tree[2*i];若2*i+1<=n,那么tree的右孩子为tree[2*i+1];
(5)若i>n div 2,那么tree[i]为叶子结点(对应于(3));
(6)若i<(n-1) div 2.那么tree[i]必有两个孩子(对应于(4))。
(7)满二叉树一定是完全二叉树,完全二叉树不一定是满二叉树。
完全二叉树第i层至多有2^(i-1)个节点,共i层的完全二叉树最多有2^i-1个节点。

- 二叉查找树、平衡二叉树

(1)二叉查找树的时间复杂度

引:
二叉排序树的搜索、插入、删除,时间复杂度

(2)树的广度优先遍历和深度优先遍历的区别

A:
广度优先遍历用队列存储结点对象。
首先将父节点入队,然后将父节点弹出队列;当父节点弹出队列时,对应的左右子节点依次入队;
将左子节点弹出队列,同时对应的左右子节点依次入队;将右子节点弹出队列,同时对应的左右子节点依次入队;
以此类推。

深度优先遍历用存储结点对象。
首先将父节点入栈;当父节点出栈时,对应的右左子节点入栈(注意先压右子结点,再压左子结点);
将左子节点(在栈顶)弹出栈,同时对应的右左子节点入栈;
将左子节点(在栈顶)弹出栈,同时对应的右左子节点入栈,依次类直到没有子节点入栈;

引:
树的广度优先遍历和深度优先遍历(递归非递归、Java实现)

- 排序

(1)下列选项中,不可能是快速排序第2趟排序结果的是 ()

2,3,5,4,6,7,9
2,7,5,6,4,3,9
3,2,5,4,7,6,9
4,2,3,5,7,6,9

A:
四个选项都是同样的数组元素,若完全有序,应为2345679
每经过一趟快排,轴点元素都必然就位,也就是说,一趟下来至少有1个元素在其最终位置
所以考察各个选项,看有几个元素就位即可。
A:2、3、6、7、9
B:2、9
C:9
D:5、9
第二趟至少应有2个元素就位,所以C不对。

- 哈希表

(1)哈希表(碰撞,复杂度)——笔试面试常考问题
(2)哈希表如何处理冲突

计算机网络、操作系统

- 缺页率

(1)缺页率的计算

A:
FIFO、LRU、OPT这三种置换算法的缺页次数

引:
内存管理
1)虚拟内存
每个程序拥有自己的地址空间,这个地址空间被分割成多个块,每一块称为一页。这些页被映射到物理内存,但不需要映射到连续的物理内存,也不需要所有页都必须在物理内存中。当程序引用到一部分不在物理内存中的地址空间时,由硬件执行必要的映射,将缺失的部分装入物理内存并重新执行失败的指令。

2)分页与分段
分页:
大部分虚拟内存系统都使用分页技术。把由程序产生的地址称为虚拟地址,它们构成了一个虚拟地址空间。例如有一台计算机可以产生 16 位地址,它的虚拟地址空间为 0~64K,然而计算机只有 32KB 的物理内存,因此虽然可以编写 64KB 的程序,但它们不能被完全调入内存运行。

虚拟地址空间划分成固定大小的页,在物理内存中对应的单元称为页框,页和页框大小通常相同,它们之间通过页表进行映射。

程序最开始只将一部分页调入页框中,当程序引用到没有在页框的页时,产生缺页中断,进行页面置换,按一定的原则将一部分页框换出,并将页调入

分段:
使用分页系统的一维地址空间,动态增长的特点会导致覆盖问题的出现。分段的做法是把每个表分成段,一个段构成一个独立的地址空间。每个段的长度可以不同,并且可以动态增长。

每个段都需要程序员来划分。

段页式:
用分段方法来分配和管理虚拟存储器。程序的地址空间按逻辑单位分成基本独立的段,而每一段有自己的段名,再把每段分成固定大小的若干页。

用分页方法来分配和管理实存。即把整个主存分成与上述页大小相等的存储块,可装入作业的任何一页。

程序对内存的调入或调出是按页进行的,但它又可按段实现共享和保护。

分页与分段的区别:
对程序员的透明性:分页透明,但是分段需要程序员显示划分每个段。
地址空间的维度:分页是一维地址空间,分段是二维的。
大小是否可以改变:页的大小不可变,段的大小可以动态改变。
出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护。

3)页面置换算法
1)最佳Optimal
所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率。
是一种理论上的算法,因为无法知道一个页面多长时间不再被访问。
举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列:70120304230321201701
开始运行时,先将 7, 0, 1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。

2)先进先出FIFO
所选择换出的页面是最先进入的页面。
该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。

3)最近最久未使用LRU
虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出。
可以用栈来实现该算法,栈中存储页面的页面号。当进程访问一个页面时,将该页面的页面号从栈移除,并将它压入栈顶。这样,最近被访问的页面总是在栈顶,而最近最久未使用的页面总是在栈底。
这里写图片描述

4)时钟Clock

- 进程线程

(1)进程什么时候变为阻塞状态
进程从运行状态转变到阻塞状态可能是由于( )。

A.进程调度程序的调度
B.现运行进程的时间片用完
C.现运行进程执行了P操作
D.现运行进程执行了V操作
A:
选C。执行P操作,当前进程可能进入信号量队列而阻塞。进程调度或时间片用完时,进程从运行状态转变为就绪状态。执行V操作,当前进程继续处于运行状态。
P操作表示申请一个资源,V操作表示释放一个资源。

引:
关于p操作和v操作的理解
进程状态的切换
这里写图片描述
就绪状态(ready):等待被调度
运行状态(running)
阻塞状态(waiting):等待资源

应该注意以下内容:

  • 只有就绪态和运行态可以相互转换,其它的都是单向转换。就绪状态的进程通过调度算法从而获得 CPU 时间,转为运行状态;而运行状态的进程,在分配给它的 CPU 时间片用完之后就会转为就绪状态,等待下一次调度。
  • 阻塞状态是缺少需要的资源从而由运行状态转换而来,但是该资源不包括 CPU 时间,缺少 CPU 时间会从运行态转换为就绪态;当一个阻塞进程等待的事件发生时,该进程的状态从阻塞变为就绪。
  • 当一个就绪进程被调度程序选中时,该进程的状态从就绪变为运行;当正在运行的进程等待某事件或申请的资源得不到满足时,该进程的状态从运行变为阻塞;当一个阻塞进程等待的事件发生时,该进程的状态从阻塞变为就绪;当一个运行进程时间片用完时,该进程的状态从运行变为就绪。

(2)关于进程间通信,不正确的是:
A、进程互斥是指每次只允许一个进程使用临界资源
B、进程控制是通过原语实现的
C、P、V操作是一种进程同步机制
D、管道不是一种进程高级通信机制

A:
D。管道是一种进程高级通信机制,管道实际上是链接读写进程的一个特殊文件,允许进程按先进先出的方式传送数据,也能使进程同步执行操作。发送进程以字符流形式把大量数据送入管道,接收进程从管道中接收数据。

引:
操作系统 – 进程间同步机制
进程和线程的区别

- 通信

(1)哪些应用协议使用UDP协议?
A:
UDP协议包括:TFTP、SNMP、NFS、DNS、BOOTP
这里写图片描述

引:
UDP协议的用途
UDP(用户数据报协议)是无连接的,尽最大可能交付,没有拥塞控制,面向报文(对于应用程序传下来的报文不合并也不拆分,只是添加UDP首部)。

TCP(传输控制协议)是面向连接的,提供可靠交付,有流量控制,拥塞控制,提供全双工通信,面向字节流(把应用层传下来的报文看成字节流,把字节流组织成大小不等的数据块)。

(2)向一个不存在但合法的公网IP人一端口发送SYN包会出现什么情况?
A:
返回ICMP主机不可达

(3)向一个存在的IP但未绑定的端口发送SYN包会出现什么情况?
A:
返回ICMP端口不可达

引:
ICMP协议

(4)第一个SYN包丢失了,客户主机(主动连接)会采取什么动作?
A:
重传,重试几次后(一般为3次)失败后,连接失败。

(5)为什么建立连接的过程作3次TCP segment交互,而不是4次?
A:
server端的SYN&ACK在一个TCP segment传给了client

(6)什么情况下将会出现4次TCP segment交互?
A:
连接的两段同时打开

(7)第二个SYN2(SYN2&ACK1)丢失了,将出现什么情况?
A:
Client收不到SYN2而不发送ACK2,server端将超时重发

(8)ACK2丢失了将会怎样?
A:
server端认为client没有收到SYN2+ACK1,重发SYN2+ACK1;另外处于未完成的状态,如果出现大量的ACK2丢失,未完成的连接队列会出现“满”的状态,从而不能再接收SYN1。

TCP 的三次握手

这里写图片描述
假设 A 为客户端,B 为服务器端。

  1. 首先 B 处于 LISTEN(监听)状态,等待客户的连接请求。
  2. A 向 B 发送连接请求报文段,SYN=1,ACK=0,选择一个初始的序号 x。
  3. B 收到连接请求报文段,如果同意建立连接,则向 A 发送连接确认报文段,SYN=1,ACK=1,确认号为 x+1,同时也选择一个初始的序号 y。
  4. A 收到 B 的连接确认报文段后,还要向 B 发出确认,确认号为 y+1,序号为 x+1。
  5. B 收到 A 的确认后,连接建立。

三次握手的原因

第三次握手是为了防止失效的连接请求到达服务器,让服务器错误打开连接。

失效的连接请求是指,客户端发送的连接请求在网络中滞留,客户端因为没及时收到服务器端发送的连接确认,因此就重新发送了连接请求。滞留的连接请求并不是丢失,之后还是会到达服务器。如果不进行第三次握手,那么服务器会误认为客户端重新请求连接,然后打开了连接。但是并不是客户端真正打开这个连接,因此客户端不会给服务器发送数据,这个连接就白白浪费了。

TCP 的四次挥手

这里写图片描述

以下描述不讨论序号和确认号,因为序号和确认号的规则比较简单。并且不讨论 ACK,因为 ACK 在连接建立之后都为 1。

  1. A 发送连接释放报文段,FIN=1。
  2. B 收到之后发出确认,此时 TCP 属于半关闭状态,B 能向 A 发送数据但是 A 不能向 B 发送数据。
  3. 当 B 要不再需要连接时,发送连接释放请求报文段,FIN=1。
  4. A 收到后发出确认,进入 TIME-WAIT 状态,等待 2MSL 时间后释放连接。
  5. B 收到 A 的确认后释放连接。

四次挥手的原因

客户端发送了 FIN 连接释放报文之后,服务器收到了这个报文,就进入了 CLOSE-WAIT 状态。这个状态是为了让服务器端发送还未传送完毕的数据,传送完毕之后,服务器会发送 FIN 连接释放报文。

TIME_WAIT

客户端接收到服务器端的 FIN 报文后进入此状态,此时并不是直接进入 CLOSED 状态,还需要等待一个时间计时器设置的时间 2MSL。这么做有两个理由:

  1. 确保最后一个确认报文段能够到达。如果 B 没收到 A 发送来的确认报文段,那么就会重新发送连接释放请求报文段,A 等待一段时间就是为了处理这种情况的发生。
  2. 等待一段时间是为了让本连接持续时间内所产生的所有报文段都从网络中消失,使得下一个新的连接不会出现旧的连接请求报文段。

(9)访问一个url返回http 403 代表什么意思?
A:
请求被服务器拒绝;Forbidden

引:
HTTP协议之http状态码详解

深度学习

(1)机器学习中防止过拟合的处理方法
机器学习中防止过拟合的处理方法
A:
Early stopping,提前停止迭代;
数据集扩增,拥有更多的数据胜过一个好的模型;
正则化方法,在目标函数或loss函数后加正则项,降低模型复杂度;
Dropout,修改神经网络中隐藏层的神经元个数来防止过拟合;
Batch normalization;

注:交叉验证是为了验证模型是否过拟合,并不能防止过拟合,随着训练数据和验证数据的增加以及训练和验证的进度,到训练和验证完成,如果训练误差和验证误差相差较大,则可能发生过拟合,可以通过增加训练数据、减少特征、正则化来解决过拟合问题。

(2)L1和L2正则化的异同点
A:
相同—都用于避免过拟合;
不同—L1可以让一部分特征的系数缩小到0,从而间接实现特征选择,L1范数适用于特征之间有关联的情况;L2让所有特征的系数都缩小,但是不会减为0,它会使优化求解稳定快速,L2适用于特征之间没有关联的情况。

(3)聚类算法有哪些?
A:
划分聚类:K-Means聚类、K-中心点算法、CLARANS算法;
层次聚类:DIANA算法、BIRCH算法、Chameleon算法;
模糊聚类:EM算法;
基于密度聚类:OPTICS算法、DBSCAN算法、OPTICS算法;

(4)聚类算法中用到哪些距离度量衡?
A:
曼哈顿距离(1范数);
欧氏距离(2范数);
汉明距离;
加权的欧式距离;
切比雪夫距离;
幂距离;
余弦相似度;
皮尔森相似度;
修正的余弦相似度;
Jaccard相似度;
相关距离;
马氏距离;

引:
聚类分析中距离度量方法比较

(5)系数矩阵一般的压缩存储方法有哪些?
A:
三元数组存储(行、列、值);
行指针链表(第一列为数组,用指针链接到本行下一个有意义的位置);
十字链表;

(6)实序列的傅里叶变换有何特点?
A、共轭对称函数
B、共轭反对称函数
C、线性函数
D、双线性函数
A:
A。实序列的傅里叶变换只有共轭对称部分,其实部是偶函数,虚部是奇函数。

(7)哪种优化方法的收敛速度是线性的?
A、梯度下降法
B、牛顿法和拟牛顿法
C、共轭梯度法
D、Adagrad
A:
A。线性收敛的优化算法:SGD、SVRG

引:
收敛速度:线性收敛,超线性收敛,r 阶收敛
线性收敛的随机优化算法之 SAG、SVRG(随机梯度下降)

(8)随机变量的皮尔森相关系数

Linux

(1)查找文件的命令
A:
find /etc -name httpd.conf  #在/etc目录下文件httpd.conf
grep ‘test’ d*  #显示所有以d开头的文件中包含 test的行
locate ~/m 搜索用户主目录下,所有以m开头的文件
whereis
which
注:type命令其实不能算查找命令,它是用来区分某个命令到底是由shell自带的,还是由shell外部的独立二进制文件提供的

引:
Linux的五个查找命令

Python

(1)list的方法
这里写图片描述

(2)map()函数
Python map()函数的用法

(3)lambda的用法
python中lambda的用法

C++

(1)哪些函数不能声明为虚函数?
A:
普通函数(非成员函数)—普通函数只能overload,不能被override,声明为虚函数没什么意思,因此编译器会在编译时绑定函数;
静态成员函数—静态成员函数对于每个类来说只有一份代码,所有的对象都共享这一份代码,它不归某个对象所有,所以也没有动态绑定的必要性;
内联成员函数—内联函数是为了在代码中直接展开,减少函数调用花费的代价,虚函数是为了在继承后对象能准确的执行自己的动作,这是不可能统一的。inline函数在编译时被展开,虚函数在运行时才能动态的绑定函数;
构造函数—构造函数是为了明确初始化对象成员才产生的,然而virtual function主要是为了在不完全了解细节的情况下也能正确处理对象。另外虚函数是在不同类型的对象产生不同的动作,现在对象还没产生,如何使用虚函数来完成想完成的动作;
友元函数;

(2)静态数据成员可以作为默认实参(Y)

(3)static变量在什么时候分配内存?
A:
全局变量、文件域的静态变量和类的静态成员变量在main执行之前的静态初始化过程中分配内存并初始化;局部静态变量(一般为函数内的静态变量)在第一次使用时分配内存并初始化。这里的变量包含内置数据类型和自定义类型的对象。

引:
C++局部静态变量在什么时候分配内存和初始化?
关于static静态变量的理解以及C中的内存区的分配

(4)#define中的##的含义
A:
# define f(a,b) a##b
# define d(a) #a
# define s(a) d(a)

void main( void )
{
puts(d(f(a,b)));
puts(s(f(a,b)));
}
输出结果:
f(a,b)
ab

分析: ##把两个符号连起来
#a指把a当成符号,就是把#后面的看成字符串
# define f(a,b) a##b
# define d(a) #a --》 以”#”开头的,直接替换,不展开:immediately replaced by the unexpanded actual argument
# define s(a) d(a) --》 非以”#”开头的,先展开,再替换,也就是一般的情况

引:
#define中#和##的作用

猜你喜欢

转载自blog.csdn.net/violethan7/article/details/79947947