news 2026/5/11 23:11:48

面试被问烂的20道编程基础题,你必须全会,不然别去面试

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
面试被问烂的20道编程基础题,你必须全会,不然别去面试

文章目录

    • 前言
    • 一、Python基础篇(6道)
      • 1. Python中list和tuple有什么区别?
      • 2. Python 3.7之后普通dict已经有序了,那OrderedDict还有存在的必要吗?
      • 3. Python中的深拷贝和浅拷贝有什么区别?
      • 4. Python中的*args和**kwargs是什么意思?
      • 5. Python中的生成器是什么?它有什么优点?
      • 6. Python中的装饰器是什么?它有什么作用?
    • 二、数据结构基础篇(5道)
      • 7. 什么是数组?它有什么优缺点?
      • 8. 什么是链表?它和数组有什么区别?
      • 9. 什么是栈和队列?它们有什么区别?
      • 10. 什么是哈希表?它的工作原理是什么?
      • 11. 什么是二叉树?什么是二叉搜索树?
    • 三、算法基础篇(3道)
      • 12. 什么是递归?递归有什么优缺点?
      • 13. 什么是动态规划?它的核心思想是什么?
      • 14. 什么是排序算法?常见的排序算法有哪些?它们的时间复杂度是多少?
    • 四、网络基础篇(2道)
      • 15. TCP的三次握手和四次挥手是什么?为什么是三次不是两次?
      • 16. HTTP和HTTPS有什么区别?
    • 五、操作系统基础篇(2道)
      • 17. 进程和线程有什么区别?
      • 18. 什么是死锁?死锁产生的条件是什么?如何避免死锁?
    • 六、数据库基础篇(2道)
      • 19. 什么是事务?事务的ACID特性是什么?
      • 20. 什么是索引?索引有什么优缺点?
    • 总结

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

前言

兄弟们,先问个扎心的问题:你最近面试的时候,是不是十场有八场都会被问到一些看似简单到离谱的编程基础题?结果你要么脑子一片空白,半天憋不出一句完整的话;要么张嘴就来,结果答得漏洞百出,被面试官连环追问,当场哑火,恨不得找个地缝钻进去?

我在AI行业摸爬滚打了22年,面过的候选人没有一千也有八百,最近这两年尤其是2026年,这种情况见得太多了。很多小伙子简历写得天花乱坠,什么"精通大模型开发"、“熟练掌握智能体架构”、“参与过千万级并发系统”,结果一被问到"Python中list和tuple有什么区别"这种小学一年级的问题,直接就卡壳了。

更离谱的是,有个小伙子面试AI算法工程师,说自己用PyTorch写过十几个大模型,结果我问他"什么是递归",他想了半天说:"递归就是…就是自己调用自己吧?"我再问:"那递归有什么缺点?"他直接懵了,说:“缺点?递归还有缺点?我一直觉得递归挺好用的啊。”

兄弟们,这不是个例。现在很多人都在追热点,什么火就学什么,大模型火就学大模型,智能体火就学智能体,结果把最基础的编程知识忘得一干二净。殊不知,面试的时候,面试官最看重的恰恰就是你的基础功底。因为热点技术可以学,框架可以换,但是基础不牢,地动山摇。

今天我就把2026年面试被问烂了的20道编程基础题整理出来,每一道都给你讲得明明白白。如果你连这些题都不会,我劝你还是别去面试了,去了也是浪费时间,浪费车费。

一、Python基础篇(6道)

1. Python中list和tuple有什么区别?

这道题简直是面试必考题,没有之一。我敢说,只要你面试Python相关的岗位,不管是后端、前端、测试还是AI算法,100%会被问到这道题。

很多人只会说:"list是可变的,tuple是不可变的。"然后就没了。兄弟,这样回答只能给你30分,剩下的70分你全丢了。

我给你一个满分回答:

