当前位置:首页阅读

2020年百度精选面试题及答案

2020年百度精选面试题及答案

答案

2020年百度精选面试题及答案

浏览器获取输入的域名

浏览器向域名系统 DNS 请求解析

DNS 解析出百度服务器的 IP 地址

浏览器与服务器建立 TCP 连接(默认端口 80)

浏览器发出 HTTP 请求,请求百度首页

服务器通过 HTTP 请求把首页文件发给浏览器

TCP 连接释放

浏览器解析首页文件,展示 web 界面

2. 请描述 C/C++程序的内存分区?

其实 C 和 C++的内存分区还是有一定区别的,但此处不作区分:

1)、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的值等。

操作方式类似于数据结构中的栈。

2)、堆区(heap) — 一般由程序员分配释放, 若程序员不释放,程序结束时可能由

OS 回

收 。注意它与数据结构中的堆是两回事,分配方式倒是类似于链表。

3)、全局区(静态区)(static)—,全局变量和静态变量的存储是放在一块的,初

始化的

全局变量和静态变量在一块区域, 未初始化的全局变量和未初始化的静态变量在相邻

的另

一块区域。 - 程序结束后由系统释放。

4)、文字常量区 —常量字符串就是放在这里的。 程序结束后由系统释放。

5)、程序代码区—存放函数体的二进制代码。

栈区与堆区的区别:

1)堆和栈中的存储内容:栈存局部变量、函数参数等。堆存储使用 new、malloc 申请

的变量等;

2)申请方式:栈内存由系统分配,堆内存由自己申请;

3)申请后系统的响应:栈——只要栈的剩余空间大于所申请空间,系统将为程序提供

内存,否则将报异常提示栈溢出。

堆——首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请

时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结

点链表 中删除,并将该结点的空间分配给程序;

4)申请大小的限制:Windows 下栈的大小一般是 2M,堆的容量较大;

5)申请效率的比较:栈由系统自动分配,速度较快。堆使用 new、malloc 等分配,较

慢;

总结:栈区优势在处理效率,堆区优势在于灵活;

内存模型:自由区、静态区、动态区;

根据 c/c++对象生命周期不同,c/c++的内存模型有三种不同的内存区域,即:自由存

储区,动态区、静态区。

自由存储区:局部非静态变量的存储区域,即平常所说的栈;

动态区: 用 new ,malloc 分配的内存,即平常所说的堆;

静态区:全局变量,静态变量,字符串常量存在的位置;

注:代码虽然占内存,但不属于 c/c++内存模型的一部分;

3. 快速排序的思想、时间复杂度、实现以及优化方法?

快速排序的三个步骤

(1)选择基准:在待排序列中,按照某种方式挑出一个元素,作为 基准(pivot);

(2)分割操作:以该基准在序列中的实际位置,把序列分成两个子序列。此时,在基准

左边的元素都比该基准小,在基准右边的元素都比基准大;

(3)递归地对两个序列进行快速排序,直到序列为空或者只有一个元素。

基准的选择:

对于分治算法,当每次划分时,算法若都能分成两个等长的子序列时,那么分治算法效

率会达到最大。

即:同一数组,时间复杂度最小的是每次选取的基准都可以将序列分为两个等长的;时

间复杂度最大的是每次选择的基准都是当前序列的最大或最小元素;

快排代码实现:

我们一般选择序列的第一个作为基数,那么快排代码如下:

void quicksort(vectorint v,int left, int right)

{

if(leftright)//false 则递归结束

{

int key=v[left];//基数赋值

int low = left;

int high = right;

while(lowhigh) //当 low=high 时,表示一轮分割结束

{

while(lowhighv[high] = key)//v[low]为基数,从后向前与基数比

{

high--;

}

swap(v[low],v[high]);

while(lowhighv[low] = key)//v[high]为基数,从前向后与基数比

{

low++;

}

swap(v[low],v[high]);

}

//分割后,对每一分段重复上述操作

quicksort(v,left,low-1);

quicksort(v,low+1,right);

}

}

注:上述数组或序列 v 必须是引用类型的形参,因为后续快排结果需要直接反映在原序

列中;

优化:

上述快排的基数是序列的第一个元素,这样的对于有序序列,快排时间复杂度会达到最

差的 o(n^2)。所以,优化方向就是合理的选择基数。

