这里用来记录我积累的面试题
基本
1.c++虚函数
解答:
这个直接百度吧:http://baike.baidu.com/view/161302.htm
2.C语言,下面两个表达式是否相等
if(strlen(x)>=strlen(y))...
if(strlen(x)-strlen(y)>=0)...
解答:
不一定相等。第二条语句结果永远为真。strlen的返回值是无符号整数。两个无符号整数的结果也是无符号整数,结果永远为真。
3.请列举面向对象设计的三个基本要素及五种主要设计原则。
http://blog.163.com/lee_020/blog/static/1247556020129237189609/
4.简述windows内存管理的几种方式及其优缺点。
5.简述数据库以及线程产生的原理及其必要条件。
http://www.cnblogs.com/cxd4321/archive/2012/05/28/2521542.html
6.C++的内存分配几种方式及其注意事项。
内存的三种分配方式:
1. 从静态存储区分配:此时的内存在程序编译的时候已经分配好,并且在程序的整个运行期间都存在。全局变量,static变量等在此存储。
2. 在栈区分配:相关代码执行时创建,执行结束时被自动释放。局部变量在此存储。栈内存分配运算内置于处理器的指令集中,效率高,但容量有限。
3. 在堆区分配:动态分配内存。用new/malloc时开辟,delete/free时释放。生存期由用户指定,灵活。但有内存泄露等问题。
有一篇blog讲c++内存管理的,很不错。
http://www.cnblogs.com/lancidie/archive/2011/08/05/2128318.html
7.稳定的排序算法有哪几种?
快速排序、希尔排序、堆排序、直接选择排序不是稳定的排序算法,而基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序是稳定的排序算法
http://baike.baidu.com/view/547325.htm?fromTaglist
堆排序:
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
using namespace std;
void max_heapify(int *a,int i,int heap_size){//保持堆的性质
int L=2*i;
int R=2*i+1;
int largest=i;
if(L<=heap_size&&a[L-1]>a[largest-1])
largest=L;
if(R<=heap_size&&a[R-1]>a[largest-1])
largest=R;
if(largest!=i){
swap(a[i-1],a[largest-1]);
max_heapify(a,largest,heap_size);
}
}
void build_max_heap(int *a ,int heap_size){//建堆
int i;
for(i=heap_size/2;i>=1;i--){
max_heapify(a,i,heap_size);
}
}
void heap_sort(int *a,int len){//堆排序
int heap_size=len;
build_max_heap(a,len);
int i;
for(i=len;i>=2;i--){
swap(a[0],a[i-1]);
heap_size--;
max_heapify(a,1,heap_size);
}
}
void print_a(int *a,int len){
int i;
for(i=0;i<len;i++)
printf("%d ",a[i]);
printf("\n");
}
int main()
{
int a[]={1,0,1,5,6,3,2,4};
int len=sizeof(a)/sizeof(int);
print_a(a,len);
heap_sort(a,len);
print_a(a,len);
return 0;
}
8.面向对象中,const 函数的处理,出现继承是又怎么处理?
9.类似printf能够接受变长字符串 call?
10c#/java的多维数组。
http://www.cnblogs.com/tianhao960/articles/273425.html
11.shared_ptr,auto_ptr
12单例模式
http://blog.csdn.net/boyhailong/article/details/6645681
13 const的基本概念。
http://baike.baidu.com/view/1065598.htm
14.TCP/IP协议分了几层?每一层有哪些功能?为什么要有网络层?
http://baike.soso.com/v6873774.htm
15. TCP协议的三次握手分析?
http://www.cnblogs.com/rootq/articles/1377355.html
16.调用惯例
http://blog.csdn.net/zhu_liangwei/article/details/9703383
17.linux shell 修改文件
当前文件夹下有一组文件,都包含了一个文件头#include "1234",把它们都改为“5566”。
sed -i 's/1234/5566/' *
17.重载函数
出现在相同作用域中的两个函数,如果具有相同的名字而形参不同,则成为重载函数。
函数不能仅仅基于不同的返回值类型而实现重载。
任何程序都经由一个main函数实例。main函数不能重载。
函数重载确定(即函数配匹)是将函数调用与重载函数集合中的一个函数相关联的过程。通过自动提取函数调用中实际使用的实际参数与重载集合中各个函数提供的形参做比较,编译器实现该调用与函数匹配。匹配结果有三种可能:
(1)编译器找到与实惨最佳匹配的函数,并生成调用该函数的代码。
(2)找不到形参与函数调用的实参匹配的函数,这种情况下,编译器将给出编译错误信息。
(3)存在多个与实参匹配的函数,但没有一二是明确的最佳选择。这种情况也是错误的,该调用具有二义性。
void f();
void f(int);
void f(int, int);
void f(double,double = 3.14);
函数调用:f(42,2.56)
重载确定的三个步骤:
1.候选函数:确定该调用所考虑的重载函数集合。
2.选择可行函数:从候选函数中选择一个或多个函数,它们能够用该调用中指定的实参来调用。f(int ,int),f(double,double).
3.寻找最佳匹配(如果有):原则是实参类型与形参类型越接近则匹配越佳。
注意:如果函数名相同,在相同的作用域内,其参数类型、参数个数,参数顺序不同等能构成函数重载。有趣的是如果同时在类中,对于函数名相同的const函数和非const函数能够构成重载,同时它们被调用的时机为:如果定义的对象是常对象,则调用的是const成员函数,如果定义的对象是非常对象,则调用重载的非const成员函数。http://xingyunbaijunwei.blog.163.com/blog/static/76538067201221010412519/
4.含有多个形参的重载确定
编译器通过依次检查每一个实例来决定哪个或那些函数匹配最佳。如果有且仅有一个函数满足下列条件,则匹配成功:
(1)其每个实参的匹配都不劣于其他可行函数需要的匹配。
(2)至少有一个实参的匹配由于其他可行函数提供的匹配。
检查了所有实参后,仍找不到唯一最佳匹配函数,则该调用错误。这个例子具有二义性。错误。
18:ACID:.数据库事务正确执行的四个基本要素
19. linux启动流程:
BIOS->MBR->gurb->load kernel->init->rc.sysinit->load kernel modules->r0.d~r6.d->rc.local->/bin/login
20.shell:删除文件的第一行、中间某一行、删除注释、替换某个字符串?
删除第n行,这里n为3
sed 3d text.txt
从第三行开始,每隔一行删除
$sed 3~2d text.txt
删除从第4行到第8行
$sed 4,8d text.txt
删除最后一行
$sed '$'d text.txt
行匹配删除
$sed /Sysadmin/d text.txt
删除匹配行和之后两行
$sed '/Storage/,+2d' thegeekstuff.txt
从匹配行到末尾行
$sed '/Website Design/,$d' thegeekstuff.txt
删除空行
$sed '/^$/d' thegeekstuff.txt
21.僵尸进程、孤儿进程?
22.gdb 调试,条件断点、watch等
23.linux内核压缩,几种linux内核Image文件的区别,。
1、vmlinux 编译出来的最原始的内核文件,未压缩。
2、zImage 是vmlinux经过gzip压缩后的文件。
3、bzImage bz表示“big zImage”,不是用bzip2压缩的。两者的不同之处在于,zImage解压缩内核到低端内存(第一个640K),bzImage解压缩内核到高端内存(1M以上)。如果内核比较小,那么采用zImage或bzImage都行,如果比较大应该用bzImage。
4、uImage U-boot专用的映像文件,它是在zImage之前加上一个长度为0x40的tag(64个字节,说明这个映像文件的类型、加载位置、生成时间、大小等信息)。其实就是一个自动跟手动的区别,有了uImage头部的描述,u-boot就知道对应Image的信息,如果没有头部则需要自己手动去搞那些参数。换句话说,如果直接从uImage的0x40位置开始执行,zImage和uImage没有任何区别。
5、vmlinuz 是bzImage/zImage文件的拷贝或指向bzImage/zImage的链接。
6、initrd 是“initial ramdisk”的简写。一般被用来临时的引导硬件到实际内核vmlinuz能够接管并继续引导的状态
http://blog.sina.com.cn/s/blog_4a70d5d901012jxp.html
25.CAS
所谓CAS指Compare and Set(或Compare and Swap)。现在几乎所有CPU指令都支持CAS,如X86的CMPXCHG汇编指令。CAS通常被视为无锁(lock free)数据结构的基础。
CAS有三个操作数: 内存位置(V)、预期原值(A)和新值(B)。如果内存位置V的值与预期A原值相匹配,那么处理器会自动将该位置值更新为新值B。否则,处理器不做任何操作。无论哪种情况,它都会在 CAS 指令之前返回该位置的值。(在 CAS 的一些特殊情况下将仅返回 CAS 是否成功,而不提取当前值。)CAS 有效地说明了“我认为位置 V 应该包含值 A;如果包含该值,则将 B 放到这个位置;否则,不要更改该位置,只告诉我这个位置现在的值即可。
26.setjmp,longjump
为了更好地、更方便地支持异常处理编程机制,使得程序员在C语言开发的程序中,能写出更高效、更友善的带有异常处理机制的代码模块来。于是,C语言中出现了一种更优雅的异常处理机制,那就是setjmp()函数与longjmp()函数。
setjmp是C标准库中提供的一个函数,它的作用是保存程序当前运行的一些状态。它的函数原型如下:
int setjmp( jmp_buf env );
setjmp函数用于保存程序的运行时的堆栈环境,接下来的其它地方,你可以通过调用longjmp函数来恢复先前被保存的程序堆栈环境。当 setjmp和longjmp组合一起使用时,它们能提供一种在程序中实现“非本地局部跳转”("non-local goto")的机制。并且这种机制常常被用于来实现,把程序的控制流传递到错误处理模块之中;或者程序中不采用正常的返回(return)语句,或函数的正常调用等方法,而使程序能被恢复到先前的一个调用例程(也即函数)中。
http://se.csai.cn/ExpertEyes/No152.htm
27:LRU和LFU
LRU是最近最少使用页面置换算法(Least Recently Used),也就是首先淘汰最长时间未被使用的页面!
LFU是最近最不常用页面置换算法(Least Frequently Used),也就是淘汰一定时期内被访问次数最少的页!
比如,第二种方法的时期T为10分钟,如果每分钟进行一次调页,主存块为3,若所需页面走向为2 1 2 1 2 3 4
注意,当调页面4时会发生缺页中断
若按LRU算法,应换页面1(1页面最久未被使用) 但按LFU算法应换页面3(十分钟内,页面3只使用了一次)
可见LRU关键是看页面最后一次被使用到发生调度的时间长短,
而LFU关键是看一定时间段内页面被使用的频率
操作系统
1.进程间通信方式。
2.进程和线程的基本概念。
设计模式
1.MVC
网络
1..tcp协议的特点
2.HTTP 状态码?302、403、404、500、502?
302:Found
请求的网页已临时移动到新位置,即临时重定向。指示请求的信息位于 Location 头中指定的 URI 处。 接收到此状态时的默认操作为遵循与响应关联的 Location 头。 原始请求方法为 POST 时,重定向的请求将使用 GET 方法
403:Forbidden
资源不可用。服务器理解客户的请求,但拒绝处理它。通常由于服务器上文件或目录的权限设置导致
404:Not Found
无法找到指定位置的资源。这也是一个常用的应答。
500:Internal Server Error
服务器遇到了意料不到的情况,不能完成客户的请求:
502:Bad Gateway
服务器作为网关或者代理时,为了完成请求访问下一个服务器,但该服务器返回了非法的应答。 亦说Web 服务器用作网关或代理服务器时收到了无效响应 ·
算法
1.非递归中序(后序,先序)遍历二叉树
2.只用位运算求a+b
#include<stdio.h>
int add(int a,int b)
{
int s,w,tmp;
s=a^b;
w=a&b;
while(w){
tmp=s;
s=s^(w<<1);
w=tmp&(w<<1);
}
return s;
}
int main()
{
int a,b;
scanf("%d%d",&a,&b);
printf("a+b=%d\n",add(a,b));
return 0;
}
简单版本函数
int add2(int a,int b)
{
if(b)
return add2(a^b,(a&b)<<1);
else
return a;
}
3.用只能产生1-5之间随机数的函数,产生1-7的随机数。
http://hawstein.com/posts/19.10.html
4.一个大小为n的数组,里面的数都属于范围[0, n-1],有不确定的重复元素,找到至少一个重复元素,要求O(1)空间和O(n)时间。
http://blog.csdn.net/morewindows/article/details/8204460
http://blog.csdn.net/morewindows/article/details/8212446
仿照这篇文章粗略写了一个:
#include<stdio.h>
int FindRepeat(int *a,int n)
{
int i;
for(i=0;i<n;i++){
int tmp=a[i]>=n?a[i]-n:a[i];
if(a[tmp]>=n)
return tmp;
else
a[tmp]+=n;
}
return -1;
}
void printarray(const int *a,int n)
{
int i;
for(i=0;i<n;i++)
printf("%4d",a[i]);
printf("\n");
}
int main()
{
#define N 10
int a[N]={0,3,2,4,5,4,7,6,9,0};
printarray(a,N);
printf("%d\n",FindRepeat(a,N));
return 0;
}
5.公司组织一次羽毛球比赛,采用淘汰制,假设公司有1001个人,如果要评出“羽毛球第一”至少要进行多少场的比赛?请简述过程,并编写代码模拟比赛过程?(百度)
想法:1001一个人选出第一,一定要淘汰1000个人,一场比赛只可淘汰一个人,所有至少1000场比赛。
6一百个灯泡排成一排,第一轮将所有灯泡打开;第二轮每隔一个灯泡关掉一个。即排在偶数的灯泡被关掉,第三轮每隔两个灯泡,将开着的灯泡关掉,关掉的灯泡打开。依次类推,第100轮结束的时候,还有几盏灯泡亮着?(百度)
http://www.51projob.com/a/baidu/20121009/1188.html
7.二分法查找,可以设定当出现重复数时,可选其中的最前一个(或最后一个)?
8.最短路径的求法。
9.在N个整数查找序列中的最大数和最小数 及 所需要的比较次数?
http://blog.csdn.net/zoushidexing/article/details/8798469
10.shell 中标准输出和错误输出的区别?(搜狐)
11.如何随机选取1000个关键字 。给定一个数据流,其中包含无穷尽的搜索关键字(比如,人们在谷歌搜索时不断输入的关键字)。如何才能从这个无穷尽的流中随机的选取1000个关键字? (Google,百度)
定义长度为1000的数组。
对于数据流中的前1000个关键字,显然都要放到数组中。
对于数据流中的的第n(n>1000)个关键字,我们知道这个关键字被随机选中的概率为 1000/n。所以我们以 1000/n 的概率用这个关键字去替换数组中的随机一个。这样就可以保证所有关键字都以 1000/n的概率被选中。
对于后面的关键字都进行这样的处理,这样我们就可以保证数组中总是保存着1000个随机关键字。
类似这一题:
给定一个未知长度的整数流,如何随机选取一个数
方法1.
将整个整数流保存到一个数组中,然后再随机选取。
如果整数流很长,无法保存下来,则此方法不能使用。
方法2.
如果整数流在第一个数后结束,则我们必定会选第一个数作为随机数。
如果整数流在第二个数后结束,我们选第二个数的概率为1/2。我们以1/2的概率用第2个数替换前面选的随机数,得到满足条件的新随机数。
....
如果整数流在第n个数后结束,我们选第n个数的概率为1/n。我们以1/n的概率用第n个数替换前面选的随机数,得到满足条件的新随机数。
....
利用这种方法,我们只需保存一个随机数,和迄今整数流的长度即可。所以可以处理任意长的整数流。
蓄水池抽象算法:http://blog.jobbole.com/42550/
12.给定一个固定长度的数组,将递增整数序列写入这个数组。当写到数组尾部时,返回数组开始重新写,并覆盖先前写过的数。请在这个特殊数组中找出给定的整数?(Google)
13.给定两个已排序序列,找出共同的元素。 (Google)
14.找到链表的倒数第m个节点。(Google)
想法:使用两个指针,并使它们指向的节点相距m-1个。然后同时向前移动两个指针,当一个指针指最后一个节点时,第二个指针指向倒数第m个节点。
15. 给定一个排序数组,如何构造一个二叉排序树(二叉查找树,Binary Sort Tree)?(Google)
16.将无向无环连通图转换成深度最小的树 (Goolge)
想法:题目可以等价于找到了两个叶节点,使得两个叶节点之间的距离最远。根节点就是这两个叶节点路径的中间点(或者中间两个点的任意一个)。我们可以每次都将连接度为1的节点删掉,直到最后只剩下1个或2个节点,则这一个节点,或者两个节点中的任意一个,就是我们要找的根节点。
17.有一个特殊的链表,其中每个节点不但有指向下一个节点的指针pNext,还有一个指向链表中任意节点的指针pRand,如何拷贝这个特殊链表? (Google,百度)
18.将字符串中的小写字母排在大写字母的前面 有一个由大小写组成的字符串,现在需要对它进行修改,将其中的所有小写字母排在大写字母的前面(大写或小写字母之间不要求保持原来次序)。
19.有n个红蓝绿3种不同颜色的球,随机排成一列。现在需要使同种颜色的球排在一起并且按红蓝绿的顺序。
荷兰国旗问题:http://blog.csdn.net/zhu_liangwei/article/details/10097657
20.一条线段截成3段组成三角形的概率
截出的任意三条线段长度都必须小于原线段长度的一半。
设固定长度为L的线段随意分成3段的长度分别是x 、y和z=L-(x+y),<x,y,z∈(0,L)>
x +y<L
三段能构成三角形,则
x+y>z, 即 x +y>(L-x-y), x +y>L/2
y+z>x, 即 y +(L-x-y)>x, x<L/2
z+x>y, 即 (L-x-y)+x>y, y<L/2
所求概率等于x+y=L/2、x=L/2、y=L/2三条直线所包围图形的面积除以直线(x+y)=L与x轴、y轴所包围图形的面积(图略)。
故将长度为1的线段随机折成三段,这三段能构成三角形的概率是
(L/2*L/2*1/2)÷(L*L*1/2)=L²/8÷L²/2=1/4
21:位运算实现加减乘除
int divide(int dividend, int divisor) {
// Start typing your C/C++ solution below
// DO NOT write int main() function
bool bNegative = false;
if((dividend>0&&divisor<0)||(dividend<0&&divisor>0))
bNegative = true;
long long a = dividend,b=divisor;
if(dividend<0)
a = -(long long)dividend;
if(divisor<0)
b = -(long long)divisor;
long long sum = 0;
long long res = 0;
long long cnt = 0;
while(a>=b) //注意是a>=b
{
sum = b;
cnt = 1;
while(sum+sum<=a)
{
sum += sum;
cnt += cnt;
}
res += cnt;
a -= sum;
}
if(bNegative)
res = -res;
return res;
}
http://blog.csdn.net/luckyxiaoqiang/article/details/6886489
http://jiyuede.blog.163.com/blog/static/3325192120130114281402/
23.5 实现string类
_string.h
class _string
{
friend std::istream& operator>>(std::istream& is, _string& a);
friend std::ostream& operator<<(std::ostream& os,_string& a);
public:
_string() //默认构造函数
{
length = 0;
b=new char[1];
b[0]='\0';
}
_string(char *a); //构造函数
_string(int n,char a);
~_string(); //析构函数
_string(_string &a); //复制构造函数
int size(){return length;} //获得字符串长度
_string operator+(const _string& a); //重载'+'操作符
_string& operator+=(const _string& a); //重载'+='操作符
_string& operator=(const _string& a); //重载赋值操作符
char& operator[]( int n); //重载下标操作符
_string substr(int pos,int n); //返回子字符串
_string substr(int pos); //返回子字符串
private:
char *b;
int length;
};
_string.cpp
// _string.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include<string.h>
#include"_string.h"
#include<stdlib.h>
using namespace std;
_string::_string(char *a) //构造函数
{
length = strlen(a);
b = new char[length+1];
for(int i= 0;i<length;i++)
{
b[i] = a[i];
}
b[length] = '\0';
}
_string::_string(int n,char a)
{
b=new char[n+1];
for(int i= 0;i<n;i++)
{
b[i] =a;
}
b[n] = '\0';
}
_string::~_string() //析构函数
{
delete []b;
length=0;
}
_string::_string(_string &a) //复制构造函数
{
length=a.size();
b=new char [length+1];
for(int i = 0;i<length;i++)
{
b[i] = a.b[i];
}
b[length] = '\0';
}
_string _string::operator+(const _string& a) //重载+
{
int newLen = length+a.length;
char *str;
str = new char[newLen+1];
int count = 0;
for(int i = 0;i<length;i++)
{
str[i] = this->b[i];
count++;
}
for(int i =0;count<newLen;count++,i++)
{
str[i] = a.b[i];
}
str[newLen] = '\0';
_string temp(str);
return temp;
}
_string& _string:: operator+=(const _string& a) //重载+=
{
int newLen = length+a.length;
char *str;
str = new char[newLen+1];
int count = 0;
for(int i = 0;i<length;i++)
{
str[i] = this->b[i];
count++;
}
for(int i =0;count<newLen;count++,i++)
{
str[i] = a.b[i];
}
str[newLen] = '\0';
_string temp(str);
*this=temp;
return *this;
}
_string& _string:: operator=(const _string &a) //重载=
{
if(this==&a)
return *this;
delete []b;
length = a.length;
b = new char[length+1];
for(int i = 0;i<length;i++)
{
b[i] = a.b[i];
}
b[length] = '\0';
return *this;
}
char& _string:: operator[]( int n) //重载下标操作符
{
if(n>length)
return b[length-1];
else
return b[n];
}
ostream& operator<<(ostream& os, _string& a) //重载输出符
{
os<<a.b;
return os;
}
istream& operator>>(std::istream& is, _string& a) //重载输入符
{
is>>a.b ;
a.length=strlen(a.b);
return is;
}
_string _string::substr(int pos, int n) //两个接受不同参数的substr函数,返回子字符串
{
char *p = new char[n+1];
for(int i=0;i<n;i++)
{
p[i]=b[pos];
pos++;
}
p[n]='\0';
_string k(p);
k.length=n;
return k;
}
_string _string::substr(int pos)
{
int len=length;
char *p=new char[len-pos+1];
int t=pos;
for(int i=0;t<len;t++,i++)
{
p[i]=b[t];
}
p[t]='\0';
_string k(p);
k.length=len-pos;
return k;
}
http://www.oschina.net/code/snippet_567425_11395
挑战你的逻辑
1.5个人分蛋糕
2.死囚犯猜帽子颜色
3.老鼠测试毒药。
有1000瓶药,其中有且只有一瓶是毒药。现在有10只小白鼠可用于测试毒药。小白鼠在服用毒药之后一个星期之后死亡。问,1.给你一个星期,如何测试出毒药?2.给你两个星期,你需要多少只老鼠?
4.等车概率问题
5.下棋输赢问题
6.电梯选楼层问题
7.海盗分金币问题
8.假定一个国家,生男孩的和生女孩的概率相等(0.5)。这个国家的父母特别喜欢男孩子,所有有孩子的家庭都要是在生一个男孩之后才停止生育。求问,若干年后,该国家的男女比例是多少?
9.现有140g沙子, 给你一台天平,天平只有7g和2g砝码各一个,让你称出90克的沙子出来?
10.给定一个数N,找出所有小于N的质数?
11.随机生成和为S的N个正整数?
这个解法很好:http://blog.csdn.net/morewindows/article/details/8439393
12.N个球中有且只有一个重量少于其他的球,外形相同。采用三次天平称重,N最多是多少?
13.如果在高速公路上30分钟内看到一辆车开过的几率是0.95,那么在10分钟内看到一辆车开过的几率是多少?(假设为常概率条件下)
这题的关键在于0.95是见到一辆或多辆汽车的概率,而不是仅见到一辆汽车的概率。在30分钟内,见不到任何车辆的概率为0.05。因此在10分钟内见不到任何车辆的概率是这个值的立方根,而在10分钟内见到一辆车的概率则为1减去此立方根,也就是大约63%。
参考资料:
编程之美
Pointers on C
C++ Primer
C Traps and Pitfalls谷歌笔试题:
http://tieba.baidu.com/p/1567915420