list和tuple的核心区别有以下5点:

  • 可变性:list是可变对象,支持增删改查操作;tuple是不可变对象,一旦创建就不能修改。这就好比list是一个笔记本,你可以在上面写字、擦字、改字;而tuple是一本书,一旦印刷出来,你就不能修改上面的内容了。
  • 语法:list用方括号[]表示,tuple用圆括号()表示。注意,当tuple只有一个元素时,需要在后面加一个逗号,比如(1,),否则Python会把它当成一个普通的变量。
  • 性能:tuple的性能比list好。因为tuple是不可变的,Python可以对它进行很多优化,比如缓存、预分配内存等。所以如果你有一些不需要修改的数据,优先使用tuple,这样可以提高程序的运行速度。
  • 哈希性:tuple是可哈希的,也就是说它可以作为字典的键,也可以放入集合中;而list是不可哈希的,不能作为字典的键,也不能放入集合中。这是因为哈希值是根据对象的内容计算出来的,如果对象可变,哈希值也会变,这样就会导致字典和集合出现混乱。
  • 使用场景:list适合存储需要动态修改的数据,比如用户列表、商品列表等;tuple适合存储不需要修改的数据,比如坐标、颜色、配置信息等。

2. Python 3.7之后普通dict已经有序了,那OrderedDict还有存在的必要吗?

这道题是最近两年才火起来的,因为Python 3.7确实把普通dict改成了有序的。很多人就觉得OrderedDict没用了,可以淘汰了。

兄弟,如果你这么想,那就大错特错了。OrderedDict不仅没有被淘汰,反而在很多场景下依然是必不可少的。

我给你讲清楚:

首先,Python 3.7的普通dict只是插入有序,也就是说它会按照你插入键值对的顺序来保存。但是它没有提供任何专门的方法来操作这个顺序。

而OrderedDict提供了很多普通dict没有的方法,比如:

  • move_to_end(key, last=True):将指定的键移动到字典的末尾或者开头
  • popitem(last=True):删除并返回字典末尾或者开头的键值对

这些方法在实现LRU缓存、FIFO队列等数据结构的时候非常有用。比如,你要实现一个LRU缓存,当缓存满了的时候,需要删除最近最少使用的元素。如果用普通dict,你需要自己维护一个链表来记录访问顺序;而用OrderedDict,只需要一行代码move_to_end(key)就可以把最近访问的元素移到末尾,然后用popitem(last=False)删除最前面的元素,非常方便。

另外,OrderedDict的相等性判断也和普通dict不同。两个OrderedDict只有当它们的键值对顺序完全相同时才会被认为是相等的;而两个普通dict只要键值对相同,不管顺序如何,都会被认为是相等的。

所以,OrderedDict不仅有存在的必要,而且在很多场景下比普通dict更适合。

3. Python中的深拷贝和浅拷贝有什么区别?

这道题也是面试高频题,而且很容易搞混。很多人只会说:"浅拷贝只拷贝第一层,深拷贝拷贝所有层。"这样回答太笼统了,面试官肯定会继续追问。

我给你用一个通俗的例子讲清楚:

假设你有一个列表a = [1, 2, [3, 4]]。这个列表就像一个文件夹,里面有两个文件12,还有一个子文件夹[3, 4],子文件夹里面又有两个文件34

  • 浅拷贝:就像你复制了这个文件夹,得到了一个新的文件夹b。新文件夹里面的文件12是原文件的副本,但是子文件夹[3, 4]只是原文件夹的一个快捷方式。也就是说,如果你修改b[0],不会影响a[0];但是如果你修改b[2][0],就会影响a[2][0],因为它们指向的是同一个子文件夹。
  • 深拷贝:就像你不仅复制了这个文件夹,还复制了里面所有的子文件夹和文件,得到了一个完全独立的新文件夹c。不管你修改c里面的任何内容,都不会影响原来的文件夹a

在Python中,实现浅拷贝的方法有:

  • 使用切片操作:b = a[:]
  • 使用工厂函数:b = list(a)
  • 使用copy模块的copy函数:import copy; b = copy.copy(a)

实现深拷贝的方法只有一个:

  • 使用copy模块的deepcopy函数:import copy; c = copy.deepcopy(a)

需要注意的是,深拷贝比浅拷贝慢很多,因为它需要递归地拷贝所有的对象。所以如果你的数据结构很简单,没有嵌套的可变对象,使用浅拷贝就足够了;只有当你的数据结构中有嵌套的可变对象,并且你需要完全独立的副本时,才使用深拷贝。

4. Python中的*args和**kwargs是什么意思?

这道题也是基础中的基础,但是很多人还是搞不清楚。其实很简单,我一句话就能给你讲明白:

  • *args用来接收任意数量的位置参数,它会把这些参数打包成一个元组
  • **kwargs用来接收任意数量的关键字参数,它会把这些参数打包成一个字典

举个例子:

deffunc(*args,**kwargs):print(args)print(kwargs)func(1,2,3,name="张三",age=18)