常见的做法“三数取中”法(序列太短还要结合其他排序法,如插入排序、选择排序等),

如下:

①当序列区间长度小于 7 时,采用插入排序;

②当序列区间长度小于 40 时,将区间分成 2 段,得到左端点、右端点和中点,我们对

这三个点取中数作为基数;

③当序列区间大于等于 40 时,将区间分成 8 段,得到左三点、中三点和右三点,分

别再得到左三点中的中数、中三点中的中数和右三点中的中数,再将得到的三个中数取

中数,然后将该值作为基数。

具体代码只是在上一份的代码中将“基数赋值”改为①②③对应的代码即可:

int key=v[left];//基数赋值

if (right-left+1=7) {

insertion_sort(v,left,right);//插入排序

return;

}else if(right-left+1=8){

key=SelectPivotOfThree(v,left,right);//三个取中

}else{

//三组三个取中,再三个取中(使用 4 次 SelectPivotOfThree,此处不具体展示)

}

需要调用的函数:

void insertion_sort(vectorint unsorted,int left, int right) //插入排序算法

{

for (int i = left+1; i = right; i++)

{

if (unsorted[i - 1]unsorted[i])

{

int temp = unsorted[i];

int j = i;

while (jleftunsorted[j - 1]temp)

{

unsorted[j] = unsorted[j - 1];

j--;

}

unsorted[j] = temp;

}

}

}

int SelectPivotOfThree(vectorint arr,int low,int high)

//三数取中,同时将中值移到序列第一位

{

int mid = low + (high - low)/2;//计算数组中间的元素的下标

//使用三数取中法选择枢轴

if (arr[mid]arr[high])//目标: arr[mid] = arr[high]

{

swap(arr[mid],arr[high]);

}

if (arr[low]arr[high])//目标: arr[low] = arr[high]

{

swap(arr[low],arr[high]);

}

if (arr[mid]arr[low]) //目标: arr[low] = arr[mid]

{

swap(arr[mid],arr[low]);

}

//此时,arr[mid] = arr[low] = arr[high]

return arr[low];

//low 的位置上保存这三个位置中间的值

//分割时可以直接使用 low 位置的元素作为枢轴,而不用改变分割函数了

}

这里需要注意的有两点:

①插入排序算法实现代码;

②三数取中函数不仅仅要实现取中,还要将中值移到最低位,从而保证原分割函数依然

可用。

4. 请描述 IO 多路复用机制?

IO 模型有 4 中:同步阻塞 IO、同步非阻塞 IO、异步阻塞 IO、异步非阻塞 IO;IO 多路

复用属于 IO 模型中的异步阻塞 IO 模型,在服务器高性能 IO 构建中常常用到。

同步异步是表示服务端的,阻塞非阻塞是表示用户端,所以可解释为什么 IO 多路复用

(异步阻塞)常用于服务器端的原因;

文件描述符(FD,又叫文件句柄):描述符就是一个数字,它指向内核中的一个结构体

(文件路径,数据区等属性)。具体来源:Linux 内核将所有外部设备都看作一个文件来

操作,对文件的操作都会调用内核提供的系统命令,返回一个 fd(文件描述符)。

下面开始介绍 IO 多路复用:

(1)I/O 多路复用技术通过把多个 I/O 的阻塞复用到同一个 select、poll 或 epoll 的

阻塞上,从而使得系统在单线程的情况下可以同时处理多个客户端请求。与传统的多线

程/多进程模型比,I/O 多路复用的最大优势是系统开销小,系统不需要创建新的额外

进程或者线程。

(2)select,poll,epoll 本质上都是同步 I/O,因为他们都需要在读写事件就绪后自

己负责进行读写,也就是说这个读写过程是阻塞的,而异步 I/O 则无需自己负责进行读

写,异步 I/O 的实现会负责把数据从内核拷贝到用户空间。

(3)I/O 多路复用的主要应用场景如下:

服务器需要同时处理多个处于监听状态或者多个连接状态的套接字;

服务器需要同时处理多种网络协议的套接字;

(4)目前支持 I/O 多路复用的系统调用有 select,poll,epoll,epoll 与 select 的

原理比较类似,但 epoll 作了很多重大改进,现总结如下:

