面试
流量控制与拥塞控制
流量控制控制端到端的速率,而拥塞控制控制全局网络的速率。
举个例子:
- 宽带速率1Gb/s,网络只有两台机器,从一台主机传送数据到另一台,这需要流量控制,以保证接收方能正常接收数据。
- 宽带速率1Gb/s,网络中有成千上万台机器,几万台主机发送到另外几万台,这需要拥塞控制,不然网络会瘫痪。
所以折中一下,在连接数较少的情况下可能需要流量控制,配合拥塞控制。
以多人聊天为例:
- 流量控制是指,友人A的讲话速率过快,你无法听清,请求他说慢一些;
- 拥塞控制是指,友人A、B、C同时讲话,你的大脑无法处理这么多信息,于是你要求A先说,然后B说,然后C说。
快速排序算法的时间复杂度分析
为了分析快速排序的时间复杂度,请先看下面的主定理:
主定理: T [n] = aT[n/b] + f (n)
其中 a >= 1 and b > 1 是常量 并且 f (n) 是一个渐近正函数, 为了使用这个主定理,您需要考虑下列三种情况:
快速排序的每一次划分把一个 问题分解成两个子问题,其中的关系可以用下式表示:
T[n] = 2T[n/2] + O(n)
其中O(n)为PARTITION()的时间复杂度
对比主定理,为:
T [n] = aT[n/b] + f (n)
我们的快速排序中:a = 2, b = 2, f(n) = O(n)
那么为什么还有最坏情况呢?考虑如下极端情况
T[n] = T[n-1] + T[1] + O(n)
问题来了,这一次的划分白玩了,划分之后一边是一个,一边是n-1个,这种极端情况的时间复杂度就是O(n^2)。
C++中 sizof求结构体大小
Q:定义一个空的类型,里面没有任何成员变量和成员函数。对该类型求sizeof,得到的结果是多少?
A:答案是1。
Q:为什么不是0?
A:空类型的实例中不包含任何信息,本来求sizeof应该是0,但是当我们声明该类型的实例的时候,它必须在
内存中占有一定的空间,否则无法使用这些实例。至于占用多少内存,由编译器决定。Visual Studio中每个空类型的实
例占用1字节的空间。
Q:如果在该类型中添加一个构造函数和析构函数,再对该类型求sizeof,得到的结果又是多少?
A:和前面一样,还是1。调用构造函数和析构函数只需要知道函数的地址即可,而这些函数的地址只与类型相关,而与类型的实例无关,编译器也不会因为这两个函数而在实例内添加任何额外的信息。
Q:那如果把析构函数标记为虚函数呢?
A:++的编译器一旦发现一个类型中有虚拟函数,就会为该类型生成虚函数表,并在该类型的每一个实例中添加一个指向虚函数表的指针。在32位的机器上,一个指针占4字节的空间,因此求sizeof得到4;如果是64位的机器,一个指针占8字节的空间,因此求sizeof则得到8。
C++ 复制构造函数传对象
在上述代码中,复制构造函数A(A other)传入的参数是A的一个实例。由于是传值参数,我们把形参
复制到实参会调用复制构造函数。因此如果允许复制构造函数传值,就会在复制构造函数内调用复制构造
函数,就会形成永无休止的递归调用从而导致栈溢出。因此C++的标准不允许复制构造函数传值参数,在
Visual Studio和GCC中,都将编译出错。要解决这个问题,我们可以把构造函数修改为A(const
A&other),也就是把传值参数改成常量引用
数组与指针的联系与区别
输出:20, 4, 4
data1是一个数组,sizeof(data1)是求数组的大小。这个数组包含5个整数,每个
整数占4字节,因此总共是20字节。data2声明为指针,尽管它指向了数组data1的第一个数字,但它的本质
仍然是一个指针。在32位系统上,对任意指针求sizeof,得到的结果都是4。在C/C++中,当数组作为函数的
参数进行传递时,数组就自动退化为同类型的指针。因此尽管函数GetSize的参数data被声明为数组,但它
会退化为指针,size3的结果仍然是4。