物理块 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
逻辑记录 | R1 | R2 | R3 | R4 | R5 | R6 | R7 | R8 | R9 | R10 |
假设磁盘的旋转速度为20ms/周,磁盘当前处在R1的开头处,若系统顺序扫描后将数据放入单缓冲区内,处理数据的时间为4ms(然后再读取下个记录),则处理这10个记录的最长时间为(C)
A、180ms B、200ms C、204ms D、220ms
解析:磁盘会一直朝某个方向旋转,不会因为处理数据而停止。本题要求顺序处理R1到R10,起始位置在R1,一周是20ms,共10个记录,所以每个记录的读取时间为2ms。首先读R1并处理R1,读R1花2ms,读好后磁盘处于R1的末尾或R2的开头,此时处理R1,需要4ms,因为磁盘一直旋转,所以R1处理好了后磁盘已经转到R4的开始了,这时花的时间为2+4=6ms。这时候要处理R2,需要等待磁盘从R5一直转到R2的开始才行,磁盘转动不可反向,所以要经过8*2ms才能转到R1的末尾,读取R2需要2ms,再处理R2需要4ms,处理结束后磁盘已经转到R5的开头了,这时花的时间为2*8+2+4=22ms。等待磁盘再转到R3又要8*2ms,加上R3自身2ms的读取时间和4ms的处理时间,花的时间也为22ms,此时磁盘已经转到R6的开头了,写到这里,大家已经可以看到规律了,读取并处理后序记录都为22ms,所以总时间为6+22*9=204ms。
2.随着IP网络的发展,为了节省可分配的注册IP地址,有一些地址被拿出来用于私有IP地址,以下不属于私有IP地址范围的是(C)(私网IP地址:10.0.0.0- 10.255.255.255;172.16.0.0- 172.31.255.255;192.168.0.0-192.168.255.255。故选C)
A、10.6.207.84 B、172.23.30.28 C、172.32.50.80 D、192.168.1.100
3.已知一个线性表(38,25,74,63,52,48),假定采用散列函数h(key) = key%7计算散列地址,并散列存储在散列表A【0....6】中,若采用线性探测方法解决冲突,则在该散列表上进行等概率成功查找的平均查找长度为(C)
A、1.5 B、1.7 C、2.0 D、2.3
解析: 0 1 2 3 4 5 6
填入的数 63 48 7 25 74 52
查找次数 1 3 1 1 2 4
平均查找长度=(1+3+1+1+2+4)/6=2
辅助:
l
这种方法的特点是:冲突发生时,顺序查看表中下一单元,直到找出一个空单元或查遍全表。
l
l
具体实现时,应建立一个伪随机数发生器,(如i=(i+p) % m),并给定一个随机数做起点。
2.
当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。
3.
本例的平均查找长度
4、建立公共溢出区
基本思想是:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表
4.表达式“X=A+B*(C--D)/E”的后缀表示形式可以为(C)
A、XAB+CDE/-*= B、XA+BC-DE/*= C、XABCD-*E/+= D、XABCDE+*/=
5(B)设计模式将抽象部分与它的实现部分相分离。
A、Singleton(单例) B、 Bridge(桥接)
C、 Composite(组合) D、 Facade(外观)
6.下面程序的输出结果为多少?
- void Func(char str_arg[100])
- {
- printf("%d\n",sizeof(str_arg));
- }
- int main(void)
- {
- char str[]="Hello";
- printf("%d\n",sizeof(str));
- printf("%d\n",strlen(str));
- char *p = str;
- printf("%d\n",sizeof(p));
- Func(str);
- }
输出结果为:6 5 4 4
数组作为函数参数传递的时候,已经退化为指针了,Func函数的参数str_arg只是表示一个指针,那个100不起任何作用的。
《程序员面试宝典》相关题目:
答案: 4 11 100 4004 3 4 6 8 4 4
注:红色答案部分对应的题目为易错题!!!!!!!!!!!
类似的题目
下面程序的输出结果为多少?
- void Func(char str_arg[2])
- {
- int m = sizeof(str_arg); //指针的大小为4
- int n = strlen(str_arg); //对数组求长度,str_arg后面的那个2没有任何意义,数组已经退化为指针了
- printf("%d\n",m);
- printf("%d\n",n);
- }
- int main(void)
- {
- char str[]="Hello";
- Func(str);
- }
输出结果为: 4 5
7.到商店里买200的商品返还100优惠券(可以在本商店代替现金)。请问实际上折扣是多少?
由于优惠券可以代替现金,所以可以使用200元优惠券买东西,然后还可以获得100元的优惠券。
假设开始时花了x元,那么可以买到 x + x/2 + x/4 + ...的东西。所以实际上折扣是50%.(当然,大部分时候很难一直兑换下去,所以50%是折扣的上限)
如果使用优惠券买东西不能获得新的优惠券,那么
总过花去了200元,可以买到200+100元的商品,所以实际折扣为 200/300 = 67%.
其他答案:需要自己去完善条件。比如优惠券本次消费是否就可以使用,还是要等到下次消费才可用,优惠券在消费多少时才可以使用等。举个简单的例子,比如只能下次消费使用,且满200才可以使用其中的50元优惠券,这样实际折扣为(200+200-50)/400=8.9折,继续买下去,折扣可以在8折左右。
8.TCP靠什么来保证数据传输的可靠?
答案:选择重传ARQ
1】以字节为单位的滑动窗口
A------>B
A根据B给出的窗口值,构造自己的发送窗口
2】选择确认ACK
接收方收到字节流的序号不连续时,先收下这些数据,但把这些信息准确告诉发送方
解析:
1,TCP的连接管理:
运输连接的三个阶段:
连接建立
数据传送
连接释放
连接是一条虚连接,连接的2个端口号
建立虚连接:三次握手
释放虚连接:四次握手
2,可靠传输
选择重传ARQ
1】以字节为单位的滑动窗口
A------>B
A根据B给出的窗口值,构造自己的发送窗口
2】选择确认ACK
接收方收到字节流的序号不连续时,先收下这些数据,但把这些信息准确告诉发送方
3,流控
端到端的问题:让发送方的发送速率不要太快
通过滑动窗口实现,即发送方的发送窗口不能超过接收方给出的接收窗口的大小
4,拥塞控制
全局过程:防止过多数据注入网络,导致链路过载,
几个拥塞控制方法:
慢开始:小--->大增大发送窗口(拥塞窗口),
设置为最大报文段;
每收到一个对新报文段的确认,拥塞窗口就增加一个最大报文段
这样,每经过一个传输轮次,拥塞窗口就加倍
拥塞避免:拥塞窗口缓慢增大,每次经过一个往返时间RTT,发送方拥塞窗口+1, 而不是加倍。按线性规律缓慢增长。
慢开始门限值为发生拥塞时,拥塞窗口大小的一半,拥塞窗口设置为1,执行慢开始,当拥塞窗口=慢开始门限值时,改用拥塞避免算法
乘法减小:无论慢开始,拥塞避免阶段,只要出现拥塞,慢开始门限值减半,即设置为当前拥塞窗口的一半
加法增大:拥塞避免算法时,拥塞窗口线性缓慢增大,防止网络过早出现拥塞。
快重传:发送方只要连续收到三个重复确认,就立即重传报文段,不必等待重传计时器到期。尽早重传未被确认的报文段
快恢复:配合快重传
要点1】发送方连续收到三个重复确认时,执行”乘法减小“算法,把慢开始门限值减半【为了预防网络发生拥塞】,接下来不执行慢开始算法(拥塞窗口设为1)
2】发送方认为网络可能没有发生拥塞,拥塞窗口设为慢开始门限值减半后的数值,然后开始执行拥塞避免算法(加法增大),使拥塞窗口线性增大
8.
给定一个字符串,输出最长的重复子串
举例:ask not what your country can do for you,but what youcan do for your country
最长的重复子串:can do for you
思路:使用后缀数组解决
分析:
1、由于要求最长公共子序列,则需要找到字符串的所有子串,即通过产生字符串的后缀数组实现。
2、由于要求最长的重复子串,则需要对所有子串进行排序,这样可以把相同的字符串排在一起。
3、比较相邻字符串,找出两个子串中,相同的字符的个数。
注意,对于一个子串,一个与其重复最多的字符串肯定是紧挨着自己的两个字符串。
步骤:
1、对待处理的字符串产生后缀数组
2、对后缀数组排序
3、依次检测相邻两个后缀的公共长度
4、取出最大公共长度的前缀
举例:输入字符串 banana
1、字符串产生的后缀数组:
a[0]:banana
a[1]:anana
a[2]:nana
a[3]:ana
a[4]:na
a[5]:a
2、对后缀数组进行快速排序,以将后缀相近的(变位词)子串集中在一起
a[0]:a
a[1]:ana
a[2]:anana
a[3]:banana
a[4]:na
a[5]:nana
之后可以依次检测相邻两个后缀的公共长度并取出最大公共的前缀
代码:
- /*给定出一个字符串,输出最长的重复子字符串*/
- #include <iostream>
- #include <algorithm>
- #include <string>
- using namespace std;
- const int MaxCharNum = 5000000;
- bool StrCmp(char* str1,char* str2);
- void GenSuffixArray(char* str,char* suffixStr[]);
- int ComStrLen(char* str1,char* str2);
- void GenMaxReStr(char* str);
- int main()
- {
- char str[MaxCharNum];
- cin.getline(str,MaxCharNum);//遇到回车结束
- GenMaxReStr(str);
- system("pause");
- return 1;
- }
- void GenMaxReStr(char* str)
- {
- int len = strlen(str);
- int comReStrLen = 0;
- int maxLoc = 0;
- int maxLen = 0;
- char* suffixStr[MaxCharNum];
- GenSuffixArray(str,suffixStr);//产生后缀数组
- //对后缀数组进行排序
- sort(suffixStr,suffixStr+len,StrCmp);
- //统计相邻单词中相同的字符数,并输出结果
- for (int i = 0;i < len-1;i++ )
- {
- comReStrLen = ComStrLen(suffixStr[i],suffixStr[i+1]);
- if (comReStrLen > maxLen)
- {
- maxLoc = i;
- maxLen = comReStrLen;
- }
- }
- //输出结果
- for (int i = 0;i < maxLen;i++)
- {
- cout<<suffixStr[maxLoc][i];
- }
- cout<<endl;
- }
- /*为字符串产生其后缀数组,并存放到数组suffixStr中*/
- void GenSuffixArray(char* str,char* suffixStr[])
- {
- int len = strlen(str);
- for (int i = 0;i < len;i++)
- {
- suffixStr[i] = &str[i];
- }
- }
- /*返回str1和str2的共同前缀的长度*/
- int ComStrLen(char* str1,char* str2)
- {
- int comLen = 0;
- while(*str1 && *str2)
- {
- if (*str1 == *str2)
- {
- comLen++;
- }
- str1++;
- str2++;
- }
- return comLen;
- }
- //字符串升序排序
- bool StrCmp(char* str1,char* str2)
- {
- if (strcmp(str1,str2) >=0 )
- {
- return false;
- }
- return true;
- }
程序输入:ask not what your country can do for you,but what you can do for your country
输出:can do for you
时间复杂度分析:产生后缀数组-时间复杂度O(N)、对后缀数组排序是O(N*NlogN),第一个N表示字符串的比较,后面NlogN使用快排排序。依次检测相邻两个后缀的公共长度-时间复杂度O(N*N)、取出最大公共长度的前缀-时间复杂度O(N)。
总的时间复杂度是O(N*NlogN)
9.typedef char *String_t; 和 #define String_d char * 这两句在使用上有什么区别?
前者声明一个类型的别名,在编译时处理,有类型检查;后者是一个简单的替换,在预编译时处理,无类型检查。
从使用上来说,String_t a,b; a和b都是char* 类型的,但String_d a,b; 只有a是char*类型的,b是char型的。
考点:奇数与偶数.
专题:计算题.
分析:本题可以通过所给的变换规律,由易到难,确定操作可变为1的数组成斐波拉契数列,再根据所发现的规律求出经过9次操作变为l的数的个数.
解答:解:通过1次操作变为1的数为2,再经过一次操作变为2的数为4、1,即通过两次操作变为1的数为4、1,
再经过1次操作变为4的数有两个为3、8、2,即通过3次操作变为1的数有两个为3,8,…,
经过1、2、3、4、5…次操作变为1的数依次为1、2、3、5、8…,这即为斐波拉契数列,
后面的数依次为:13+8=21,21+13=34,34+21=55.
即经过9次操作变为1的数有55个.
已知有个rand7()的函数,返回1到7随机自然数,让利用这个rand7()构造rand10() 随机1~10
- int rand7()
- {
- return rand()%7+1;
- }
- int rand10()
- {
- int x=0;
- do
- {
- x=(rand7()-1)*7+rand7();
- }
- while(x>40);
- return x%10+1;
- }
下面说明为什么(rand7()-1)*7+rand7()可以构造出均匀分布在1-49的随机数:
首先rand7()-1得到一个离散整数集合{0,1,2,3,4,5,6},其中每个整数的出现概率都是1/7。那么(rand7()-1)*7得到一个离散整数集合A={0,7,14,21,28,35,42},其中每个整数的出现概率也都是1/7。而rand7()得到的集合B={1,2,3,4,5,6,7}中每个整数出现的概率也是1/7。显然集合A和B中任何两个元素组合可以与1-49之间的一个整数一一对应,也就是说1-49之间的任何一个数,可以唯一确定A和B中两个元素的一种组合方式,反过来也成立。由于A和B中元素可以看成是独立事件,根据独立事件的概率公式P(AB)=P(A)P(B),得到每个组合的概率是1/7*1/7=1/49。因此(rand7()-1)*7+rand7()生成的整数均匀分布在1-49之间,每个数的概率都是1/49。
ps:用while(x>40)而不用while(x>10)呢?原因是如果用while(x>10)则有40/49的概率需要循环while,很有可能死循环了。
——————————————————————————————————————————————————————————————————————
其他题目:链接http://jingyan.baidu.com/article/2d5afd69b7b5f785a2e28eb0.html
1】const的含义及实现机制?
const用来说明所定义的变量是只读的。
这些在编译期间完成,编译器使用常量直接替换掉const变量
int main(void)
{
const int n = 1 ;
int *p = (int *)&n ;
*p = 0 ;
cout << n << endl ;
cout << *p << endl ;
return 0;
}//输出1 0
注:const的几个用法
(1)const定义常量:
const dataType constData=value;//const修饰的类型为dataType的变量value不可变.
(2)指针中使用const,主要有三种方式
a.指针本身是常量,它本身不可变
char* const ptr;
b.指针所指向的内容是常量,指向的内容不可变
const char* ptr;
c.两者都不可变
const char* const ptr;
(3)函数中使用const
a.传指针参数前添加const
void* A(const char* Str); //Str指向的内容被修饰为常量
b.传引用参数前添加const
void* A(const ClassType &obj); //obj在函数体内被修饰为常量
(4)类中使用const
a.使用const修饰成员变量
使用const修饰类的成员,表示成员常量,它只能在初始化列表中赋值。如:
class A
{
A(int x): val(x) { } ; //在初始化列表中定义
const int val; //成员常量
}
b.使用const修饰类的成员函数,如 int getNum(int a)const;
这样当程序修改了类的数据成员或调用了非const成员函数时,编译器就会报错。
c.使用const修饰类的对象,或者类对象引用或指针
这对象中的所有数据成员都不能被修改,对于对象指针或对象引用也一样。
在这种情况下,同时不能通过对象名调用对象中的非const成员,这符合安全规则。
2】tcp三次握手的过程,accept发生在三次握手哪个阶段?
accept发生在三次握手之后。
第一次握手:客户端发送syn包(syn=j)到服务器。
第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个ASK包(ask=k)。
第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1)。
三次握手完成后,客户端和服务器就建立了tcp连接。这时可以调用accept函数获得此连接。
3】用UDP协议通讯时怎样得知目标机是否获得了数据
可以在每个数据包中插入一个唯一的ID,比如timestamp或者递增的int。
发送方在发送数据时将此ID和发送时间记录在本地。
接收方在收到数据后将ID再发给发送方作为回应。
发送方如果收到回应,则知道接收方已经收到相应的数据包;如果在指定时间内没有收到回应,则数据包可能丢失,需要重复上面的过程重新发送一次,直到确定对方收到。
4】求一个论坛的在线人数,假设有一个论坛,其注册ID有两亿个,每个ID从登陆到退出会向一个日志文件中记下登陆时间和退出时间,要求写一个算法统计一天中论坛的用户在线分布,取样粒度为秒。
一天总共有 3600*24 = 86400秒。
定义一个长度为86400的整数数组int delta[86400],每个整数对应这一秒的人数变化值,可能为正也可能为负。开始时将数组元素都初始化为0。
然后依次读入每个用户的登录时间和退出时间,将与登录时间对应的整数值加1,将与退出时间对应的整数值减1。
这样处理一遍后数组中存储了每秒中的人数变化情况。
定义另外一个长度为86400的整数数组int online_num[86400],每个整数对应这一秒的论坛在线人数。
假设一天开始时论坛在线人数为0,则第1秒的人数online_num[0] = delta[0]。第n+1秒的人数online_num[n] = online_num[n-1] + delta[n]。
这样我们就获得了一天中任意时间的在线人数。
5】在一个文件中有 10G 个整数,乱序排列,要求找出中位数。内存限制为 2G。
不妨假设10G个整数是64bit的。
2G内存可以存放256M个64bit整数。
我们可以将64bit的整数空间平均分成256M个取值范围,用2G的内存对每个取值范围内出现整数个数进行统计。这样遍历一边10G整数后,我们便知道中数在那个范围内出现,以及这个范围内总共出现了多少个整数。
如果中数所在范围出现的整数比较少,我们就可以对这个范围内的整数进行排序,找到中数。如果这个范围内出现的整数比较多,我们还可以采用同样的方法将此范围再次分成多个更小的范围(256M=2^28,所以最多需要3次就可以将此范围缩小到1,也就找到了中数)。6】 两个整数集合A和B,求其交集
答案:使用map。扫描A,设置为1,然后扫描B
腾讯笔试题:判断数字是否出现在40亿个数中?
给40亿个不重复的unsigned int的整数,没排过序的,然后再给几个数,如何快速判断这几个数是否在那40亿个数当中?
答案:
unsigned int 的取值范围是0到2^32-1。我们可以申请连续的2^32/8=512M的内存,用每一个bit对应一个unsigned int数字。首先将512M内存都初始化为0,然后每处理一个数字就将其对应的bit设置为1。当需要查询时,直接找到对应bit,看其值是0还是1即可。