①支持一个进程打开的文件句柄 FD 个数不受限制(为什么 select 的句柄数量受限制:

select 使用位域的方式来传递关心的文件描述符,因为位域就有最大长度,在 Linux

下是 1024,所以有数量限制);

②I/O 效率不会随着 FD 数目的增加而线性下降;

③epoll 的 API 更加简单;

(5)三种接口调用介绍:

①select 函数调用格式:

#include sys/select.h

#include sys/time.h

int select(int maxfdp1,fd_set *readset,fd_set *writeset,fd_set

*exceptset,const struct timeval *timeout)

//返回值:就绪描述符的数目,超时返回 0,出错返回-1

②poll 函数调用格式:

# include poll.h

int poll ( struct pollfd * fds, unsigned int nfds, int timeout);

③epoll 函数格式(操作过程包括三个函数):

#include sys/epoll.h

int epoll_create(int size);

int epoll_ctl(int epfd, int op, int fd, struct epoll_event *event);

int epoll_wait(int epfd, struct epoll_event * events, int maxevents, int

timeout);

(6)作用:一定程度上替代多线程/多进程,减少资源占用,保证系统运行的高效率;

5. 实践中如何优化 MySQL?

四条从效果上第一条影响最大,后面越来越小。

① SQL 语句及索引的优化

② 数据库表结构的优化

③ 系统配置的优化

④ 硬件的优化

2020年百度精选面试题及答案_WWW.XUNWANGBA.COM

6. 什么情况下设置了索引但无法使用?

① LIKE 语句,模糊匹配

② OR 语句

③ 数据类型出现隐式转化(如 varchar 不加单引号的话可能会自动转换为 int 型)

7. SQL 语句的优化.

1.对查询进行优化,应尽量避免全表扫描,首先应考虑在 where 及 order by 涉及的

列上建立索引。

2.应尽量避免在 where 子句中使用!=或操作符,否则将引擎放弃使用索引而进行全

表扫描。

3.应尽量避免在 where 子句中对字段进行 null 值判断,否则将导致引擎放弃使用索

引而进行全表扫描,如:

select id from t where num is null

可以在 num 上设置默认值 0,确保表中 num 列没有 null 值,然后这样查询:

select id from t where num=0

4.应尽量避免在 where 子句中使用 or 来连接条件,否则将导致引擎放弃使用索引而

进行全表扫描,如:

select id from t where num=10 or num=20

可以这样查询:

select id from t where num=10

union all

select id from t where num=20

5.下面的查询也将导致全表扫描:

select id from t where name like %abc%

若要提高效率,可以考虑全文检索。

6.in 和 not in 也要慎用,否则会导致全表扫描,如:

select id from t where num in(1,2,3)

对于连续的数值,能用 between 就不要用 in 了:

select id from t where num between 1 and 3

7.如果在 where 子句中使用参数,也会导致全表扫描。因为 SQL 只有在运行时才会解

析局部变量,但优化程序不能将访问计划的选择推迟到运行时;它必须在编译时进行选

择。然而,如果在编译时建立访问计划,变量的值还是未知的,因而无法作为索引选择

的输入项。如下面语句将进行全表扫描:

select id from t where num=@num

可以改为强制查询使用索引:

select id from t with(index(索引名)) where num=@num

8.应尽量避免在 where 子句中对字段进行表达式操作,这将导致引擎放弃使用索引而

进行全表扫描。如:

select id from t where num/2=100

应改为:

select id from t where num=100*2

9.应尽量避免在 where 子句中对字段进行函数操作,这将导致引擎放弃使用索引而进行

全表扫描。如:

select id from t where substring(name,1,3)=abc--name 以 abc 开头的 id

select id from t where datediff(day,createdate,2005-11-30)=0--2005-11-30

生成的 id

应改为:

select id from t where name like abc%

select id from t where createdate=2005-11-30 and createdate2005-12-1

10.不要在 where 子句中的“=”左边进行函数、算术运算或其他表达式运算,否则系

统将可能无法正确使用索引。

11.在使用索引字段作为条件时,如果该索引是复合索引,那么必须使用到该索引中的

第一个字段作为条件时才能保证系统使用该索引,否则该索引将不会被使用,并且应尽

可能的让字段顺序与索引顺序相一致。

12.不要写一些没有意义的查询,如需要生成一个空表结构:

select col1,col2 into #t from t where 1=0

这类代码不会返回任何结果集,但是会消耗系统资源的,应改成这样:

create table #t(...)

13.很多时候用 exists 代替 in 是一个好的选择:

select num from a where num in(select num from b)

用下面的语句替换:

select num from a where exists(select 1 from b where num=a.num)

14.并不是所有索引对查询都有效,SQL 是根据表中数据来进行查询优化的,当索引列

有大量数据重复时,SQL 查询可能不会去利用索引,如一表中有字段 sex,male、female

几乎各一半,那么即使在 sex 上建了索引也对查询效率起不了作用。

15.索引并不是越多越好,索引固然可以提高相应的 select 的效率,但同时也降低了

insert 及 update 的效率,因为 insert 或 update 时有可能会重建索引,所以怎样

建索引需要慎重考虑,视具体情况而定。一个表的索引数最好不要超过 6 个,若太多则

应考虑一些不常使用到的列上建的索引是否有必要。

16.应尽可能的避免更新 clustered 索引数据列,因为 clustered 索引数据列的顺序

就是表记录的物理存储顺序,一旦该列值改变将导致整个表记录的顺序的调整,会耗费

相当大的资源。若应用系统需要频繁更新 clustered 索引数据列,那么需要考虑是否

应将该索引建为 clustered 索引。

17.尽量使用数字型字段,若只含数值信息的字段尽量不要设计为字符型,这会降低查

询和连接的性能,并会增加存储开销。这是因为引擎在处理查询和连接时会逐个比较字

符串中每一个字符,而对于数字型而言只需要比较一次就够了。

18.尽可能的使用 varchar/nvarchar 代替 char/nchar ,因为首先变长字段存储空间

小,可以节省存储空间,其次对于查询来说,在一个相对较小的字段内搜索效率显然要

高些。

19.任何地方都不要使用 select * from t ,用具体的字段列表代替“*”,不要返回

用不到的任何字段。

20.尽量使用表变量来代替临时表。如果表变量包含大量数据,请注意索引非常有限(只

有主键索引)。

21.避免频繁创建和删除临时表,以减少系统表资源的消耗。

22.临时表并不是不可使用,适当地使用它们可以使某些例程更有效,例如,当需要重

复引用大型表或常用表中的某个数据集时。但是,对于一次性事件,最好使用导出表。

23.在新建临时表时,如果一次性插入数据量很大,那么可以使用 select into 代替

create table,避免造成大量 log ,以提高速度;如果数据量不大,为了缓和系统表

的资源,应先 create table,然后 insert。

24.如果使用到了临时表,在存储过程的最后务必将所有的临时表显式删除,先

truncate table ,然后 drop table ,这样可以避免系统表的较长时间锁定。

25.尽量避免使用游标,因为游标的效率较差,如果游标操作的数据超过 1 万行,那么

就应该考虑改写。

26.使用基于游标的方法或临时表方法之前,应先寻找基于集的解决方案来解决问题,

基于集的方法通常更有效。

27.与临时表一样,游标并不是不可使用。对小型数据集使用 FAST_FORWARD 游标通常

要优于其他逐行处理方法,尤其是在必须引用几个表才能获得所需的数据时。在结果集

中包括“合计”的例程通常要比使用游标执行的速度快。如果开发时间允许,基于游标

的方法和基于集的方法都可以尝试一下,看哪一种方法的效果更好。

28.在所有的存储过程和触发器的开始处设置 SET NOCOUNT ON ,在结束时设置 SET

NOCOUNT OFF 。无需在执行存储过程和触发器的每个语句后向客户端发送

DONE_IN_PROC 消息。

29.尽量避免向客户端返回大数据量,若数据量过大,应该考虑相应需求是否合理。

30.尽量避免大事务操作,提高系统并发能力。

8. 在一个带头结点的单链表 HL 中,若要在第一个元素之前插

入一个由指针 p 指向的结点。其语句为?

在插入节点时:先要将待插入节点 p 的后继节点设为第一个元素, 也就是 p-next=HL

next。然后再将头结点 HL 的后继节点改为 p 节点,HL-next=p。下图中红色的箭头说

了插入操作执行的顺序,如果顺序不当,就会丢失指向第一个元素的指针,破坏链表结构