输出结果:

(1, 2, 3) {'name': '张三', 'age': 18}

*args**kwargs的使用场景主要有两个:

  1. 当你不知道函数会接收多少个参数的时候,可以用它们来接收任意数量的参数
  2. 当你需要把一个列表或者字典作为参数传递给函数的时候,可以用它们来解包

比如:

defadd(a,b):returna+b nums=[1,2]print(add(*nums))# 输出3params={"a":3,"b":4}print(add(**params))# 输出7

需要注意的是,*args必须放在**kwargs前面,否则会报错。

5. Python中的生成器是什么?它有什么优点?

生成器是Python中一个非常重要的概念,也是面试常考题。很多人觉得生成器很神秘,其实一点都不神秘。

生成器就是一个特殊的迭代器,它不需要一次性把所有的数据都加载到内存中,而是在迭代的时候才生成数据。这样可以大大节省内存空间,尤其是当你需要处理大量数据的时候。

创建生成器有两种方法:

  1. 使用生成器表达式:把列表推导式的方括号改成圆括号就可以了
    gen=(xforxinrange(1000000))
  2. 使用yield关键字:在函数中使用yield关键字,这个函数就变成了一个生成器函数
    deffib(n):a,b=0,1for_inrange(n):yieldb a,b=b,a+b

生成器的优点主要有两个:

  • 节省内存:生成器不需要一次性把所有的数据都加载到内存中,而是在需要的时候才生成数据。比如上面的例子,如果你用列表推导式创建一个包含100万个元素的列表,会占用大量的内存;而用生成器表达式,几乎不占用任何内存。
  • 惰性计算:生成器只有在迭代的时候才会计算下一个值。这样可以避免不必要的计算,提高程序的运行效率。

需要注意的是,生成器只能迭代一次。迭代完之后,生成器就空了,不能再迭代了。

6. Python中的装饰器是什么?它有什么作用?

装饰器是Python中一个非常强大的特性,也是面试必考题。很多人觉得装饰器很难,其实只要你理解了函数是一等公民这个概念,装饰器就非常简单了。

在Python中,函数是一等公民,也就是说:

  • 函数可以作为参数传递给另一个函数
  • 函数可以作为返回值从另一个函数返回
  • 函数可以被赋值给一个变量

装饰器本质上就是一个函数,它接收一个函数作为参数,然后返回一个新的函数。新的函数会在不修改原函数代码的情况下,给原函数添加一些额外的功能。

举个最简单的例子,我们要给一个函数添加计时功能:

importtimedeftimer(func):defwrapper(*args,**kwargs):start=time.time()result=func(*args,**kwargs)end=time.time()print(f"{func.__name__}函数执行时间:{end-start}秒")returnresultreturnwrapper@timerdefadd(a,b):time.sleep(1)returna+bprint(add(1,2))

输出结果:

add函数执行时间:1.000123秒 3

这里的@timer就是一个装饰器,它等价于add = timer(add)

装饰器的作用非常广泛,比如:

  • 日志记录
  • 性能统计
  • 权限验证
  • 缓存
  • 重试机制

等等。可以说,装饰器是Python中实现面向切面编程(AOP)的最佳方式。

二、数据结构基础篇(5道)

7. 什么是数组?它有什么优缺点?

数组是最基本的数据结构之一,几乎所有的编程语言都支持数组。

数组是一种连续存储的数据结构,它在内存中占用一块连续的空间,用来存储相同类型的数据。数组中的每个元素都有一个唯一的索引,通过索引可以快速访问数组中的任意元素。

数组的优点:

  • 随机访问速度快:通过索引可以在O(1)时间内访问数组中的任意元素。这是数组最大的优点,也是很多其他数据结构无法比拟的。
  • 内存利用率高:数组是连续存储的,没有指针开销,内存利用率很高。

数组的缺点:

  • 插入和删除操作慢:因为数组是连续存储的,所以在数组中间插入或者删除元素的时候,需要移动后面的所有元素,时间复杂度是O(n)。
  • 大小固定:大多数编程语言中的数组大小都是固定的,一旦创建就不能改变。如果数组满了,就需要创建一个更大的数组,然后把原来的元素复制过去,这个过程非常耗时。
  • 只能存储相同类型的数据:数组只能存储相同类型的数据,不能存储不同类型的数据。

8. 什么是链表?它和数组有什么区别?

