从Python求素数到list与dict的比较
2012-08-31 18:08
253 查看
上学期上网络安全课的时候,杨老简单介绍了一些关于求素数的方法,闲着无聊,把筛选法用python实现了一下,发现有些好玩儿的地方:
从2开始依次往后面数,如果当前数字一个素数,那么就将所有其倍数的数从表中删除或者标记,然后最终得到所有的素数。
测试以后得到的结果是:求一千万以内的素数用了9.68秒
可是我觉得使用1个dict和1个list存会很浪费空间(其实不然,一千万以内的素数只有66万个,相对一千万来说可以忽略不计),所以想改进一下算法
因为无法在for中删除list,所以使用一个xrange,然后每次判断k是否在lis中再做删除,结果:求十万以内的素数一共花了186.79秒。
结果是:
可以看出,在查找方面list是远远不如dict的,说明list不应该是哈希查找,而remove的时间也远远大于哈希的赋值时间(好像这是句废话- -)
不过由此判断第二种方法是一无是处的话未免言之过早了。因为第二种方法里面的实现是先申请了一段空间,然后再运算,而实现一的空间是动态增长的(在给哈希表赋值的那边体现),所以如果涨到一半发现内存不够用的话就会报错(测试1亿数据的时候就出现了这个问题),而实现二一开始就会报错,而不用做前面的一系列无用功。
总之就是空间换时间,时间换空间的那些戏码。不过挺有意思。
最后小tip:好像python的垃圾回收机制有点什么问题,我结束一次测试以后以前的内存不回收,有空了解一下,有一个暂时解决的办法。可以调用gc module里面的collect函数,挺好用~
原理:
素数,指在一个大于1的自然数中,除了1和此整数自身外,不能被其他自然数整除的数。在加密应用中起重要的位置,比如广为人知的RSA算法中,就是基于大整数的因式分解难题,寻找两个超大的素数然后相乘作为密钥的。一个比较常见的求素数的办法是埃拉托斯特尼筛法(the Sieve of Eratosthenes) ,说简单一点就是画表格,然后删表格,如图所示:从2开始依次往后面数,如果当前数字一个素数,那么就将所有其倍数的数从表中删除或者标记,然后最终得到所有的素数。
实现:
下面是python的一个实现:实现1:
首先用dic存储n范围内的元素,然后依次标记,最后从头扫描一次dic,把合适的元素放在list中返回结果def prime(n): lis = {} for i in xrange(2,n+1): if not i in lis: lis[i] = 1 k = i*2 while k <= n: lis[k] = 0 k = k+i ans = [] for i in lis: if lis[i] == 1: ans.append(i) return ans
测试以后得到的结果是:求一千万以内的素数用了9.68秒
可是我觉得使用1个dict和1个list存会很浪费空间(其实不然,一千万以内的素数只有66万个,相对一千万来说可以忽略不计),所以想改进一下算法
实现2:
这次只用一个list存数字,然后遍历删除def primeC(n): lis = range(2,n+1) for i in xrange(2,n+1): if i in lis: k = i+i while k<=n: if k in lis: lis.remove(k) k = k+i return lis
因为无法在for中删除list,所以使用一个xrange,然后每次判断k是否在lis中再做删除,结果:求十万以内的素数一共花了186.79秒。
比较:
在时间上,第一个方法远远比第二个办法有效率,dict是哈希实现,查询的速度是常数级的,所以在标记合数的时候所花费的时间非常少,但是list是顺序表,不知道内部是怎么实现in 和 remove的,从时间上可以大概推测出应该是顺序查找实现的,所以用如下代码做了测试:import random import time def find(source,test): for each in test: each in source def remove(liss,test): for each in test: if each in liss: liss.remove(each) def removeDic(dicc,test): for each in test: if each in dicc: dicc[each] = 1 n = 100000 m = 1000 liss = range(n) dicc = {i:0 for i in xrange(n)} test = [] for i in xrange(m): test.append(random.randint(0,n)) s = time.clock() find(liss,test) print time.clock()-s s = time.clock() find(dicc,test) print time.clock()-s s = time.clock() remove(liss,test) print time.clock()-s s = time.clock() removeDic(dicc,test) print time.clock()-s
结果是:
1.10526960281 0.00036479383832 2.11714318396 0.000374692766596
可以看出,在查找方面list是远远不如dict的,说明list不应该是哈希查找,而remove的时间也远远大于哈希的赋值时间(好像这是句废话- -)
不过由此判断第二种方法是一无是处的话未免言之过早了。因为第二种方法里面的实现是先申请了一段空间,然后再运算,而实现一的空间是动态增长的(在给哈希表赋值的那边体现),所以如果涨到一半发现内存不够用的话就会报错(测试1亿数据的时候就出现了这个问题),而实现二一开始就会报错,而不用做前面的一系列无用功。
总之就是空间换时间,时间换空间的那些戏码。不过挺有意思。
小结:
求素数,list和dict的效率比较最后小tip:好像python的垃圾回收机制有点什么问题,我结束一次测试以后以前的内存不回收,有空了解一下,有一个暂时解决的办法。可以调用gc module里面的collect函数,挺好用~
相关文章推荐
- Python【基础:数据类型和变量 字符串和编码 list和tuple 条件判断 循环 dict和set】注意事项(与java,c比较)
- python的list,dict,tuple比较和应用
- python list/tuple/dict/set/deque的简单比较、优化和时间复杂度(表格)
- python dict 与list比较
- python中in在list和dict中查找效率比较
- python的list,dict,tuple比较和应用
- python---数据结构与数据类型,list,dict,tuple,排序sort,比较cmp,字符串模版
- python的list,dict,tuple比较和应用
- Python中set、list、dict、tuple的比较
- python的list,dict,tuple比较和应用
- Python笔记-list、tuple、dict、set及其比较
- python中list、set、tuple、dict比较分析
- python内置数据类型:list,tuple,dict比较
- PYTHON内置数据类型( list ,tuple ,dict,set)
- python的dict,set,list,tuple应用详解
- Python的Set和List的性能比较 + 两者之间的转换
- 【Python】 list & dict & str
- Python学习笔记(9)-列表list、元组tuple、字典dict、集合set
- Python 列表(list)、字典(dict)、字符串(string)常用基本操作小结
- python的dict、list、set学习运用