本文主要是介绍开发算法岗八股技术实战面经containing各大互联网,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
开发算法岗八股技术实战面经containing各大互联网
这份面经是笔者从3月初开始面试到五月初的所有公司的经典面视问题和答案的总结,这里分享一下。有了这份面经,只能说乱杀好吧,是包赢的!剩下做好准备起飞,芜湖!
下个月笔者会更新记录自己的实习过程,想了解的可以关注一下,为秋招做准备。
当然,现在笔者身处公司学习加班(今天本来是休息的),祝各位过期的小朋友节日快乐呐!
new和malloc的区别?
语法:
new 是 C++ 中的运算符,用于动态分配内存并调用对象的构造函数来初始化内存。malloc 是 C 和 C++ 中的函数,用于分配指定大小的内存块,但不会调用对象的构造函数。
类型安全:
new 是类型安全的,它会根据分配的类型来确定所需的内存大小,并返回正确类型的指针。malloc 返回的是 void* 类型的指针,需要手动进行类型转换,容易出错。
构造函数:
new 在分配内存后会调用对象的构造函数,用于初始化对象。
malloc 只是分配了内存空间,不会调用对象的构造函数,需要手动初始化对象。
返回值:
new 返回指向动态分配的对象的指针。
malloc 返回指向动态分配的内存块的指针。
释放内存:
delete 用于释放由 new 分配的内存,并调用对象的析构函数。
free 用于释放由 malloc 分配的内存。
C++里面适合查找的数据结构 ?
std::map 和 std::unordered_map:
std::map 是一个基于红黑树实现的关联容器,它提供了对键值对进行有序存储和快速查找的功能。
std::unordered_map 是一个基于哈希表实现的关联容器,它提供了快速的插入、删除和查找操作,但不保持元素的顺序。
std::set 和 std::unordered_set:
std::set 是一个基于红黑树实现的有序集合,它保持元素的顺序并提供快速的查找操作。
std::unordered_set 是一个基于哈希表实现的无序集合,它提供了快速的插入、删除和查找操作。
std::multimap 和 std::unordered_multimap:
std::multimap 和 std::unordered_multimap 是允许重复键的关联容器,它们提供了对键值对进行存储和查找的功能。
std::set 和 std::unordered_set 的多重映射:
如果你需要存储多个相同键对应的值,你可以使用 std::multiset 和 std::unordered_multiset,它们允许重复元素的存在。
std::vector 和 std::deque:如果你需要根据索引来查找元素,可以使用 std::vector 或 std::deque,它们提供了快速的随机访问功能。但需要注意,查找操作的时间复杂度为 O(1),而插入和删除操作的时间复杂度为 O(n)。
For 里面写成了死循环,对cpu有什么影响?
for 循环是一种常用的循环结构,如果循环条件没有被正确设置,可能会导致死循环,即循环永远不会结束。这样的死循环会导致 CPU 不断地执行循环体内的代码,占用 CPU 资源,并且可能会导致程序的崩溃或系统的不稳定。
具体对 CPU 的影响取决于死循环中的代码,如果循环体内有大量的计算或者 I/O 操作,那么 CPU 使用率会很高,系统可能会变得非常缓慢,甚至无法响应其他操作。如果循环体内没有任何延迟操作,那么可能会导致 CPU 使用率接近 100%,严重影响系统的性能。
因此,在编写代码时,一定要确保循环的终止条件正确设置,避免出现死循环。可以使用适当的条件来控制循环次数,或者使用 break 语句在循环体内根据某些条件跳出循环。同时,定期检查和优化代码,确保代码的稳定性和性能。
一个进程4个线程会有几个堆和栈?
一个进程中的线程共享同一个地址空间,因此它们将共享进程的堆和栈。
堆(Heap):在一个进程中,所有线程共享同一个堆。堆是动态分配内存的区域,通常由操作系统的内存管理器来管理。多个线程可以同时在堆中分配和释放内存。
栈(Stack):每个线程都有自己的栈。栈用于存储函数调用的局部变量、函数参数、返回地址等信息。当线程调用函数时,函数的参数和局部变量被存储在栈上,并在函数返回时被释放。因此,每个线程都有自己独立的栈空间。
所以,一个进程中的 4 个线程会共享同一个堆,每个线程都有自己独立的栈。
多态的特性?
多态(Polymorphism)是面向对象编程中的一个重要概念,它指的是同一个接口可以表现出不同的行为。多态允许以统一的方式处理不同类型和结构的对象,提高了代码的灵活性、可维护性和可扩展性。
多态具有以下几个特性:
静态多态(静态多态性,也称为编译时多态):
静态多态是在编译时就确定了具体调用的函数,主要通过函数重载和运算符重载来实现。通过重载可以让一个函数名字可以拥有多种定义,编译器根据传入参数的不同选择合适的函数进行调用。
动态多态(动态多态性,也称为运行时多态):
动态多态是在运行时根据对象的实际类型来确定调用的函数,主要通过虚函数和继承来实现。
通过虚函数和继承,可以实现基类指针或引用指向派生类对象,在运行时根据对象的实际类型来确定调用的函数。
动态多态是面向对象编程的重要特性之一,它通过将实现细节与接口分离,提供了一种灵活的方式来处理对象之间的关系,使得代码更加可扩展和可维护。
动态规划(Dynamic Programming,DP)和分治法(Divide and Conquer)都是常见的算法设计技术,它们有一些共同点,但也存在一些显著的区别。
共同点:
问题分解:两种方法都将原始问题分解成较小的子问题,以便更容易地解决。
递归求解:在解决子问题时,通常采用递归的方式,直到达到基本情况。
不同点:
问题类型:
动态规划通常用于解决优化问题,例如最长公共子序列、背包问题等,其中每个子问题的解可以根据其他子问题的解计算得出。
分治法通常用于解决分而治之的问题,例如归并排序、快速排序等,其中每个子问题是相互独立的,且不需要考虑其他子问题的解。
子问题关系:
动态规划中的子问题通常是重叠的,也就是说,在求解一个子问题时,可能需要多次求解相同的子问题。为了避免重复计算,动态规划通常采用记忆化搜索或者自底向上的方法,将子问题的解存储起来,避免重复计算。
分治法中的子问题通常是独立的,每个子问题的解只依赖于自身,不依赖于其他子问题的解。因此,分治法通常不需要额外的记忆化搜索或者存储子问题的解。
时间复杂度:
由于动态规划中存在子问题重叠的情况,因此动态规划的时间复杂度通常较高,但可以通过记忆化搜索或者动态规划表来优化。
分治法中的子问题是相互独立的,因此通常具有较低的时间复杂度。然而,分治法在某些情况下可能会有较高的空间复杂度,因为每个子问题的解都需要单独存储。
数据库的四大特性
ACID
数据库的四大特性是ACID,即原子性(Atomicity)、一致性(Consistency)、隔离性(Isolation)和持久性(Durability)。
原子性:指的是事务是一个不可分割的工作单位,事务中的操作要么全部发生,要么全部不发生,不会出现部分成功部分失败的情况。
一致性:确保事务的执行结果使数据库从一个一致性状态转换到另一个一致性状态。这意味着事务的执行必须遵循业务的逻辑规则,保证数据的一致性。
隔离性:意味着多个事务并发执行时,每个事务之间是相互隔离的,互不干扰。这保证了事务的执行不会受到其他并发事务的影响。
持久性:指的是一旦事务执行完毕并且提交,对数据库的改变就是永久的,即使系统发生故障也不会影响已经提交的事务结果。
C11的新特性
http://t.csdnimg.cn/gZACY
1.多线程支持:
在 C11 标准中引入了 <threads.h> 头文件,其中定义了一组函数和类型,用于支持线程相关的操作。这个头文件提供了一些函数和类型,可以用于创建、管理和同步线程
2.泛型选择表达式:
_Generic 关键字是 C11 标准引入的一个新特性,用于根据表达式的类型选择不同的代码块。它主要用于实现泛型编程中的条件选择,允许编写更通用的代码,根据表达式的类型动态地选择不同的处理方式。
3.匿名结构体和联合体:
在 C11 标准中引入了匿名结构体和匿名联合体的概念,允许在不提供名称的情况下定义结构体和联合体,使其更为灵活。
4.静态断言:
_Static_assert 是 C11 标准引入的一个关键字,用于在编译时执行静态断言(static assertion)。静态断言是指在编译时检查条件是否为真,如果条件为假则会触发编译器错误,防止程序继续编译。
5.可重入的标准库函数:
C11 引入了一些可重入的标准库函数,这些函数可以在多线程环境下安全地被多个线程同时调用,而不会导致竞态条件或数据损坏。
可重入函数具有以下特点:
不会使用静态数据。
不会修改除了传入参数和返回结果以外的任何数据。
在多线程环境下可以安全地并发调用。
6.原子操作:
C11 标准引入了原子操作,提供了一组函数和类型,用于支持多线程并发访问共享变量时的原子性操作。原子操作是在不被中断的情况下执行的操作,保证了对共享变量的操作不会被其他线程的操作所干扰。
7.内存模型和Unicode支持改进、新增的函数库(数学和内存中的)
密钥 对称加密,非对称加密 私钥 公钥
密钥通常指的是加密和解密过程中使用的特定字符串或者代码,用于加密数据以确保安全传输和存储。在加密算法中,密钥被用来转换普通文本成加密文本,或者将加密文本还原成普通文本。密钥可以是对称的(使用相同的密钥进行加密和解密),也可以是非对称的(使用一对相关的密钥,公钥用于加密,私钥用于解密,或者反之)。密钥的安全性对于保护数据的机密性至关重要。
常见的加密方法有 对称加密、非堆成加密、哈希函数(MD5,SHA),混合加密
对称加密算法:在对称加密中,同一个密钥被用于加密和解密数据
非对称加密算法:在非对称加密中,使用一对相关的密钥进行加密和解密,其中一个是公开的公钥,另一个是私有的私钥。
公钥和私钥是非对称加密算法中的两个关键部分,常用于加密和解密数据、数字签名等操作。以下是它们的解释:
公钥 (Public Key):
公钥是非对称加密算法中用于加密数据的部分,也是用于验证数字签名的部分。
公钥可以自由地分发给其他用户,因为它用于加密数据,任何人都可以使用公钥来加密消息,但却无法使用公钥来解密它。
公钥通常用于安全地发送加密消息或者验证数字签名的有效性。
公钥通常以数字证书的形式发布,由可信任的证书颁发机构 (CA) 签名,以确保公钥的真实性和完整性。
私钥 (Private Key):
私钥是非对称加密算法中的另一部分,用于解密被公钥加密的数据,或者用于生成数字签名。
私钥是保密的,只有拥有者才能访问和使用它。
私钥用于解密由相应公钥加密的数据,或者用于创建数字签名以验证消息的真实性和完整性。
私钥的安全性对于整个加密系统的安全至关重要,因此必须妥善保护。
公钥和私钥之间存在数学关系,通过这种关系,使用公钥加密的数据只能使用相应的私钥解密,使用私钥生成的数字签名可以被相应的公钥验证。这种关系使得非对称加密算法成为安全通信和数字签名的重要工具。
管道
当提到操作系统(OS)中的管道时,通常是指一种用于进程间通信的机制。在类Unix操作系统中,比如Linux和macOS,管道是一种特殊的文件,用于将一个进程的输出直接传递给另一个进程的输入,而无需借助临时文件或者其他额外的中间步骤。
下面是关于管道的一些基本概念和特性:
单向性:管道是单向的,分为标准输入(stdin)和标准输出(stdout)两种。一个进程可以将数据写入到管道的输出端口,另一个进程则可以从管道的输入端口读取数据。
匿名管道:最常见的管道是匿名管道,也称为无名管道。这种管道没有与之相关联的文件,而是由操作系统内核动态创建和维护。匿名管道只能用于具有亲缘关系的进程之间,通常是父子进程之间。
符号:在Unix-like系统中,管道的符号是竖线(|)。在命令行中,可以使用管道来将一个命令的输出传递给另一个命令的输入,从而实现命令的串联执行。
缓冲:管道通常具有有限的缓冲区,当写入数据的速度快于读取数据的速度时,缓冲区可能会填满,导致写入进程阻塞直到有足够的空间。
进程同步:管道也可以用于进程间的同步。写入进程可以向管道写入数据,当读取进程读取这些数据时,写入进程可以被阻塞,直到所有数据都被读取完毕。
匿名管道(Anonymous Pipes):
匿名管道是最常见的一种类型,也是最简单的一种。它没有关联的文件名,只能在创建它的进程及其子进程之间使用。
匿名管道通常用于具有亲缘关系的进程之间进行通信,比如父进程和子进程之间。
命名管道(Named Pipes):
命名管道是一种有名字的管道,它以文件的形式存在于文件系统中。在文件系统中以特殊的文件类型存在,而不是普通的文件。
不同于匿名管道,命名管道可以在没有亲缘关系的进程之间进行通信,只要它们知道管道的名字并有权限访问它。
命名管道通常用于解决不同进程间的通信问题,比如两个独立运行的程序需要进行数据交换。
总的来说,匿名管道适用于具有亲缘关系的进程之间的通信,而命名管道则适用于不具有亲缘关系的进程之间的通信。两者都提供了进程间通信的方式,但应根据具体的场景和需求选择合适的类型。
进程之间的通信可以通过多种机制来实现,其中包括:
管道(Pipes):管道是一种在进程间传递数据的简单方法。它可以是匿名管道或命名管道,用于在具有亲缘关系的进程之间传递数据。
信号(Signals):信号是一种异步通信机制,用于通知接收进程某些事件的发生。例如,一个进程可以向另一个进程发送信号来请求终止或处理某些异常情况。
共享内存(Shared Memory):共享内存允许多个进程共享同一块内存区域,从而实现高效的数据交换。进程可以直接读写共享内存,而不需要复制数据,因此它是一种高效的进程间通信方式。
消息队列(Message Queues):消息队列允许进程通过发送和接收消息来进行通信。消息队列提供了一种可靠的通信方式,允许进程按照特定顺序接收消息,并提供了消息持久化的功能。
信号量(Semaphores):信号量是一种用于进程同步和互斥的计数器。它可以用于多个进程之间对共享资源的访问控制,以防止竞争条件和死锁等问题的发生。
套接字(Sockets):套接字是一种在网络中进行进程间通信的机制,但也可以用于同一台计算机上的进程间通信。它提供了一种灵活的通信方式,允许进程在不同的计算机或同一台计算机上的不同进程之间进行通信。
TCP/IP 协议中的三次握手和四次挥手是用于建立和终止 TCP 连接的过程。这些步骤确保了可靠的数据传输和连接的安全关闭。下面分别介绍三次握手和四次挥手的过程:
三次握手(Three-way Handshake):
客户端发送 SYN 请求: 客户端首先向服务器发送一个 TCP 报文段,其中设置 SYN 标志位,并指定客户端的初始序列号(ISN)。
服务器回应 SYN-ACK: 服务器收到 SYN 请求后,如果同意建立连接,则会发送一个 TCP 报文段作为响应。该报文段中设置 SYN 和 ACK 标志位,并确认了客户端发送的序列号,同时也发送了自己的初始序列号。
客户端发送 ACK: 客户端收到服务器的 SYN-ACK 后,会发送一个带有 ACK 标志位的 TCP 报文段作为确认,确认号设置为服务器发送的序列号加1。此时,TCP 连接已建立,客户端和服务器可以开始进行数据传输。
四次挥手(Four-way Handshake):
客户端发送 FIN: 客户端决定关闭连接时,会发送一个带有 FIN(Finish)标志位的 TCP 报文段给服务器,表示数据发送完成。
服务器回应 ACK: 服务器收到客户端的 FIN 后,会发送一个带有 ACK(Acknowledgment)标志位的报文段作为确认,表示已经接收到客户端的关闭请求。
服务器发送 FIN: 服务器决定关闭连接时,会发送一个带有 FIN 标志位的 TCP 报文段给客户端,表示服务器也准备关闭连接。
客户端回应 ACK: 客户端收到服务器的 FIN 后,会发送一个带有 ACK 标志位的报文段作为确认。此时,客户端和服务器的连接已经关闭。
通过这样的握手和挥手过程,TCP 可以确保连接的建立和关闭过程都是可靠的,避免了数据丢失或者连接无法正确关闭的问题。
这篇关于开发算法岗八股技术实战面经containing各大互联网的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!