链表也是一种非常基本的数据结构,它和数组正好相反。

链表是一种非连续存储的数据结构,它由一个个节点组成,每个节点包含数据和一个指向下一个节点的指针。链表中的节点在内存中不是连续存储的,而是通过指针连接在一起的。

链表和数组的区别主要有以下几点:

特性数组链表
存储方式连续存储非连续存储
随机访问O(1)O(n)
插入和删除O(n)O(1)(已知前驱节点)
大小固定动态
内存利用率低(有指针开销)

举个通俗的例子:数组就像一排连在一起的房子,每个房子都有一个门牌号,你可以通过门牌号直接找到对应的房子;而链表就像一串珍珠,每个珍珠都用线连在一起,你要找到第n个珍珠,必须从第一个珍珠开始,一个一个地数过去。

链表的优点是插入和删除操作快,大小动态;缺点是随机访问慢,内存利用率低。

9. 什么是栈和队列?它们有什么区别?

栈和队列都是操作受限的线性表,它们的区别在于操作的顺序不同。

  • :是一种后进先出(LIFO)的数据结构。也就是说,最后进入栈的元素,最先被取出。栈的操作主要有两个:入栈(push)和出栈(pop)。入栈是把元素放到栈顶,出栈是把栈顶的元素取出来。

    栈就像一个羽毛球筒,你把羽毛球一个一个地放进去,最后放进去的那个,最先被拿出来。

  • 队列:是一种先进先出(FIFO)的数据结构。也就是说,最先进入队列的元素,最先被取出。队列的操作主要有两个:入队(enqueue)和出队(dequeue)。入队是把元素放到队尾,出队是把队头的元素取出来。

    队列就像排队买东西,先来的人先买,后来的人后买。

栈和队列的应用场景非常广泛:

  • 栈的应用:函数调用栈、表达式求值、括号匹配、深度优先搜索(DFS)等
  • 队列的应用:消息队列、任务调度、广度优先搜索(BFS)等

10. 什么是哈希表?它的工作原理是什么?

哈希表也叫散列表,是一种非常重要的数据结构,几乎所有的编程语言都内置了哈希表的实现(比如Python中的dict)。

哈希表的核心思想是:通过一个哈希函数,将键(key)映射到一个数组的索引,然后将值(value)存储在这个索引对应的位置。这样,当我们需要查找一个键的时候,只需要用哈希函数计算出它的索引,然后直接访问数组中对应的位置就可以了,时间复杂度是O(1)。

哈希表的工作原理:

  1. 当我们要插入一个键值对时,首先用哈希函数计算出键的哈希值
  2. 然后用哈希值对数组的长度取模,得到数组的索引
  3. 最后将值存储在这个索引对应的位置

但是,不同的键可能会计算出相同的哈希值,这就叫做哈希冲突。解决哈希冲突的方法主要有两种:

  • 链地址法:将哈希值相同的元素存储在一个链表中。当发生哈希冲突时,就将新元素添加到链表的末尾。Python中的dict就是用这种方法解决哈希冲突的。
  • 开放地址法:当发生哈希冲突时,就按照一定的规则寻找下一个空的位置。常见的开放地址法有线性探测、二次探测和双重哈希。

哈希表的优点是查找、插入和删除操作都非常快,平均时间复杂度是O(1);缺点是哈希冲突会影响性能,而且哈希表是无序的。

11. 什么是二叉树?什么是二叉搜索树?

二叉树是一种非常重要的树形数据结构,它的每个节点最多有两个子节点,分别叫做左子节点和右子节点。

二叉树有很多种特殊的类型,比如满二叉树、完全二叉树、二叉搜索树、平衡二叉树、红黑树等等。其中,二叉搜索树是面试中最常被问到的。

二叉搜索树(BST)也叫二叉排序树,它具有以下性质:

  • 左子树上所有节点的值都小于根节点的值
  • 右子树上所有节点的值都大于根节点的值
  • 左子树和右子树也都是二叉搜索树

二叉搜索树的优点是查找、插入和删除操作都比较快,平均时间复杂度是O(log n)。但是,如果二叉搜索树不平衡,比如变成了一个链表,那么时间复杂度就会退化为O(n)。

为了解决这个问题,人们发明了平衡二叉树,比如AVL树和红黑树。它们通过旋转操作来保持树的平衡,从而保证了最坏情况下的时间复杂度也是O(log n)。

