面试总结(堆、UDP、voliate)

来源:互联网 发布:linux 双网卡负载均衡 编辑:程序博客网 时间:2024/06/05 17:53

1.

二叉堆是完全二叉树或者是近似完全二叉树。

二叉堆满足2个特性:

1.父结点的键值总是大于或等于(小于或等于)任何一个子节点的键值。

2.每个结点的左子树和右子树都是一个二叉堆(都是最大堆或最小堆)。

当父结点的键值总是大于或等于任何一个子节点的键值时为最大堆。当父结点的键值总是小于或等于任何一个子节点的键值时为最小堆

由于其它几种堆(二项式堆,斐波纳契堆等)用的较少,一般将二叉堆就简称为堆。

 

堆的表示:

一般都用数组来表示堆,i结点的父结点下标就为(i – 1) / 2。它的左右子结点下标分别为2 * i + 1和2 * i + 2。如第0个结点左右子结点下标分别为1和2。

 

堆的插入:

每次插入都是将新数据放在数组最后。可以发现从这个新数据的父结点到根结点必然为一个有序的数列,现在的任务是将这个新数据插入到这个有序数据中——这就类似于直接插入排序中将一个数据并入到有序区间中。

 

堆的删除:

按定义,堆中每次都只能删除第0个数据。为了便于重建堆,实际的操作是将最后一个数据的值赋给根结点,然后再从根结点开始进行一次从上向下的调整。调整时先在左右儿子结点中找最小的,如果父结点比这个最小的子结点还小说明不需要调整了,反之将父结点和它交换后再考虑后面的结点。相当于从根结点将一个数据的“下沉”过程。

 

 

2.voliate修饰符

volatile 影响编译器编译的结果,volatile变量是随时可能发生变化的,与volatile变量有关的运算,不要进行编译优化,以免出错,(VC++ 在产生release版可执行码时会进行编译优化,加volatile关键字的变量有关的运算,将不进行编译优化。)。 
例如: 
volatileint i=10; 

int j =i; 
... 
int k =i; 
volatile 告诉编译器i是随时可能发生变化的,每次使用它的时候必须从i的地址中读取,因而编译器生成的可执行码会重新从i的地址读取数据放在k中。 
而优化做法是,由于编译器发现两次从i读数据的代码之间的代码没有对i进行过操作,它会自动把上次读的数据放在k中。而不是重新从i里面读。这样以来,如果i是一个寄存器变量或者表示一个端口数据就容易出错,所以说volatile可以保证对特殊地址的稳定访问,不会出错。

 

一个定义为volatile的变量是说这变量可能会被意想不到地改变,这样,编译器就不会去假设这个变量的值了。准确地说就是,优化器在用到这个变量时必须每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份。下面是volatile变量的几个例子: 
1)
并行设备的硬件寄存器(如:状态寄存器) 
2)
一个中断服务子程序中会访问到的非自动变量(Non-automatic variables) 
3)
多线程应用中被几个任务共享的变量 

如下例:

int square(volatile int *ptr) 

return*ptr * *ptr; 

被翻译成:

int square(volatile int *ptr) 

int a,b; 
a = *ptr; 
b = *ptr; 
return a* b; 

 

3.UDP为什么快及应用场景

一定要说UDP比TCP快的地方无非就是UDP没有流控,没有握手,没有成功确认,一个数据包发过去就不管,从这个角度上说TCP是开销大一点。
但UDP的“快”带来的问题是它不可靠,的确有些场景快就足够了,比如流媒体,偶尔丢失错乱几个包不是大问题,但更多的情况下,数据的正确性是一个必选项,此时UDP就不一定适用了。

但有个场景你是绝对需要UDP的,那就是广播,TCP这种点对点有连接的协议,天生就没法广播,你只能建立一大堆连接然后朝每个对端把数据分别发送一遍。

 

UDP的应用场景:

TCP一般用于文件传输(FTP HTTP对数据准确性要求高,速度可以相对慢),发送或接收邮件(POP IMAP SMTP 对数据准确性要求高,非紧急应用),远程登录(TELNETSSH 对数据准确性有一定要求,有连接的概念)等等;UDP一般用于即时通信(QQ聊天 对数据准确性和丢包要求比较低,但速度必须快),在线视频(RTSP 速度一定要快,保证视频连续,但是偶尔花了一个图像帧,人们还是能接受的),网络语音电话(VoIP 语音数据包一般比较小,需要高速发送,偶尔断音或串音也没有问题)等等。

 

4.const与#define

1、定义常量

2.const修饰函数参数

3.修饰成员函数(只能访问const成员变量,不能访问非const成员变量)

 

const常量有数据类型, 而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只能进行字符替换,没有类型安全检查。而且字符替换可能会带来料想不到的边界效应。有些集成化工具可以对const常量进行调试, 但不能对宏量进行调试。

 

const的常量是一个Run-Time的概念,它在程序中确确实实的存在可以被调用、传递。而#define常量则是一个Compile-Time概念,它的生命周期止于编译期:在实际程序中他只是一个常数、一个命令中的参数,没有实际的存在。const常量存在于程序的数据段.#define常量存在于程序的代码段。

 

1.const定义的只读变量在程序运行过程中只有一份拷贝(因为它是全局的只读变量,存放在静态区),而#define定义的宏常量在内存中有若干个拷贝。

2.#define宏是在预编译阶段进行替换,而const修饰的只读变量是在编译的时候确定其值。

从执行效率上来说#define是一个更好的选择。从执行稳健性来说用const会好一些。

 

5.C和C++的区别

C和C++的关系:就像是win98跟winXP的关系。C++是在C的基础上增加了新的理论,玩出了新的花样。所以叫C加加。
1. C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制)。

2. C++,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。 所以C与C++的最大区别在于它们的用于解决问题的思想方法不一样。之所以说C++比C更先进,是因为“ 设计这个概念已经被融入到C++之中 ”。

 

0 0
原创粉丝点击