面试笔试细节汇总

来源:互联网 发布:淘宝自己开店套现 编辑:程序博客网 时间:2024/05/16 19:30

这里记录我们面试笔试过程中遇到的一些不懂或模棱两可的题目。

虚析构函数的作用

在继承体系中,虚析构函数可以防止基类不被析构。
如:class B : public A;A是基类,B是派生类。
A* pa = new B;delete pa;
这时,如果不适用虚析构,则只会释放继承体系中的类A部分内存,这样就出现了内存泄露。
简言之,如果用基类指针指向派生类对象时,由于析构顺序是从派生类到基类依次调用析构函数,所以delete基类指针的时候只会调用基类析构。

struct和class的区别

  1. C语言中的struct只作一种复杂数据结构类型的定义,不能用于面向对象编程。
  2. C++中:struct默认访问级别是public,class是private。
  3. C++中:class可以用于表示模板类型(template< class T>),struct则不行。

C++实现一个单例模式

首先简单的方法:

//单例模式class Singleton{public:    ~Singleton(){};        static Singleton* Instance(){        if (instance == 0){            instance =  new Singleton();        }        return instance;    }    void print(){        cout << "Singlton Instance had creatded." << endl;    }private:    Singleton(){}    static Singleton* instance;};Singleton* Singleton::instance = 0;

以上解法会出现,多线程同步问题,而实现同步的解法很多,但是同步是很浪费时间地。所以,就有如下解法:

class Singleton{    friend class OneInstance;public:    ~Singleton(){};    static Singleton* Instance()    {        return instance;    }    void print()    {        cout << "Singlton Instance had creatded." << endl;    }private:    Singleton(){}    static Singleton* instance;};Singleton* Singleton::instance = new Singleton();

这样就不会出现多线程,同时访问,出现的创建两个对象的问题。
但是,如果没有任何类使用该对象,那么将是一种浪费空间的做法。如果解决创建时机过早的问题呢。

多线程同步的方式

首先要搞清楚进程间通信与多线程间通信概念及区别。
进程间的通信:
- 管道:数据只能单向流动,有名管道可以实现非父子进程间的通信。
- 信号:比较复杂的通信方式,用于接收进程中的某个事件已经发生。
- 信号量:是一个计数器(PV操作),多用于多进程间的资源共享访问,也用于多进程和多线程间的同步。
- 消息队列:是一个消息链表,存放在内核中,由消息队列标识符标识。克服了信号方式的传递消息少,管道方式只能承载无格式字节流和缓冲区大小受限等缺点。
- 共享内存:映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如和信号量,配合使用,来实现进程间的同步和通信。
- 套接字:可用于不同机器间的进程通信。

进程间通信目的:数据传输、共享数据、通知事件、资源共享、进程控制(有些进程希望完全控制另外一个进程的执行(Debug进程))等。
线程间通信实现比较简单,多用于资源共享,而资源共享必涉及到同步问题。

线程通信:
- 全局变量:最简单的同一进程的多线程通信方式,变量一般使用 volatile修饰(告诉编译器无需对该变量作任何的优化,即无需将它放到一个寄存器中,并且该值可被外部改变)。
- 参数传递:主线程创建子线程时,可以通过传递给线程函数的参数和线程通信。
- 自定义消息响应:在Windows程序设计中,应用程序的每一个线程都拥有自己的消息队列,甚至工作线程也不例外,这样一来,就使得线程之间利用消息来传递信息就变的非常简单。我们可以在一个线程的执行函数中向另一个线程发送自定义的消息来达到通信的目的。一个线程向另外一个线程发送消息是通过操作系统实现的。利用Windows操作系统的消息驱动机制,当一个线程发出一条消息时,操作系统首先接收到该消息,然后把该消息转发给目标线程,接收消息的线程必须已经建立了消息循环。该方式可以实现任意线程间的通信,所以是比较常见和通用的方式。

线程的同步方式:

  • 临界区:不可以跨进程,忘记解锁会无限等待,要么存在要么没有,多线程访问独占性共享资源。
  • 互斥量:可以跨进程,忘记解锁会自动释放,要么存在要么没有。
  • 信号量:可以跨进程,始终代表可用资源数量,当资源数为o时,线程阻塞,允许多个线程同时访问一个共享资源。
  • 事件:又叫线程触发器,不可以跨进程,要么存在要么没有,一个线程来唤醒另一个线程(包括自动和人工两种方式)。

虚拟存储器的容量大小受什么控制()

A,页表大小 B,内存实际空间 C,计算机体系结构和外存大小 D,CPU