三、算法基础篇(3道)

12. 什么是递归?递归有什么优缺点?

递归是一种非常重要的算法思想,它是指一个函数直接或者间接调用自己。

递归的核心思想是:将一个大问题分解成若干个规模较小的子问题,这些子问题和原问题具有相同的结构,然后通过解决这些子问题来解决原问题。

递归必须满足两个条件:

  1. 基线条件:也叫终止条件,当问题分解到一定程度时,就可以直接解决,不需要再递归了。
  2. 递归条件:将大问题分解成小问题的条件。

举个最简单的例子,计算阶乘:

deffactorial(n):# 基线条件ifn==0orn==1:return1# 递归条件returnn*factorial(n-1)

递归的优点:

  • 代码简洁、清晰,容易理解
  • 很多问题天然适合用递归解决,比如树的遍历、图的搜索、分治算法等

递归的缺点:

  • 栈溢出风险:递归调用会占用函数调用栈的空间,如果递归深度太大,就会导致栈溢出。比如Python默认的递归深度是1000,如果超过这个深度,就会抛出RecursionError异常。
  • 重复计算:很多递归算法会存在重复计算的问题,比如斐波那契数列的递归实现,时间复杂度是O(2^n),非常慢。
  • 性能开销:函数调用会有一定的性能开销,递归调用的次数越多,性能开销越大。

为了解决递归的缺点,我们可以用迭代来代替递归,或者用记忆化搜索来避免重复计算。

13. 什么是动态规划?它的核心思想是什么?

动态规划是一种非常重要的算法思想,也是面试中的难点。很多人觉得动态规划很难,其实只要你掌握了它的核心思想,就会发现动态规划其实很简单。

动态规划的核心思想是:将一个大问题分解成若干个规模较小的子问题,先解决这些子问题,然后将子问题的解存储起来,避免重复计算,最后通过子问题的解来得到原问题的解。

动态规划和递归的区别在于:递归是自顶向下的,从原问题开始,分解成子问题,然后递归解决子问题;而动态规划是自底向上的,从最小的子问题开始,逐步解决更大的问题,直到解决原问题。

动态规划问题一般可以分为以下几个步骤:

  1. 定义状态:确定dp数组的含义,dp[i]表示什么
  2. 确定状态转移方程:找出dp[i]和dp[i-1]、dp[i-2]等之间的关系
  3. 确定初始条件:确定dp[0]、dp[1]等初始值
  4. 确定遍历顺序:确定是从前往后遍历还是从后往前遍历

举个最简单的例子,斐波那契数列的动态规划实现:

deffib(n):ifn==0orn==1:returnn# 定义状态:dp[i]表示第i个斐波那契数dp=[0]*(n+1)# 初始条件dp[0]=0dp[1]=1# 状态转移方程foriinrange(2,n+1):dp[i]=dp[i-1]+dp[i-2]returndp[n]

这个实现的时间复杂度是O(n),空间复杂度是O(n),比递归实现快多了。

14. 什么是排序算法?常见的排序算法有哪些?它们的时间复杂度是多少?

排序算法是最基础的算法之一,也是面试必考题。面试官经常会让你手写一个排序算法,或者问你各种排序算法的时间复杂度和适用场景。

常见的排序算法有:冒泡排序、选择排序、插入排序、快速排序、归并排序、堆排序、计数排序、桶排序、基数排序等。

我给你整理了一个表格,包含了常见排序算法的时间复杂度、空间复杂度和稳定性:

排序算法平均时间复杂度最坏时间复杂度最好时间复杂度空间复杂度稳定性
冒泡排序O(n²)O(n²)O(n)O(1)稳定
选择排序O(n²)O(n²)O(n²)O(1)不稳定
插入排序O(n²)O(n²)O(n)O(1)稳定
快速排序O(n log n)O(n²)O(n log n)O(log n)不稳定
归并排序O(n log n)O(n log n)O(n log n)O(n)稳定
堆排序O(n log n)O(n log n)O(n log n)O(1)不稳定
计数排序O(n + k)O(n + k)O(n + k)O(k)稳定
桶排序O(n + k)O(n²)O(n)O(n + k)稳定
基数排序O(d * (n + k))O(d * (n + k))O(d * (n + k))O(n + k)稳定

其中,k是数据的范围,d是数据的位数。

