# 由N个人围圈，报数3的离队问题，分析Python代码的执行效率

#-*- coding:UTF-8 -*-
import time

def func1(n):
"""思路:删除原有列表中的凡是数到3及倍数的
使用临时序列存储要删除的数字，在每次循环完后删除需要去掉的数字"""
ltPserion = list(range(1,n+1))
pos = 0
while len(ltPserion)>1:
ltRemove = []
for i in ltPserion:
pos += 1
if pos%3==0:
ltRemove.append(i)
#print('ltPserion:',ltPserion,'将删除',ltRemove)
for i in ltRemove:
ltPserion.remove(i)
return ltPserion[0]
def func2(n):
"""思路:列表中凡是数到3及倍数
对于报数进行取余判断，如果是3的倍数就删除"""
ltPserion = list(range(1,n+1))
SayNo = 0
DelCount = 0
while DelCount<len(ltPserion)-1:
for i in range(len(ltPserion)):
if ltPserion[i] != 0:
SayNo+=1
if SayNo%3==0:
ltPserion[i]=0
#print('删除',ltPserion[i] ,ltPserion)
DelCount+=1
for i in ltPserion:
if i!=0:
return i

def func3(n):
"""思路：删除原有列表中的凡是数到3及倍数的
直接在原序列上操作，不中间列表存储要删除的数字"""
ltPserion = list(range(1,n+1))
SayNo = 0
DelCount = 0
i = 0
while len(ltPserion)>1:
SayNo += 1
#print(ltPserion, '索引i=',i ,'当前数数SayNo=', SayNo, '人', ltPserion[i], end='')
if SayNo%3 == 0:
#print('删除',ltPserion[i], end='')
ltPserion.remove(ltPserion[i])
i-=1
i+=1
if i>=len(ltPserion):
i=0
#print()
return ltPserion[0]

def func4(n):
"""思路:列表中凡是数到3的就标记为删除
不用%取余，直接用if判断大于3就从1开始数数"""
ltPserion = list(range(1,n+1))
SayNo = 0
DelCount = 0
while DelCount<len(ltPserion)-1:
for i in range(len(ltPserion)):
if ltPserion[i] != 0:
if SayNo==3:
SayNo = 1
else:
SayNo += 1
if SayNo==3:
ltPserion[i]=0
#print('删除',ltPserion[i] ,ltPserion)
DelCount+=1
for i in ltPserion:
if i!=0:
return i

def main():
N = 100000
starttime1 = time.clock()
rt1 = func1(N)
endtime1 = time.clock()
print('func1:',rt1, endtime1-starttime1)

starttime2 = time.clock()
rt2 = func2(N)
endtime2 = time.clock()
print('func2:', rt2, endtime2-starttime2)

starttime3 = time.clock()
rt3 = func3(N)
endtime3 = time.clock()
print('func3:',rt3, endtime3-starttime3)

starttime4 = time.clock()
rt4 = func4(N)
endtime4 = time.clock()
print('func4:',rt4, endtime4-starttime4)
pass

if __name__ == '__main__':
main()


执行结果如下

>>>
func1: 92620 39.25819919960245
func2: 92620 0.31389559593181104
func3: 92620 42.987894393368286
func4: 92620 0.30714721310604887
>>> 

func1和func3类似，都是处理的list,删除报数为3的人，而func3更慢一点的原因是“if i>=len(ltPserion):”每次循环都获取了一次人员列表的长度。

func2和func4都没有删除数到3的人，只是在原队列中标记了去除的人，效率高了100倍，有此可见，程序执行循环耗费的时间，比队列的元素的删除省不少运行时间。func4比func2效率高一点点的原因是func2中“if SayNo%3==0:”使用了取余，取余操作的效率不如“if SayNo==3:SayNo = 1; else: SayNo += 1;”效率高。