面试里有犹豫的问题……
1、Fibonacci序列
#我最开始的答案:
def fibs(n):
assert isinstance(n, int) and n>=0
if n==1 or n==2:
return 1
else:
return fibs(n-1)+fibs(n-2)
#面试官:递归可以,但是会有重复计算,可以改进吗?
#我:重复,好像是一颗不全满的二叉树?试试递归→循环?(记得二分搜索是可以拆的)
def fibs(n):
assert isinstance(n, int) and n>=0
if n==1 or n==2:
return 1
first=1
second=1
n=n-2
while (n>0):
temp=second
second=first+second
first=temp
n-=1
return second
#面试官:其实可以用yiled……充分发挥Python这门语言的优势
#我:哦………%生成器
#尝试写一下
def fibs():
first=1
second=1
yield first
yield second
while True:
yield first+second
temp=second
second=first+second
first=temp
def show_fibs(n):
assert isinstance(n, int) and n>=0
it=fibs()#it是生成器对象
for i in range(n):
print(next(it))
show_fibs(5)
#写完我在想,是不是所有的递归都可以拆成循环,以及是不是所有的循环都可以拆成生成器
#【复习生成器……】
2、单链表的相邻元素两两交换
#当时没有答出来,下来花了半个小时也没有写对……
#昨天经 @unoyx 提醒,可以用只交换data的方法达成目的,但这种实现写法在其他语言里可能有问题(我不懂)
#随后终于把两种都写了出来,@shenJin总结得很对:只要指针不乱指!(所有错误的根源……)
class Node(object):
def __init__(self,data,next=None):
self._data=data
self._next=next
class SingleLinkedList():
def __init__(self):
self._head=None
def exchange1(self):
#交换指针
if (self._head!=None and self._head._next!=None):#至少有2个元素,否则不需要做任何事
#head指针比较特殊,需要单独考虑
first=self._head
self._head=self._head._next
#接下来就是循环,每一轮会改变两个指针的指向
probe=first#初始化指针位置
while True:
third = probe._next._next # 提前保存probe._next._next
probe._next._next=probe#第一次改变指针指向
if third==None or third._next==None:#当前节点为1往后数到3或4为空,不需要交换
probe._next=third
return
else:#否则当前节点1的next指向往后数节点3的next,也就是节点4
probe._next=third._next
probe=third
def exchange2(self):
#只交换data
probe=self._head
while(probe!=None and probe._next!=None):
#当probe和probe._next所指向的元素不为None时,交换这两个元素
temp_pointer=probe##提前保存probe的位置
temp=probe._data
probe._data=probe._next._data
probe._next._data=temp
#之后指针前移两格
probe=temp_pointer._next._next
3、函数装饰器(被问过两三次了……)
问:如果一个函数以同样的参数被反复调用……考虑将函数的返回值保存起来,以后直接取用会提高效率,请用装饰器实现……
#感谢 @Manjusaka 的提问,印象深刻……
a_lst=[]#想写成字典但是找不到唯一的key
def buff(func):
def wrapper(*args,**kwgs):
global a_lst
for item in a_lst:
if args==item[0] and kwgs==item[1]:
return item[2]
else:
result=func(*args,**kwgs)
a_lst.append([args,kwgs,result])
return result
return wrapper
@ buff
def func(*args,**kwgs):
pass
func(real_args1,real_kwgs1)
func(real_args1,real_kwgs1)
func(real_args1,real_kwgs1) #多次调用,希望其中的计算过程可以省略
4、手写多线程,以及:子线程如何向主线程返回数据?
#摘抄以前的笔记,以下
#(1)直接实例化t一个threading.Thead对象
t=threading.Thead(target=func,ars=())
t.start()
#(2)从threading.Thead派生一个新的类并实现它的run()方法,
class MyThread(threading.Thead):
def run(self):
pass
t=MyThread()
t.start()
问:子线程如何向主线程返回数据?
(1)定义全局变量,只要在一个进程内都可以共享
(2)线程队列queue.Queue
重点看queue.Queue对象具有这样一些方法:q.get()
q.put(a_para)
q.size()
q.empty()
q.full()
q.get_nowait()等价于q.get(Fasle)
q.put_nowait()等价于q.put(False)
q.task_done()#完成一项任务后,改变q
q.join()#阻塞……知道q判断等所有任务都完成也就是发出q.task_done以后。因此,如果用了q.join(),那么每次q.get()以后都要加上q.task_done(),否则一直阻塞。
线程队列与【生产者消费者模型】:
?(1)解决大并发(2)通过中间的阻塞队列解决生产者与消费者的强耦合问题
# coding=utf-8
"""
module/program document
"""
from queue import Queue
from threading import Thread
class producer(Thread):
def __init__(self, q):
super().__init__()
self.q = q
def run(self):
print('producer begin to run……')
self.count = 5
while self.count > 0:
if self.count == 1:
self.count -= 1
self.q.put(2)
else:
self.count -= 1
self.q.put(1)
print('producer finish')
class consumer(Thread):
def __init__(self, q):
super().__init__()
self.q = q
def run(self):
print('consumer begin to run……')
while True:
print('while true')
data = self.q.get()
self.q.task_done()
if data == 2:#遇2终止,遇1消费
print("stop because data=", data)
print('q.task_done')
break
else:
print("data is good,data=", data)
#self.q.task_done()#不能省略,因为q.join()需要直到所有任务都task_done才取消阻塞,所以每次get后需要调用task_done,
print('consumer finish')
def main():
qq = Queue()
p = producer(qq)
c = consumer(qq)
p.setDaemon(True)
c.setDaemon(True)
p.start()
c.start()
print('stage 1')
qq.join()#Blocks until all items in the Queue have been gotten and processed,也就是等到Queue都处理完了,主线程才往下
print('stage 2')
print("queue is complete")
if __name__ == '__main__':
main()