在实际应用中,最常用的排序算法是快速排序,因为它的平均时间复杂度是O(n log n),而且常数因子很小,性能非常好。但是快速排序的最坏时间复杂度是O(n²),不过这种情况很少发生。

四、网络基础篇(2道)

15. TCP的三次握手和四次挥手是什么?为什么是三次不是两次?

这道题简直是网络基础面试的"天花板",没有之一。只要你面试和网络相关的岗位,100%会被问到这道题。很多人背了无数遍三次握手和四次挥手的过程,但是面试官一问"为什么是三次不是两次",就支支吾吾答不上来。

我先给你讲清楚三次握手的过程:

TCP是一种面向连接的、可靠的传输层协议。在传输数据之前,客户端和服务器必须先建立连接。建立连接的过程就是三次握手:

  1. 第一次握手:客户端向服务器发送一个SYN包,请求建立连接。此时客户端进入SYN_SENT状态。
  2. 第二次握手:服务器收到SYN包后,向客户端发送一个SYN+ACK包,确认客户端的请求,同时也请求建立连接。此时服务器进入SYN_RCVD状态。
  3. 第三次握手:客户端收到SYN+ACK包后,向服务器发送一个ACK包,确认服务器的请求。此时客户端和服务器都进入ESTABLISHED状态,连接建立成功。

为什么是三次不是两次?

很多人会说:"因为要确认双方的发送和接收能力都正常。"这个回答是对的,但是不够全面。

我给你一个更深入的回答:

如果只有两次握手,那么就会出现这样一种情况:客户端发送了一个SYN包,但是这个包在网络中滞留了,没有及时到达服务器。客户端以为这个包丢失了,于是又重新发送了一个SYN包。服务器收到第二个SYN包后,建立了连接,传输完数据后,关闭了连接。

但是过了一段时间,第一个SYN包终于到达了服务器。服务器以为客户端又要建立连接,于是向客户端发送一个SYN+ACK包,进入ESTABLISHED状态。但是客户端根本没有请求建立连接,所以会忽略这个ACK包。而服务器却一直等待客户端发送数据,这样就会浪费服务器的资源。

三次握手就可以解决这个问题。因为在第三次握手的时候,客户端会向服务器发送一个ACK包。如果服务器没有收到这个ACK包,就会知道这个连接是无效的,从而关闭连接,不会浪费资源。

接下来讲四次挥手的过程:

当数据传输完成后,客户端和服务器需要关闭连接。关闭连接的过程就是四次挥手:

  1. 第一次挥手:客户端向服务器发送一个FIN包,请求关闭连接。此时客户端进入FIN_WAIT_1状态。
  2. 第二次挥手:服务器收到FIN包后,向客户端发送一个ACK包,确认客户端的请求。此时服务器进入CLOSE_WAIT状态,客户端进入FIN_WAIT_2状态。
  3. 第三次挥手:服务器发送完所有数据后,向客户端发送一个FIN包,请求关闭连接。此时服务器进入LAST_ACK状态。
  4. 第四次挥手:客户端收到FIN包后,向服务器发送一个ACK包,确认服务器的请求。此时客户端进入TIME_WAIT状态,等待2MSL(最长报文段寿命)后,进入CLOSED状态。服务器收到ACK包后,也进入CLOSED状态。

为什么关闭连接需要四次挥手,而建立连接只需要三次握手?

因为建立连接的时候,服务器的SYN和ACK可以放在同一个包中发送;而关闭连接的时候,服务器的ACK和FIN不能放在同一个包中发送,因为服务器可能还有数据没有发送完。所以服务器需要先发送一个ACK包确认客户端的关闭请求,然后等所有数据都发送完之后,再发送一个FIN包请求关闭连接。

16. HTTP和HTTPS有什么区别?

这道题也是网络基础面试的必考题,尤其是现在几乎所有的网站都使用HTTPS了。

HTTP和HTTPS的核心区别主要有以下几点:

  • 安全性:HTTP是明文传输的,数据在传输过程中容易被窃听、篡改和伪造;而HTTPS是在HTTP的基础上加入了SSL/TLS协议,对数据进行了加密传输,保证了数据的安全性。
  • 端口号:HTTP默认使用80端口;HTTPS默认使用443端口。
  • 性能:HTTPS的性能比HTTP差,因为加密和解密需要消耗一定的CPU资源。不过现在随着硬件性能的提升和SSL/TLS协议的优化,这个差距已经越来越小了。
  • 证书:HTTPS需要申请SSL证书,证书一般需要向CA机构购买;而HTTP不需要证书。

