前天去参加了大众点评招聘的面试,感觉不太好,可能要悲剧了,回来总结一下,试着回想了几个题目,在此一起学习呀。
1. 两个已排好序的数组(假设X[n],Y[n]),如何求得合并后的中间数
当时二话没说直接给出直接简单的解决方法:遍历一遍,总的比较次数是n+m-1次
给出更高效的算法:
假设中间数为X[k],则X数组中比X[k]小的数有k个,而合并后比X[k]小的数应该是n个,所以Y数组中比X[k]小的数应该有n-k个即Y[n-k-1]<=X[k]<=Y[n-k];如果Y[n-k-1]>X[k],递归取k'>k。如果X[k]>Y[n-k],递归取k'<k。
遍历完数组X如果没有找到中位数,则在Y数组中,同样的思想继续进行。
#include <iostream>
using namespace std;
int find_mid(int a[],int b[],int n,int low,int high)
{
if(low > high) return 0;
int k = (low+high)/2;
if(k == n-1 && a[n-1] <= b[0])
return a[n-1];
else if(k < n-1 && a[k]>=b[n-k-1] && a[k]<=b[n-k])
return a[k];
else if(a[k] < b[n-k-1])
return find_mid(a,b,n,k+1,high);
else
return find_mid(a,b,n,low,k-1);
}
int find(int a[],int b[],int n)
{
int mid = 0;
mid = find_mid(a,b,n,0,n-1);
if(mid == 0) mid = find_mid(b,a,n,0,n-1);
return mid;
}
int main()
{
int a[] = {2,5,8,12,16};
int b[] = {1,3,7,10,13};
int mid = find(a,b,5);
cout<<mid<<endl;
return 0;
}
2. 讲一下hash表,我们学过的专业知识中哪里具体用到了这个东西
通过散列函数映射,数据结构课程学的,还有冲突解决方法之类的,基本概念题,应该都知道,但是学过的哪些知识用到了哈希算法,当时确实没想到什么,在这做一总结:
(1)对大数据进行处理时,内存不够,效率不高,用hash可以得到很大帮助
(2)操作系统原理课程,我们知道文件管理中存取管理时可用hash处理
3.网络编程socket
因为用java写过包括socket的程序,知道其是基于TCP协议的服务器和客户端程序的实现方法。
知道五层或者七层协议的就很容易回答这个问题了。
4.多态,虚函数,纯虚函数,重载
好久没翻书,确实对虚函数和纯虚函数有点生疏了。在此总结下:
先知道一句话:重载时静态的多态的实现,虚函数是动态多态的实现
虚函数:成员函数加上virtual关键字,,就成为虚函数,它的子类都是virtual的。这样,虚函数可以实现玩捆绑,比如定义的基类指针,可以在运行时确定该指针指向的对象是基类对象还是派生类对象。那么这个是怎么是实现的呢?
编译器为每个包含虚函数的类创建一个虚函数表(VTABLE),在该表中,放置指定类的虚函数地址,每个带有虚函数的类中,编译器秘密放置一个指针vpointer指向vtable,这样便实现了运行时捆绑。
纯虚函数:虚函数后面加个=0便是纯虚函数。纯虚函数,即提供一个接口,没有定义,不允许创建实例对象,因为没有意义。而继承它的子类必须实现这个接口,才能创建实例对象。
5.构造函数,析构函数,继承后的父类子类的调用顺序,为什么?
构造函数时,先调用父类的构造函数,再调用子类的构造函数。因为继承时构造子类时已经继承了父类的成员,既然能用父类的成员,当然父类的构造函数已经被调用过
析构时,先调用子类的析构函数,在调用父类的构造函数。这是显然的,子类中有父类的成员,假设先调用父类的析构函数,子类中的父类成员终止了,可子类依然存在,但是子类存在,它的成员就该存在(包含的父类成员在),这就矛盾了