2020年百度精选面试题及答案_WWW.XUNWANGBA.COM

其语句为: p-next=HL-next; HL-next=p;

9. 如何设计一个高并发的系统?

① 数据库的优化,包括合理的事务隔离级别、SQL 语句优化、索引的优化;

② 使用缓存,尽量减少数据库 IO;

③ 分布式数据库、分布式缓存;

④ 服务器的负载均衡;

10. 两条相交的单向链表,如何求他们的第一个公共节点?

①如果两个链表相交,则从相交点开始,后面的节点都相同,即最后一个节点肯定相同;

②从头到尾遍历两个链表,并记录链表长度,当二者的尾节点不同,则二者肯定不相交;

③尾节点相同,如果 A 长为 LA,B 为 LB,如果 LALB,则 A 前 LA-LB 个先跳过;

——更多如链表相关经典问题:求单向局部循环链表的入、将两个有序链表合并合成一

个有序链表、链表逆序、求倒数第 K 个节点,判断是否有环等。

11. new/delete 和 malloc/free 的底层实现?

malloc 和 new 的区别:

1)malloc 与 free 是 C++/C 语言的标准库函数,new/delete 是 C++的运算符。它们都

可用于申请动态内存和释放内存;

2)new 返回指定类型的指针,并且可以自动计算所需要大小。而 malloc 则必须要由

程序员计算字节数,并且在返回后强行转换为实际类型的指针;

3)new/delete 在对象创建的同时可以自动执行构造函数初始化,在对象在消亡之前会

自动执行析构函数。而 malloc 只管分配内存,并不能对所得的内存进行初始化,所以

得到的一片新内存中,其值将是随机的;

既然 new/delete 的功能覆盖了 malloc/free,为什么 C++还要保留 malloc/free?因为

C++程序经常要调用 C 函数,而 C 程序只能用 malloc/free 管理动态内存。

new/delete、malloc/free 底层实现原理:

概述:new/delete 的底层实现是调用 malloc/free 函数实现的,而 malloc/free 的底

层实现也不是直接操作内存而是调用系统 API 实现的。

new/delete 的两种分配方式原理图如下:

注意,针对上图最末尾所述的“new[]/delete[]时会多开辟 4 字节用于存储对象个数”,

作如下说明:

①对于内置类型:

new []不会在首地址前 4 个字节定义数组长度。

delete 和 delete[]是一样的执行效果,都会删除整个数组,要删除的长度从 new 时即

可知道。

②对于自定义类型:

new []会在首地址前 4 个字节定义数组长度。

当 delete[]时,会根据前 4 个字节所定义的长度来执行析构函数删除整个数组。

如果只是 delete 数组首地址,只会删除第一个对象的值。

12. overload、override、overwrite 的介绍.

(1)overload(重载),即函数重载:

①在同一个类中;

②函数名字相同;

③函数参数不同(类型不同、数量不同,两者满足其一即可);

④不以返回值类型不同作为函数重载的条件。

(2)override(覆盖,子类改写父类的虚函数),用于实现 C++中多态:

①分别位于父类和子类中;

②子类改写父类中的 virtual 方法;

③与父类中的函数原型相同。

(3)overwrite(重写或叫隐藏,子类改写父类的非虚函数,从而屏蔽父类函数):

①与 overload 类似,但是范围不同,是子类改写父类;

②与 override 类似,但是父类中的方法不是虚函数。

13. 什么是守护进程?

(1)什么是守护进程?

守护进程(Daemon Process),也就是通常说的 Daemon 进程(精灵进程),是 Linux

中的后台服务进程。它是一个生存期较长的进程,通常独立于

控制终端并且周期性地执行某种任务或等待处理某些发生的事件。

守护进程是个特殊的孤儿进程,这种进程脱离终端,为什么要脱离终端呢?之所以脱离

于终端是为了避免进程被任何终端所产生的信息所打断,其在执

行过程中的信息也不在任何终端上显示。

(2)如何查看守护进程?

在终端敲:ps axj

从上图可以看出守护进行的一些特点:

守护进程基本上都是以超级用户启动( UID 为 0 )

没有控制终端( TTY 为 ?)

终端进程组 ID 为 -1 ( TPGID 表示终端进程组 ID)

14. 请描述小端/大端机器.

