16年面试提问
2016-02-23 21:26 sylar_liang 阅读(290) 评论(0) 编辑 收藏 举报2016-2-23面试提问:
1.什么是句柄?
句柄是一个32位的证书,是windows在内存中维护的一个对象(窗口等)内存物理地址列表的整数索引。
句柄是指使用的一个唯一的整数值,用来标识应用程序中的不同对象和同类中的不同的实例。
2.什么是哈希表,哈希表原理是什么,哈希表的提出主要用来解决什么问题?
>哈希表最大的优点:把数据的存储和查找消耗的时间大大降低,几乎可以看成是常数时间,而代价仅仅是消耗比较多的内存。
>什么时候适合应用哈希表?
某个元素是否在已知集合中,也就是需要高效得数据存储和查找。
设计一个好的哈希函数很关键,而好的标准就是较低的冲突率和易于实现。
>基本原理:
使用一个下标范围都比较大的数组来存储元素,可以设计一个函数,使得每个元素的关键字都与一个函数值(即数组下标)相对应。但不能保证每个元素的关键字与函数值一一对应,不同的元素却计算出相同的函数值,这就产生了冲突。
3.常用的排序算法。6种,时间复杂度,空间复杂度,稳定度。
1>冒泡排序。(从后往前比)
#define MAX_SIZE 10
typedef struct { int data[MAX_SIZE]; int nLen; }SqList; // 交换SqList中下标为i和j元素。 void swap(SqList *L, int i, int j) { int temp = L->data[i]; L->data[i] = L->data[j]; L->data[j] = temp; } void BubbleSort(SqList *array) { for(int i=0; i<array->nLen-1; ++i) // 比较的次数。下标从0开始算。 { for(int j=array->nLen-2; j>=i; j--) // 从尾部开始往前比较。 { if( array->data[j] > array->data[j+1] ) // 若前者大于后者 { swap(array, j, j+1); } } } } 改进的冒泡排序:添加一个标志位,假如标志位为假,则不进入循环内比较 void BubbleSort2(SqList *array) { bool flag = true; for(int i=0; i<array->nLen-1 && flag; ++i) // 假如flag为0,说明没有变动,不再往下循环比较。 { flag = false; // 初始化为false for(int j=array->nLen-2; j>=i; j--) { if( array->data[j] > array->data[j+1] ) { swap(array, j, j+1); flag = true; // 有改变则置1 } } } }
2>选择排序。 (从前往后比)
关键点:从前往后逐个比较,查找最小的小标,再将最小下标的元素与当前位置交换。
在待排序的n个记录中选择一个最小的记录需要比较n-1次。
void SelectSort(SqList *array) { int min; for(int i=0; i<array->nLen-1; ++i) // 比较的次数 { min = i; for(int j=i+1; j<array->nLen; j++) { if( array->data[min] > array->data[j] ) { min = j; // 获取最小值下标 } } if(min != i) // min不等于i,说明找到最小值下标了。 swap(array, i, min); } }
3>直接插入排序。(从2开始,与前一个比较)
直接插入排序:将一个记录插入到已经排好序的有序表中,从而得到一个新的、记录数增1的有序表。
// 数组第0位 作为 哨兵
void InsertSort(SqList *array) { int i, j; for(i=2; i<array->nLen; ++i) // a[0] 哨兵, 也算进 nLen长度里。这里是i<nLen,没有=,否则5个元素,会出现a[5]越界了。 { if( array->data[i] < array->data[i-1] ) // 从2开始比较,跟前一个比较 { array->data[0] = array->data[i]; // 把 较小值 存进 哨兵 for(j=i-1; array->data[j] > array->data[0]; --j ) // 与哨兵逐一比较, j是自减 { array->data[j+1] = array->data[j]; // 往后移位 } array->data[j+1] = array->data[0]; // 赋值给j+1, 将哨兵插入到正确的位置 } } }
4>希尔排序: 将相距某个"增量"的记录组成一个子序列。
关键不是随便分组后各自排序,而是将相隔某个"增量"的记录组成一个子序列,实现跳跃式的移动,使得排序的效率提高。
☆增量的选取非常关键。
基本排序:小的在前面,大的在后边,不大不小的在中间。
// 存在 a[0] 作为哨兵 void ShellSort(SqList *array) { int i, j; int add = array->nLen; // 增量初始化 为 SqList元素个数 do { add = add/3 + 1; // 设置增量. 这个值很关键,后续直接影响到排序的效率。 for(i=add+1; i<array->nLen; ++i) { if( array->data[i] < array->data[i-add] ) { array->data[0] = array->data[i]; // 暂存进哨兵 for(j=i-add; j>0 && array->data[0] < array->data[j]; j -= add) // 哨兵元素 比较小,则互换位置 { array->data[j+add] = array->data[j]; // 记录后移 } array->data[j+add] = array->data[0]; // 把哨兵值 存入。 } } } while(add > 1); }
5>堆排序。
6>归并排序。
7>快速排序
4.http协议。
>超文本协议。
>超文本传输协议URL= “http:” “//” 主机名【":"端口号(可选)】【绝对路径【"?"查询】】。
>通常使用TCP/IP连接,缺省是80端口。
http协议请求:包括请求行,消息报头,请求正文。
http响应:状态行,消息报头,响应正文。
请求:数据长度,字符集,接受html文本,编码格式,语言,授权,主机host,
响应:Location重定向,Server服务器类型,
GET与POST区别?
?GET用于获取数据,POST用户发送数据
?POST比GET安全。
?GET对URL长度有限制,1024,POST没有。
5.DNS与ARP分别指什么?
>DNS(Domain Name System):域名系统。使用户不用去记IP数串。每个IP地址都可以有一个主机名。
通过主机名,最终得到该主机名对应的IP地址的过程叫做域名解析。
>主机名到IP地址的映射有2种方式:
静态映射:每台设备上都配置主机到IP地址的映射。
动态映射:建立一套域名解析系统,使用主机名通信的设备时,先到DNS服务器查找对应的IP地址。
>ARP(Address Resolution Protocol):地址解析协议。是根据IP地址获取物理地址的一个TCP/IP协议。
6.Socket的类型。
1>SOCK_STREAM流套接字:读取TCP协议的数据,提供面向连接的、可靠的数据传输服务。该服务能保证数据能够实现无差错无重复发送,并按顺序接收。
2>SOCK_DGRAM数据报套接字:读取UDP协议的数据,提供一种无连接的服务。不保证数据传输的可靠性。
3>SOCK_RAW原始套接字:可以读取内核没有处理的IP数据包。
7.select与epoll的实现,他们的共同点与区别。
>select几大缺点:相关函数(FD_ZERO,FD_SET,FD_CLR,FD_ISSET)
1>每次调用select,都需要把fd集合从用户态拷贝到内核态,这个开销在fd很多时很大。
2>每次调用select都需要在内核遍历传递进来的所有fd,这个开销在fd很多时也很大。
3>select支持的文件描述符数量太小了,默认为1024.
>epoll
1>epoll是在每次注册新的事件到epoll句柄中时(EPOLL_CTL_ADD),会把所有的fd拷贝进内核,而不是在epoll_wait时重复拷贝。epoll保证了每个fd在整个过程只会拷贝一次。
2>epoll只用维护一个队列,看队列是否为空就可以了。epoll只会对活跃的socket进行操作,只有活跃的fd才会主动去调用对应的callback函数。
3>epoll没有文件描述符的限制。
区别:
>select的句柄数目受限(最多同时监听1024个fd,因为内核代码的限制)。epoll则没有,它的限制是最大的打开文件句柄数。
>select采用的是轮询处理,其中的数据结构类似以个数组的数据结构,而epoll是维护一个队列,直接看队列是否为空就可以。
8.进程与线程。
>进程是系统进行资源分配和调度的一个独立单位,线程是进程的一个实体,是CPU调度和分派的基本单位。
>进程有独立的地址空间。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,线程共享进程的地址空间。
>一个线程死掉就等于整个进程死掉,所以多进程的程序比多线程的程序健壮,但在进程切换时,耗费资源较大,效率差一点。
>线程执行开销小,但不利于资源的管理和保护,进程则相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。
SMP:一组处理器(多CPU)之间共享内存子系统以及总线结构。
9.抓包软件。
WireShark,HttpWatch。
10.linux下查看网络流量的命令。
>nload: (不是系统自带)快速查看总带宽使用情况,无需每个进程的详细情况。
查看系统端口使用情况
>netstat
netstat -tln 用来查看linux的端口使用情况
11.如何处理TCP黏包问题。
>现在主流且有效的做法就是加包头,不要考虑这些不实用的方式了。
>在发送每个数据包加上一个自定义的数据头,所以都没出现过黏包现象。
push的作用:对方的包源源不断的发过来,接收方的内核未必收到一个包就通知上层一次,如果包足够频繁,它可以积累一些一块通知上层。push标识就是告诉接收者,这个包尽快上报,最好不要缓存了。接收方看到这个标识,会酌情处理(看协议实现者的心情了)。
因此,所有的包都加了push,也不能保证不会粘包。
===========================
1.OSI参考模型:物理层,数据链路层,网络层(IP),传输层(TCP,UXP),会话层,表示层,应用层(HTTP,DNS,SMTP)。
TCP/IP五层模型:物理层,数据链路层,网络层,传输层,应用层。
2.串口通信(RS232):按位(bit)发送和接收。
>分为:单工(只能A->B,),半双(A->B,B->A,只能一个方向),全双工(允许双向传输)。
>将接受的串行数据转换为并行的数据字符传输给CPU器件。
串口通信最重要的参数是:
>波特率:衡量符号传输速率的参数。1个起始位,一个停止位,剩下数据位。
>数据位
>停止位
>奇偶校验:四种校错方式:奇,偶,高,低。
窗口通信编程:串口初始化,打开串口,发送读取数据命令,等待接受数据,数据处理与显示,关闭串口。
3.JTAG技术
========================================
2016-2-24面试提问:
1.String的4种构造函数。
// 构造函数
String::String(const char * ptr)
{
if(ptr == NULL)
{
m_pData = new char[1];
m_pData[0] = '\0';
}
else
{
int n = strlen(ptr);
m_pData = new char[n+1];
strcpy(m_pData, ptr);
}
}
// 析构函数
String::~String()
{
if(m_pData)
{
delete [] m_pData;
m_pData = NULL;
}
}
// 拷贝构造函数
String::String(const String & s1)
{
int n = strlen(s1.m_pData);
m_pData = new char[n+1];
strcpy(m_pData, s1.m_pData);
}
// 赋值构造函数
String & String::operator =(const String & s1)
{
if( this == &s1) // 检查自赋值
return *this;
delete [] m_pData;
int n = strlen(s1.m_pData);
m_pData = new char[n+1];
strcpy(m_pData, s1.m_pData);
return *this;
}
2.单链表的插入删除。
struct Node
{
int data;
Node * pNext;
};
3.什么是网络字节序、主机字节序?如何转换?
网络字节序是TCP/IP中规定好的一种数据表示格式,采用大端排序方式。
主机字节序是指整数在内存中保存的顺序。
高地址在低字节 大端。
高地址在高字节 小端。
如: 0x01020304
4000 4001 4002 4003
小 04 03 02 01
大 01 02 03 04
htons htonl ntohs ntohl
h 主机序
n 网络字节序
s 短整形
l 长整形
4.什么是虚拟内存?
虚拟内存是计算机系统内存管理的一种技术。当内存消耗完时,系统匀出一部分硬盘空间来充当内存使用,系统将数据移入分页文件来释放RAM。
5.MFC,API,STL,SSL等等分别代表什么。
MFC:Microsoft Foundation Classes 微软基础类库。
API:Application Programming Interface 应用程序编程接口。
STL:Standard Template Library 标准模板库。分为容器,迭代器,空间配置器,配接器,算法,仿函数。
SSL:Secure Sockets Layer 安全套接层。利用加密技术,确保数据在网络传输过程中不会被截取及窃听。
6.memcpy与memmove的区别?
memcpy是memmove的一个子集。
唯一的区别是,当内存发生局部重叠的时候,memmove保证拷贝的结果是正确的,memcpy不保证拷贝的结果正确。memmove内部定义了一个局部数组来作为中间的存储。所以memcpy效率高一点。
区别是它们处理内存区域重叠(overlapping)的方式不同。
7.12种常用的设计模式,分别用在什么情景下?
>简单工厂模式
>抽象工厂模式
>工厂模式
>策略模式
>装饰模式
>单例模式
>代理模式
>
x.数据结构查找方法
1>顺序表查找算法。复杂度O(n)
// a为数组,n为要查找的数组个数,key为要查找的关键字 for(int i=0; i<n; ++i) { if( a[i] == key ) return i; // 从0开始计数。 } return -1; // 失败返回-1 // 改良的顺序查找算法,添加哨兵。可在数组头部或者尾部添加哨兵。复杂度比上面的有所降低。 // a为数组,n为要查找的数组个数,key为要查找的关键字 a[0] = key; i = n; // 从尾部开始查找 while( a[i] != key ) // 因为添加了a[0],所以数组从1开始计数。 { i--; } return i;
2>有序表查找。复杂度O(logn)
>折半查找/二分法查找:前提是记录是有序的。一般是从小到大。
// int binarysearch(int *a, int len, int key) { int high,low; high = len - 1; low = 0; while(low <= high) { mid = (low+high)/2; if ( key < a[mid] ) high = mid-1; else if ( key > a[mid] ) low = mid + 1; else return mid; // 相等,则说明mid为要查找的位置 } return -1; // 失败返回-1 }
升级版:
>插值查找:关键字分布比较平均时适用。极度不平均的分布则不适用。
关键>>>mid = (low + high )/2 改为 mid = low + (key-a[low])/(a[high]-a[low])*(high-low);
关键计算公式: (key-a[low])/(a[high]-a[low])
>斐波那契查找。利用黄金分割原理
========================================
2016-2-25面试提问:
1.Windows下注册表有什么用?
2.写一个函数将字符串转换为数字。如"1234"-->1234
3.数据库的建表,插入,删除,查询语句。
4.二分法链表的查找。
5.Windows下进程间通信的方法,共享内存的原理是什么?Linux下进程通信的方法又有什么?
6.static在3种情况下的作用。
>在函数内声明
>在模块内声明
>在模块内,但不在函数内
7.继承有什么好处?多态的作用是什么?
8.int const a 与 const int a; const int *a; int * const a;
9.