HTTPS的工作原理:

  1. 客户端向服务器发送一个HTTPS请求
  2. 服务器将自己的SSL证书发送给客户端
  3. 客户端验证证书的有效性。如果证书有效,就生成一个随机的对称密钥,然后用服务器的公钥加密这个对称密钥,发送给服务器
  4. 服务器用自己的私钥解密,得到对称密钥
  5. 客户端和服务器使用对称密钥进行加密通信

这样,即使数据在传输过程中被窃听,窃听者也无法解密数据,因为他们没有对称密钥。

五、操作系统基础篇(2道)

17. 进程和线程有什么区别?

这道题是操作系统基础面试的必考题,也是很多人搞不清楚的问题。

我给你用一个通俗的例子讲清楚:

进程就像一个工厂,它有自己的厂房、设备和工人。线程就像工厂里的工人,多个工人可以在同一个工厂里工作,共享工厂的资源。

具体来说,进程和线程的区别主要有以下几点:

  • 资源分配:进程是资源分配的基本单位,每个进程都有自己独立的地址空间、文件描述符、堆等资源;线程是CPU调度的基本单位,线程不拥有资源,它共享所属进程的资源。
  • 开销:创建和销毁进程的开销很大,因为需要分配和回收资源;创建和销毁线程的开销很小,因为只需要保存少量的上下文信息。
  • 并发性:多个进程可以并发执行;一个进程中的多个线程也可以并发执行。
  • 通信:进程间通信(IPC)比较复杂,需要使用管道、消息队列、共享内存、信号量等方式;线程间通信非常简单,因为它们共享同一个地址空间,可以直接读写全局变量。
  • 安全性:进程之间是相互独立的,一个进程崩溃不会影响其他进程;线程之间是共享资源的,一个线程崩溃可能会导致整个进程崩溃。

举个例子:你打开一个浏览器,就是启动了一个进程。浏览器里的每个标签页,就是一个线程。多个标签页可以同时加载网页,共享浏览器的内存、CPU等资源。如果一个标签页崩溃了,可能会导致整个浏览器崩溃。

18. 什么是死锁?死锁产生的条件是什么?如何避免死锁?

死锁是指两个或多个进程在执行过程中,由于竞争资源而造成的一种互相等待的现象。如果没有外力干预,它们都将无法继续执行下去。

死锁产生的四个必要条件:

  1. 互斥条件:一个资源在同一时间只能被一个进程使用。
  2. 请求和保持条件:一个进程已经持有了至少一个资源,又请求其他已经被其他进程持有的资源。
  3. 不可剥夺条件:进程已经获得的资源,在未使用完之前,不能被其他进程强行剥夺,只能由进程自己释放。
  4. 循环等待条件:存在一个进程循环链,链中的每个进程都在等待下一个进程所持有的资源。

这四个条件必须同时满足,才会产生死锁。只要破坏其中任何一个条件,就可以避免死锁。

避免死锁的方法主要有:

  • 破坏互斥条件:将独占资源改为共享资源。比如,将打印机改为假脱机打印机,多个进程可以同时打印。
  • 破坏请求和保持条件:进程在开始执行之前,一次性申请所有需要的资源。如果资源不够,就不分配任何资源。
  • 破坏不可剥夺条件:当一个进程已经持有了一些资源,又请求其他已经被其他进程持有的资源时,它必须释放已经持有的所有资源,然后重新申请。
  • 破坏循环等待条件:对所有的资源进行编号,进程必须按照编号递增的顺序申请资源。

六、数据库基础篇(2道)

19. 什么是事务?事务的ACID特性是什么?

事务是数据库操作的基本单位,它是一组要么全部执行成功,要么全部执行失败的SQL语句。

事务的ACID特性是:

  • 原子性(Atomicity):事务是一个不可分割的工作单位,事务中的操作要么全部执行,要么全部不执行。如果事务在执行过程中发生错误,就会回滚到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性(Consistency):事务执行前后,数据库的完整性约束没有被破坏。比如,A向B转账100元,转账前后A和B的总金额应该保持不变。
  • 隔离性(Isolation):多个事务并发执行时,一个事务的执行不能被其他事务干扰。也就是说,不同的事务之间是相互隔离的,每个事务都感觉不到其他事务在并发执行。
  • 持久性(Durability):一个事务一旦提交,它对数据库的修改就应该是永久性的。接下来的其他操作或者故障不应该对它有任何影响。