小端/大端的区别是指低位数据存储在内存低位还是高位的区别。其中小端机器指:数

据低位存储在内存地址低位,高位数据则在内存地址高位;大端机器正好相反。

当前绝大部分机器都是小端机器,就是比较符合人们逻辑思维的数据存储方式,比如

intel 的机器基本就都是小端机器。

15. 请描述长连接与短连接.

(1)就是 TCP 长连接和 TCP 短连接:

①TCP 长连接:TCP 长连接指建立连接后保持连接而不断开。若一段时间内没有数据传

输,服务器会发送心跳包给客户端,判断客户端是否还在线,叫做 TCP 长连接中的 keep

alive。一般步骤:连接→数据传输→保持连接(心跳)→数据传输→保持连接(心跳)

→……→关闭连接;

②TCP 短连接:指连接建立并传输数据完成后,就断开连接。一般步骤:连接→数据传

输→关闭连接;

③使用场景:长连接适合单对单通信且连接数不太多的情况;短连接适合连接数多且经

常更换连接对象的;

(2)HTTP 是什么连接:

①在 HTTP/1.0 中,默认使用的是短连接。但从 HTTP/1.1 起,默认使用长连接,用以

保持连接特性。使用长连接的 HTTP 协议,会在响应头有加入这行代码:

Connection:keep-alive

注意:此处的 keep-alive 和上述 TCP 长连接原理介绍中的 keep alive 不是一个意思:

此处表示告知服务器本 http 请求是长连接模式,而 TCP 长连接中的 keep alive 表示对

客户端的保活检测。

②http 长连接并不是一直保持连接

http 的长连接也不会是永久保持连接,它有一个保持时间如 20s(从上一次数据传输完

成开始计时),可以在不同的服务器软件(如 Apache)中设定这个时间,若超过该时

间限制仍然无数据通信传输,服务器就主动关闭该连接。注:实现长连接要客户端和服

务端都支持长连接。

③http 连接实质:http 的长连接/短连接实质上就是 TCP 的长/短连接。

16. C++中引用与指针的联系与区别?

联系:引用是变量的别名,可以将引用看做操作受限的指针;

区别:

1) 指针是一个实体,而引用仅是个别名;

2)引用只能在定义时必须初始化,指针可以不初始化为空;

3)引用初始化之后其地址就不可改变(即始终作该变量的别名直至销毁,即从一而终。

注意:并不表示引用的值不可变,因为只要所指向的变量值改变。引用的值也就改变了),

但指针所指地址是不可变的;如下:

int m=23,n=13;

int a=m;

a=12; //合法,相当于修改 m=12

a=n; //合法,相当于修改 m=13

17. 一个大的含有 50M 个 URL 的记录,一个小的含有 500 个

URL 的记录,找出两个记录里相同的 URL。

首先使用包含 500 个 url 的文件创建一个 hash_set。

然后遍历 50M 的 url 记录,如果 url 在 hash_set 中,则输出此 url 并从 hash_set 中删

除这个 url。

所有输出的 url 就是两个记录里相同的 url。

18. 海量日志数据,提取出某日访问百度次数最多的那个 IP。

如果日志文件足够的大,大到不能完全加载到内存中的话。

那么可以考虑分而治之的策略,按照 IP 地址的 hash(IP)%1024 值,将海量日志存储到

1024 个小文件中。每个小文件最多包含 4M 个 IP 地址。

对于每个小文件,可以构建一个 IP 作为 key,出现次数作为 value 的 hash_map,并记

录当前出现次数最多的 1 个 IP 地址。

有了 1024 个小文件中的出现次数最多的 IP,我们就可以轻松得到总体上出现次数最多

的 IP。

17. 有 10 个文件,每个文件 1G,每个文件的每一行都存放

的是用户的 query,每个文件的 query 都可能重复。如何

按照 query 的频度排序?

1)读取 10 个文件,按照 hash(query)%10 的结果将 query 写到对应的文件中。这样我

们就有了 10 个大小约为 1G 的文件。任意一个 query 只会出现在某个文件中。

2)对于 1)中获得的 10 个文件,分别进行如下操作

-利用 hash_map(query,query_count)来统计每个 query 出现的次数。

-利用堆排序算法对 query 按照出现次数进行排序。

-将排序好的 query 输出的文件中。

