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

问题如题:N个人围城一圈报数(1/2/3/1/2/3/...),数到3的退出队列,求最后留下的人

#-*- 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
>>> 

分析: 

对于上面的问题,采用了4个方法处理,求得的结果是方法4效率最高。

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;”效率高。

当然func2、func4比起func1、func3也有弊端,就是占用的内存,func1、func3运行内存会不断的减小,而func2、func4不会减小。

展开阅读全文

没有更多推荐了,返回首页