解析:开始我是这样想的,虚拟地址到实际物理地址是通过页表始址寄存器+虚拟地址的高20位页号,通过页表中页号主存块号的对应关系,再加上虚拟地址的页内位移,最后得打实际主存地址。所以,我选择了A。只能说是一知半解吧。
主存块号只与内存大小和系统设置的页面大小有关,比如32位地址结构中,页面大小为4KB,所以,2^20 * 4KB = 4GB.刚好能表示4GB的最大内存空间。所以,页表的大小与虚拟存储器的大小没有关系。另一方面想,现在的真正64位系统采用的是反置页表(页表大小是根据物理内存页面号的数量来组织页表,且系统中只有一个页表)来实现地址空间的映射。并且题目给的是页表大小,而不是页表中每一个页表项的大小。
因为可以用外存来当内存用,所以虚拟存储器的空间应该是可以很大很大的,受外部存储可用空间大小限制。但是实际的容量受计算机地址总线结构限制。虚拟地址结构是由页号+页内位移组成。地址总线结构决定了访问的地址长度。所以,最后选C。

最长子串,求字符串A,B中最长的子字符串,如ABDFGH和BUYDTFLKGY的最长字串就是BDFG。

博客公共子串和子序列:
(http://blog.csdn.net/z702143700/article/details/48832465)
(http://blog.csdn.net/z702143700/article/details/48832445)

两个同时运行的进程能够同时访问同一物理内存吗?

解析:肯定是不可以的。

广义表概念和拓扑排序概念

广义表就是一个线性的树,但是没有树的约束,具有递归算法。拓扑排序和参阅我的博客数据结构图那一部分。

MyISAM索引和数据是分离的吗

解析:是的,Innodb和MyISAM引擎都是基于B+树实现的,但是MyISAM的B+树种存储的是索引数据地址,而InnoDB则是数据,它直接把整个表按B+树存储起来了。

为用户授权数据库和表的访问权限

--授予角色 r_test 对 HR.Employees 表的所有权限GRANT ALL ON HR.Employees TO r_test--拒绝安全账户 u_test 对 HR.Employees 表的 SELECT 权限DENY SELECT ON HR.Employees TO u_test--如果要收回权限,可以使用如下语句。revoke all on HR.Employees from r_test--ALL 权限已不再推荐使用,并且只保留用于兼容性目的。它并不表示对实体定义了 ALL 权限。

拓扑排序、广义表、子网掩码、数的互质概念

拓扑排序:就是将有向无环图进行拓扑排序,使得所有顶点排序成一个有向的线性序列(满足顶点间的前区后继或先后关系),的过程叫拓扑排序,排好的图叫AOV网。
关键路径:有向图或有向网中顶点表示事件,弧(箭头)表示活动,弧上的权值表示活动持续时间,这样的有向图叫活动的网,即AOE网。求源点到汇点的最长路径称为AOE的关键路径。
广义表:它是一种非线性的数据结构,是线性表的一种推广,即广义表中放松对表元素的原子限制。
子网掩码:10.11.12.91/28,表示从10开始的28位,表示网络地址,后4位表示主机地址。255.255.255.224表示前27位用做网络地址,后5位用做主机地址(2^5=32,去掉全0的网络号和全1的广播号,有30个可用地址),与10.11.12.91/27同一个意思。子网掩码是划分子网用的,有的时候公司申请了某类(A、B、C)地址,并需要将改地址划分成多个子网,这时就需要子网掩码,根据最大主机数和子网数来确定子网的位数。如果需要判断两个主机地址是否属于同一子网,只需判断两地址与其子网掩码与的结果是否相同即可。对于A类地址来说,默认的子网掩码是255.0.0.0;对于B类是255.255.0.0;对于C类是255.255.255.0。
互质:两个数的公约数为1。

求二维数组中从左下角到右上角的路径最大值(只可以向上向右移动)

动态规划,新建一个二维数组保存其中每个位置的最大路径值。先求M(n,i)和M(j,n),然后比较其左边和下边的值,取最大。
参阅(http://blog.csdn.net/z702143700/article/details/48832379)

求集合A中的两个子集合B、C使得sum(B)*sum(C)最大

这题我觉得有难度,需要仔细摸索,提示:数组分割来做。

脏页

指为提高读写速度,将磁盘上的数据缓存到高速缓存中,系统中数据的单位是以页为单位管理,如果高速缓存中的数据被进程修改,这时这个数据就叫脏页

笔试写代码的一点感悟

  • 如果1分钟内没有想到更好的解法,就应该直接考虑用最普通的方法实现。在实现的过程中,也许会冒出比较好的想法。
  • 写之前或写完代码之后一定要尝试各种测试用例。这样才能防止边界问题和非法输入问题。
  • 算法一定要关注边界条件、特殊输入、错误处理

写在最后

虽然还有好多都在笔记本上没有写下了,很多很长很粗糙的总结没有在这里写,略微感觉不满意。一点建议,找工作的过程中一定要不懂的弄懂弄透彻!慢慢的你会发现没那么容易被虐了!
当我写这最后一段话的时候,我已经签了qunar,最多的时候一天笔试4场或者3场笔试加一次面试,基本满武汉各酒店的跑。笔试面试剩余时间还需要将在笔试面试过程中不懂的记录下来,并研究透彻,时间各种不够用。最深体会的就是,累!最深的感触就是,各种被虐!

0 0