这样我们就获得了 10 个文件,每个文件中都是按频率排序好的 query。

3)对 2)中获得的 10 个文件进行归并排序,并将最终结果输出到文件中。

20. 有一根 27 厘米长的细木杆,在第 3 厘米,7 厘米,11

厘米,17 厘米,23 厘米这五个位置上各有一只蚂蚁,木杆

很细,不能同时通过两只蚂蚁,开始时,蚂蚁的头朝向左还

是右是任意的,他们只会朝前走或掉头,但不会后退,当两

只蚂蚁相遇后,蚂蚁会同时掉头朝反方向走,假设蚂蚁们每

秒钟可以走 1 厘米的距离。求所有蚂蚁都离开木杆的最小时

间和最大时间。

两只蚂蚁相遇后,各自掉头朝相反方向走。如果我们不考虑每个蚂蚁的具体身份,这和

两只蚂蚁相遇后,打个招呼继续向前走没有什么区别。

所有蚂蚁都离开木杆的最小时间为

max(min(3,27-3),min(7,27-7), min(11,27-11), min(17,27-17),min(23,27-23))=11

所有蚂蚁都离开木杆的最大时间为

max(max(3,27-3),max(7,27-7), max(11,27-11), max(17,27-17),max(23,27-23))=24

21. 判断两棵树是否相等,请实现两棵树是否相等的比较,

相等返回 1,否则返回其他值,并说明算法复杂度。

数据结构为:

typedef struct TreeNode

{

char c;

TreeNode *leftchild;

TreeNode *rightchild;

}TreeNode;

函数接口为:int CompTree(TreeNode* tree1,TreeNode* tree2);

注:A、B 两棵树相等当且仅当 RootA-c==RootB--c,而且 A 和 B 的左右子树相等或者

左右互换相等。

递归方法:

bool CompTree(TreeNode *tree1, TreeNode *tree2)

{

if (tree1 == NULLtree2 == NULL)

return true;

if (tree1 == NULL || tree2 == NULL)

return false;

if (tree1-c != tree2-c)

return false;

if ( (CompTree(tree1-leftchild, tree2-leftchild)

CompTree(tree1-rightchild, tree2-rightchild)) ||

CompTree(tree1-leftchild, tree2-rightchild)

CompTree(tree1-rightchild, tree2-leftchild) )

return true;

}

时间复杂度:

在树的第 0 层,有 1 个节点,我们会进行 1 次函数调用;

在树的第 1 层,有 2 个节点,我们可能会进行 4 次函数调用;

在树的第 2 层,有 4 个节点,我们可能会进行 16 次函数调用;

......

在树的第 x 层,有 2^x 个节点,我们可能会进行(2^x)^2 次函数调用;

所以假设总节点数为 n,则算法的复杂度为 O(n^2)。

22. 将多个集合合并成没有交集的集合。

给定一个字符串的集合,格式如:{aaabbbccc},{bbbddd},{eeefff},{ggg},{dddhhh}

要求将其中交集不为空的集合合并,要求合并完成后的集合之间无交集。

例如上例应输出{aaabbbcccdddhhh},{eeefff},{ggg}。

(1)请描述你解决这个问题的思路;

(2)请给出主要的处理流程,算法,以及算法的复杂度

(3)请描述可能的改进。

集合使用 hash_set 来表示,这样合并时间复杂度比较低。

1、给每个集合编号为 0,1,2,3...

2、创建一个 hash_map,key 为字符串,value 为一个链表,链表节点为字符串所在集

合的编号。遍历所有的集合,将字符串和对应的集合编号插入到 hash_map 中去。

3、创建一个长度等于集合个数的 int 数组,表示集合间的合并关系。例如,下标为 5

的元素值为 3,表示将下标为 5 的集合合并到下标为 3 的集合中去。开始时将所有值都

初始化为-1,表示集合间没有互相合并。在集合合并的过程中,我们将所有的字符串都

合并到编号较小的集合中去。

遍历第二步中生成的 hash_map,对于每个 value 中的链表,首先找到最小的集合编

号(有些集合已经被合并过,需要顺着合并关系数组找到合并后的集合编号),然后将

链表中所有编号的集合都合并到编号最小的集合中(通过更改合并关系数组)。

