• python开发工程师面试准备


    python基础加高级

    1. 字典和列表的实现原理

      字典:是一个无序键值对集合,不能通过偏移下标查找数据,通过哈希函数将key-value数组映射到hash表中,映射方式是以key为自变量,与hash表数组长度取余,余数对应的就是hash表中该键值对在表中位置,查询时,也是通过通过hash(key)获得位置找到对应值的。
      列表:列表是一个有序的集合,通过偏移下标查找数据;列表对应数据结构中的数组,创建初始化时,内存空间会将列表的引用变量放在一个存储空间,列表存放在另一个空间。

    2. init 和new的区别

      1. __new__是用于创建实例对象的,在创建实例对象之前调用.
      2. __init__是用于初始化实例对象的,为实例对象添加属性,是在创建实例对象之后调用的。

    3. lambda

      lambda在python中是用于创建单行匿名函数的一种实现方法,使代码看起来更加简洁,但是执行效率并不会有什么提高。

    4. is和==在操作整形数有什么区别

      ==判断的是两个对象的值是否相等,is则是判断两个对象的地址是否相同;在操作整形数是,如果是-5到256范围内的,则是直接从python的缓存池中获取值的引用地址,超出这个范围的每创建一个对象,则会新分配一个地址,因此他们的地址不相同,所以用is判断为false,==就为true

    数据结构

    1. 链表和数组的区别

      1. 数组在内存空间是连续存储的,而链表不是,链表里的元素可以在任何位置,然后每个节点储存当前节点的值,和下一节点的引用地址。
      2. 在插入和删除时数组的时间复杂度是O(n),每次操作完需要偏移n个元素的位置,链表是O(1),只需要修改节点的下一节点引用地址即可。
      3. 在查询时数组的时间复杂度是O(1),可以通过下标索引进行随机访问。链表是O(n),链表不能进行随机访问,只能从第一个节点开始依次访问,直到找到要访问的那个元素。

    2. 哈希表

      哈希表也叫(散列表),关键字key通过哈希函数映射得到的地址对应哈希表的位置进行存储key-value,即用于存储键值对

    3. 哈希冲突,解决哈希冲突

      哈希冲突就是指,在对关键字key进行哈希函数映射时,得到的对应哈希表的地址已存储了一对键值对。
      1. 开放地址法:在遇到哈希冲突后,不断的进行哈希函数再次映射出一个地址,直到哈希表中这个对应的地址为空即可
      2. 链地址法:在遇到哈希冲突后,就在这个位置存储一个链表连接每个键值对,以关键字作为节点的值
      链地址法相比于开放地址法占用的空间更多,但是在进行查找和插入的时候能够减少对关键字的平均查找长度。

    4. B+树,B+树和平衡树(B树)的区别, 平衡树的应用

      https://blog.csdn.net/Beyond_Xuz/article/details/105082122

      平衡树的应用:https://blog.csdn.net/qq_36183935/article/details/81095212

    5. 说一下平衡二叉树。怎么构建平衡二叉树呢?

      平衡二叉树也叫平衡二叉查找树,满足左右子节点的高度差不大于一;父节点大于所有左子节点,小于所有右子节点;可以是空树;所有子节点要么满足同样的要求;

      构建平衡二叉树

    6. 说一下常见排序 哪个排序比较快 时间复杂度是多少,python内置排序算法底层原理

      常见排序:冒泡排序,插入排序,选择排序,归并排序,快速排序,堆排序
      一般使用快速排序比较快,最坏的情况时间复杂度是O(n^2), 最好的情况是O(nlogn)

      python内置排序算法底层原理(底层用的是Timsort排序,结合了插入和归并排序的稳定的排序算法,最坏的情况下时间复杂度是O(nlogn), 最好的情况下是O(n))

    7. 堆,大根堆,小根堆,如何实现堆排序

      堆实际上就是一个完全二叉树,常用于顺序存储;堆又分为大根堆,小根堆;大根堆指父节点大于他的左右子树的完全二叉树,并且他的所有子节点一样满足这样的要求;小根堆是指父节点小于他的左右子树,其他与大根堆一样;

      堆排序:首先先将无序的数组构建一个大根堆或小根堆,如果从数组下标为0开始,下标i的父节点对应的数组下标是(i-1//2),左子树对应的数组下标是(2i+1),右子树是(2i+2),子树创建时与父节点进行比较大小,假如是大根堆,子比父大则,子跟父的交换值,依次比较;

    8. 堆和栈的区别

      1. 管理方式不同:栈是由操作系统自动分配的,堆是由申请和释放的,容易产生内存泄漏。
      2. 空间大小不同:每个进程获取的栈的大小要远远小于堆。
      3. 分配方式不同:堆是动态分配的,没有静态分配的堆,而栈有静态和动态两种分配方式。
      4. 分配效率不同:栈是由操作系统自动分配的,由底层硬件提供支持,压栈出栈由相关指令;堆是通过库函数申请和释放的,实现机制较为复杂;因此栈的分配效率高于堆

    9. 怎么用堆 多次free会发生什么

      一次free一个指针的时候,会将指针在堆中对应的空间释放,而栈中指针变量指向的堆的内存空间的地址没有发生变化,因此在再次使用free后,由于指针指向的堆的内存空间已经不在了,所以会导致编译器报错

    操作系统

    1. 进程(孤儿进程,僵尸进程等),linux如何终止?以及kill后面为什么加-9

      孤儿进程:一个父进程退出,而他的一个或多个子进程还在运行,那么这些子进程就叫做孤儿进程。
      僵尸进程:子进程在父进程还没有调用wait()或waitpid()就退出,那么这些子进程就叫做僵尸进程。

      linux下杀死僵尸进程:1. 使用命令ps -ef | grep "defunct"查看僵尸进程信息,找到其父进程ppid。2. 使用命令kill -9 父进程pid杀死其父进程。

      kill后面加-9表示无条件杀死该进程即强制终止该进程

    2. 进程间的通信

      管道,消息队列,共享内存,信号量, 信号, socket
      https://blog.csdn.net/OYMNCHR/article/details/124728256

    3. 怎么使用共享内存

      现代操作系统下会给每个进程分配一个虚拟内存,虚拟内存映射到真实的物理内存。而共享内存就是不同的进程取出一块虚拟内存映射到相同的物理内存空间上。这样一个进程写入的东西,另一个进程马上就能看到,不需要拷贝。

    4. 什么是多进程,多线程,如何创建多线程和多进程

      多进程是指同时运行多个进程来执行任务,而多线程是指在一个进程里同时运行多个线程来执行任务;他们都是并行的;

      多线程的创建:

      import threading
      
      def test(a):
      	print(a)
      
      if __name__ == '__main__':
      	t1 = threading.Thread(target=test, arg=('1',))
      	t2 = threading.Thread(target=test, arg=('2',))
      	t1.start()
      	t2.start()
      	# 主线程保证所有子线程结束再结束
      	t1.join() 
      	t2.join() 
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13

      多进程的创建:

      from multiprocessing import Process
      
      def test(b):
      	print(b)
      
      if __name__ == '__main__':
      	p1 = Process(target=test, arg=('1',))
      	p2 = Process(target=test, arg=('2',))
      	p1.start()
      	p2.start()
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
    5. select, poll, epoll

      1. select实现需要不断轮询fd集合,直到设备就绪,期间会睡眠和唤醒多次;epoll会调用epoll_wait函数不断轮询就绪表,但但设备就绪后,会将就绪的fd添加到就绪表中,调用回调函数,唤醒epoll_wait中睡眠的进程,这期间也会睡眠唤醒交替多次,不过,select每次醒来都要遍历整个fd集合,和epoll只需要检查就绪表是否为空,这样大大减小了cpu的开销。
      2. select 没调用一次都会将fd集合从用户态拷贝到内核态一次,并将crrunt挂到设备等待队列一次。而epoll只需要拷贝一次,将crrunt往等待队列中也只需挂一次,这里的等待队列是epoll内部定义的等待队列。这样大大节省了空间的开销
      3. poll与select基本相同,不同的是select用fd标注为来存放fd,poll采用链表来存放fd,因此,select最大连接数限制,poll没有。

    网络编程

    1. TCP关闭连接的时候,一般是4次握手,但很多情况下是三次握手,这是什么场景呢?

      如果客户端请求关闭连接时,服务器并没有数据需要发送,其实三次挥手应该也是可以的。但一般情况下,客户端猝不及防地请求断开连接,服务器还是有数据需要传输的,所以四次挥手更加地稳妥。

    补充

  • 相关阅读:
    JavaScript 中的灵活编程模式-行为委托
    PHP操作MongoDB的原生CURD方法
    企业该如何选择合适的ERP系统?谈谈国内外ERP软件的优缺点
    CAXA 3D实体设计2024:塑造未来的创新引擎
    go-carbon v2.2.13 发布,轻量级、语义化、对开发者友好的 Golang 时间处理库
    通过阿里云宕机这件事,来看国内程序员的畸形职场文化
    《深入浅出消息中间件》-RabbitMQ 安装
    音视频从入门到精通——MediaMuxer API 简介
    SCT52240STDR,SCT52240MTER,SCT52240QSTDR,SCT52240QMTER,栅极驱动器
    防抖(debounce)和节流(throttle)区别详细讲解及案例练习
  • 原文地址:https://blog.csdn.net/COOL66BOY/article/details/126881687