举个例子:A向B转账100元,这个操作可以分为两个步骤:

  1. A的账户减去100元
  2. B的账户加上100元

这两个步骤必须放在一个事务中。如果第一步执行成功,第二步执行失败,那么事务就会回滚,A的账户会恢复到原来的状态,不会出现A少了100元而B没有多100元的情况。

20. 什么是索引?索引有什么优缺点?

索引是数据库中用来提高查询速度的一种数据结构。它就像一本书的目录,可以让你快速找到你需要的内容,而不需要一页一页地翻书。

索引的优点:

  • 提高查询速度:这是索引最大的优点。通过索引,数据库可以快速定位到需要查询的数据,而不需要进行全表扫描。
  • 提高排序和分组的速度:索引可以让数据库在排序和分组的时候不需要进行额外的排序操作。

索引的缺点:

  • 占用磁盘空间:索引需要占用额外的磁盘空间。如果表中有很多索引,那么索引文件可能会比数据文件还要大。
  • 降低插入、更新和删除的速度:当对表进行插入、更新和删除操作时,数据库不仅要修改数据,还要修改索引,这样会降低这些操作的速度。

所以,索引并不是越多越好。我们应该只在经常查询的列上创建索引,而在很少查询或者经常更新的列上不要创建索引。

常见的索引类型有:主键索引、唯一索引、普通索引、联合索引、全文索引等。

总结

兄弟们,以上就是2026年面试被问烂了的20道编程基础题。这些题看起来简单,但是真正能全部答对的人并不多。

很多人都觉得基础不重要,觉得只要会用框架、会调API就行了。但是我要告诉你,基础才是最重要的。框架会过时,API会变,但是基础永远不会变。

我见过很多人,用TensorFlow、PyTorch写大模型写得溜得飞起,但是连Python的基本数据类型都搞不清楚;我见过很多人,用Spring Boot写后端写得风生水起,但是连TCP的三次握手都讲不明白。这些人在面试的时候,很容易就会被面试官问倒。

所以,我劝大家,在追热点技术的同时,一定要把基础打牢。只有基础扎实了,你才能走得更远。

最后,祝大家都能找到一份满意的工作!

P.S. 目前国内还是很缺AI人才的,希望更多人能真正加入到AI行业,共同促进行业进步,增强我国的AI竞争力。想要系统学习AI知识的朋友可以看看我精心打磨的教程 http://blog.csdn.net/jiangjunshow,教程通俗易懂,高中生都能看懂,还有各种段子风趣幽默,从深度学习基础原理到各领域实战应用都有讲解,我22年的AI积累全在里面了。注意,教程仅限真正想入门AI的朋友,否则看看零散的博文就够了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/11 23:10:36

AI时代数据中心架构变革:从计算中心到加速基础设施

1. 从“计算中心”到“加速基础设施”:数据中心架构的范式转移最近和几个在头部云厂商做架构设计的老朋友聊天,话题总绕不开一个词:加速基础设施。这词儿听起来挺高大上,但说白了,就是咱们传统数据中心那套“通用计算存…

作者头像 李华
网站建设 2026/5/11 23:03:44

理想主义工程学:重塑工程师职业意义与教育模式

1. 工程教育的现实困境与“理想主义”的召唤 最近在整理旧资料时,翻到一篇十多年前的行业评论,标题挺有意思,叫《“理想主义工程学”能拯救局面吗?》。文章的核心讨论,即便放在今天,依然像一把精准的手术刀…

作者头像 李华
网站建设 2026/5/11 23:00:52

苹果W1芯片如何通过低功耗无线技术重塑TWS耳机体验

1. 无线音频的功耗困局与苹果的破局思路 2016年9月,当苹果在发布会上首次亮出那对剪掉线缆的AirPods时,整个消费电子行业都在问同一个问题:它是怎么做到的?更具体地说,它如何解决了无线耳机领域最核心、也最令人头疼的…

作者头像 李华
网站建设 2026/5/11 22:57:44

CFD流程图

这个CFD计算流程是合理的,它完整覆盖了CFD仿真从准备到输出的全流程,符合CFD计算的标准逻辑:流程完整性‌:从建立几何模型开始,依次完成网格划分、条件设定、方程构建、参数给定,再到收敛性判断与结果输出&…

作者头像 李华