标签:
洗牌问题: 洗一副扑克,有什么好办法?既能洗得均匀,又能洗得快?即相对于一个文件来说怎样 高效率的实现乱序排列? 关于洗牌问题,其实已经有了一个很好的shell解法,这里另外给三个基于AWK的方法, 有错误之处还请不吝指出。 方法一穷举: 类似于穷举法,构造一个散列来记录已经打印行出现行的次数,如果出现次数多于一 次则不进行处理,这样可以防止重复,但缺点是加大了系统的开销。 awk -v N=`sed -n ‘$=‘ data` ‘ BEGIN{ FS="\n"; RS="" } { srand(); while(t!=N){ x=int(N*rand()+1); a[x]++; if(a[x]==1) { print $x;t++ } } } ‘ data 方法二变换: 基于数组下标变换的办法,即用数组储存每行的内容,通过数组下标的变换 交换数组的内容,效率好于方法一。 #! /usr/awk BEGIN{ srand(); } { b[NR]=$0; } END{ C(b,NR); for(x in b) { print b[x]; } } function C(arr,len,i,j,t,x){ for(x in arr) { i=int(len*rand())+1; j=int(len*rand())+1; t=arr[i]; arr[i]=arr[j]; arr[j]=t; } } 方法三散列: 三个方法中最好的。 利用AWK中散列的特性(详细请看:info gawk 中的7.x ),只要构造一个 随机不重复的散列函数即可,因为一个文件每行的linenumber是独一无二的,所 以用: 随机数+每行linenumber ------对应------> 那一行的内容 即为所构造的随机函数。 从而有: awk ‘BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}‘ data 其实大家担心的使用内存过大的问题不必太在意,可以做一个测试: 测试环境: PM 1.4GHz CPU,40G硬盘,内存256M的LAPTOP SUSE 9.3 GNU bash version 3.00.16 GNU Awk 3.1.4 产生一个五十几万行的随机文件,大约有38M: od /dev/urandom |dd count=75000 >data 拿效率较低的方法一来说: 洗牌一次所用时间: time awk -v N=`sed -n ‘$=‘ data` ‘ BEGIN{ FS="\n"; RS="" } { srand(); while(t!=N){ x=int(N*rand()+1); a[x]++; if(a[x]==1) { print $x;t++ } } } ‘ data 结果(文件内容省略): real 3m41.864s user 0m34.224s sys 0m2.102s 所以效率还是勉强可以接受的。 方法二的测试: time awk -f awkfile datafile 结果(文件内容省略): real 2m26.487s user 0m7.044s sys 0m1.371s 效率明显好于第一个。 接着考察一下方法三的效率: time awk ‘BEGIN{srand()}{b[rand()NR]=$0}END{for(x in b)print b[x]}‘ data 结果(文件内容省略): real 0m49.195s user 0m5.318s sys 0m1.301s 对于一个38M的文件来说已经相当不错了。 玩的愉快!
标签:
原文地址:http://www.cnblogs.com/archoncap/p/4964006.html