4、现在合并关系数组中值为-1 的集合即为最终的集合,它的元素来源于所有直接或间

接指向它的集合。

算法的复杂度为 O(n),其中 n 为所有集合中的元素个数。

题目中的例子:

0:{aaabbbccc}

1:{bbbddd}

2:{eeefff}

3:{ggg}

4:{dddhhh}

生成的 hash_map,和处理完每个值后的合并关系数组分别为

aaa:0。[-1,-1,-1,-1,-1]

bbb:0,1。[-1,0,-1,-1,-1]

ccc:0。[-1,0,-1,-1,-1]

ddd:1,4。[-1,0,-1,-1,0]

eee:2。[-1,0,-1,-1,0]

fff:2。[-1,0,-1,-1,0]

ggg:3。[-1,0,-1,-1,0]

hhh:4。[-1,0,-1,-1,0]

所以合并完后有三个集合,第 0,1,4 个集合合并到了一起。

23. 平面内有 11 个点,由它们连成 48 条不同的直,由这些

点可连成多少个三角形?

首先你要分析,平面中有 11 个点,如果这些点中任意三点都没有共线的,那么一共应

该有 C(11,2)=55, 可是,题目中说可以连接成 48 条直线,那么这 11 个点中必定有

多点共线的情况。 55-48=7,从 7 来分析:

假设有一组三个点共线,那么可以组成的直线在 55 的基础上应该减去 C(3,2)-1=2

2*3=6≠7,因此,可以断定不仅有三点共线的,也可能有四个点共线的可能。

假设有一组四个点共线,那么可以组成的直线在 55 的基础上应该减去 C(4,2)-1=5

(备注,五个点共线的可能不存在,因为,C(5,2)-1=97,故不可能有五条直线共线。)

因此,三点共线少 2 条,4 点共线少 5 条,只有一个 4 点共线,一个 3 点共线才能满足

条件,其余情况不能满足少了 7 条直线。

那么,这 11 个点能组成的三角形的个数为,C(11,3)-C(3,3)-C(4,3)=165-1-4=160 (备

注,三个点共线不能组成三角形)

24. 在常用的 C 编译环境中, 已知 struct {int a; double b;char

c;} A; 求 sizeof(A)的返回值?

24

25. 若有宏定义: #define MOD(x, y) x%y 则执行以下语句后的

输出结果是?

int a=13, b=94;

printf(%d\n, MOD(b, a+4));

7

26. 用两个栈实现一个 FIFO 队列.

一个用来入栈,一个用来出栈.

27. 描述 IPv6 相对 IPv4 带来了哪些技术差异.

IPv4 有 4 个 8 位二级制数表示, 工 4 个字节.

浏览器向域名系统 DNS 请求解析

IPv6 地址空间从 IPV4 的 32 位扩展到 128 位 IPv6 实现了包头设计的简化,降低了网络

设备对包处理的负荷 IPv6 实现了实现了地址的自动化配置,无需部署 DHCP 也可实现地

址配置为了实现 IPv6 地址解析、路由、网络控制消息传递等功能,网络需要配合实现邻

居发现协议( Neighbor Discovery)、 ICMPVI6、 DHCPV6、 OSPFV3、BGP4+等新协议部

署或扩展 IPv6 部署过程中,网络可能会部署双栈、隧道或翻译等过渡方案实现与原有

PV4 网络互通

28. 内存主要用的 4 个区是?

栈区, 堆区, 静态区, 代码区

29. Linux 下进程通信的方式有哪些?

管道, 消息队列, 共享内存, 信号量, 信号, 套接口

30. 如何用队列来求一个二叉树的最大高度?

BFS

31. 下列哪个操作可以不需要再内核态执行?

A.系统调用 B.malloc/free C.软中断 D.内存换页

B

32. 应用程序 ping 发出的是什么报文?

ICMP 应答报文

33. 假定对长度为 n=119 的有序数组进行折半查找,则对应的

判定数的高度是多少?

7

2^7=128119

面试题太多了,小编就不一一的列举了,需要更详细的 可以加入QQ群:956314242 ,让我们一起技术讨论起来吧,小编编辑文章已编辑的手软

2020年百度精选面试题及答案_WWW.XUNWANGBA.COM

以上就是(2020年百度精选面试题及答案)全部内容,收藏起来下次访问不迷路!