php排序1亿个QQ号码,该如何解决

php排序1亿个QQ号码吃饱喝足了,还发贴了。拆开分成几千份进行排序再合并。首先先创建一个1亿个QQ号的txt。?p

php排序1亿个QQ号码
吃饱喝足了,还发贴了。
拆开分成几千份进行排序再合并。


首先先创建一个1亿个QQ号的txt。


<?php

// 创建一亿个QQ号的txt (大约需85~100秒)

set_time_limit(0);
$fn = 'qq.txt';
$fp = fopen($fn, 'w');

$st = microtime(true);

$l = range(0,10000);
shuffle($l);
foreach ($l as $k=>$v)
{
$arr = range($v*10000+10000,10000*($v+1)+9999);
shuffle($arr);
fputs($fp,implode("\n", $arr)."\n");
unset($arr);
}

echo  microtime(true)-$st;

?>


 

稍等一两分钟1亿个随机QQ创建完成了。

QQ号码范围为>10000。文件大小大概有840MB。



下面就进行分类划分成几千份文件。

以QQ号码长度为文件夹,QQ号码前3位为文件名。


<?php

// 长度号码分类 (大约需360~400秒)

set_time_limit(0);
$st = microtime(true);

if(!is_dir('qq_no')) mkdir('qq_no');
$file = fopen('qq.txt', 'r'); 


$i=0;
$end_s = '';
while(!feof($file))
{
$g = 1042*1024;
fseek($file,$g*$i);
$s = fread($file, $g);

 
$end = strrpos($s, "\n");
$arr_s = $end_s.substr($s, 0, $end);
$end_s = substr($s, $end);

$arr = explode("\n", $arr_s);
foreach ($arr as $k=>$v)
{
if($v!='')
{
$tag = "$v[0]$v[1]$v[2]";
$text_arr[strlen($v)][$tag][] = $v;
}
}

foreach ($text_arr as $k=>$v)
{
$n_dir = 'qq_no/'.$k;
if (!is_dir($n_dir)) mkdir($n_dir);
foreach ($v as $tag=>$val)
{
$n_tf = fopen($n_dir.'/'.$tag.'.txt', 'a+');
fputs($n_tf,implode("\n",$val)."\n");
}


}
unset($text_arr);

++$i;

}

echo  microtime(true)-$st;

?>




最后就要每个文件进行排序合并数据了。


<?php

// 排序完成拉 (800~920秒)

set_time_limit(0);
$st = microtime(true);

$qq_done = fopen('qq_done.txt', 'a+');

$root = 'qq_no';
$dir_array = scandir($root);

foreach ($dir_array as $key=>$val)
{
if ($val != '.' && $val != '..')
$dirs[$val] =  scandir($root.'/'.$val);
}


foreach ($dirs as $key=>$val)
{
foreach ($val as $v)
{
if ($v != '.' && $v != '..')
{
$file = $root. '/' . $key . '/'. $v;
$c = file_get_contents($file);
$arr = explode("\n", $c);
sort($arr);
fputs($qq_done, implode("\n",$arr));
unlink($file);
}
}
rmdir($root. '/' . $key);
}
rmdir($root);

echo  microtime(true)-$st;

?>



总共大概花费了20多分钟。

虽然完成了,但方法很土鳖 0_0 ,坛里各位高手们改进改进啊。

[解决办法]
来个C版本的

#include <stdio.h>

#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 100000000

int a[1 + N/BITSPERWORD];

void set(int i)


{
a[i>>SHIFT] 
[解决办法]
= (1<<(i & MASK)); //i&MASK相当于1&(32-1),即1%32
}

void clr(int i)
{
a[i>>SHIFT] &= ~(1<<(i & MASK));
}

int test(int i)
{
return a[i>>SHIFT] & (1<<(i & MASK));
}

int main()
{
int i;
//初始化
for(i = 0; i < N; i++)
clr(i);

//读取文件,置位
while(scanf("%d", &i) != EOF)
set(i);

for(i = 0; i < N; i++)
if(test(i))
printf("%d\n", i);

return 0;
}


[解决办法]

既然有现成的数据文件,就没有必要去构造插入串了
set_time_limit(0);
$sql =<<< SQL
CREATE TABLE IF NOT EXISTS qq1 (
  `qq` int(10) NOT NULL,
  KEY `qq` (`qq`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8;
SQL;

mysql_connect('localhost', 'root', '');
mysql_select_db('test');
mysql_query($sql);

$filename = str_replace('\\', '/', realpath('qq.txt'));
$sql =<<< SQL
LOAD DATA INFILE '$filename' INTO TABLE qq1
SQL;

check_speed(1);
mysql_query($sql) or print(mysql_error());;
check_speed();
时间: 182,955,851 微秒
内存: 664


set_time_limit(0);
mysql_connect('localhost', 'root', '');
mysql_select_db('test');

echo '升序<br />';
$filename = str_replace('\\', '/', dirname(__FILE__) . '/qq_1.txt');
if(file_exists($filename)) unlink($filename);
$sql =<<< SQL
SELECT qq FROM  qq1 ORDER BY qq ASC INTO OUTFILE '$filename'
SQL;
check_speed(1);
mysql_query($sql) or print(mysql_error());
check_speed();

echo '降序<br />';
$filename = str_replace('\\', '/', dirname(__FILE__) . '/qq_2.txt');
if(file_exists($filename)) unlink($filename);
$sql =<<< SQL
SELECT qq FROM  qq1 ORDER BY qq DESC INTO OUTFILE '$filename'
SQL;
check_speed(1);
mysql_query($sql) or print(mysql_error());
check_speed();

echo '主键可不排序<br />';
$filename = str_replace('\\', '/', dirname(__FILE__) . '/qq_0.txt');
if(file_exists($filename)) unlink($filename);
$sql =<<< SQL
SELECT qq FROM  qq1 INTO OUTFILE '$filename'
SQL;
check_speed(1);
mysql_query($sql) or print(mysql_error());;
check_speed();


升序
时间: 46,308,538 微秒
内存: 520

降序
时间: 105,860,001 微秒
内存: 432

主键可不排序
时间: 38,615,022 微秒
内存: 432

[解决办法]
ok, 又试了全是11位的QQ号, 实际上100020001个,
sort一下, 22分钟


引用:
引用:

这位同学请教一下,直接sort怎么弄啊?

引用:

用你代码生成qq.txt,

然后直接sort,
在我的fedora(vmware)里18分钟出结果

(可能还要短一点,因为我把它放后台了)




就是unix的命令sort啊

改天我再试试大点的文件和mysql数据库






[解决办法]
主贴的qq号默认最大是100009999,而目前可能的最大qq号却是9999999999,差好多个数量级呢,实际情况使用位排序就是 9999999999 /8 /1024 /1024 差不多1.1G内存。。。
用主贴生成的数据测试了下,机器比较烂,花了300多秒生成,用c实现的位排序法读,排,写,总共时间差不多1分10秒多,LZ可以拿去测试看看,对了,主贴中生成qq号我改成了1行一个qq,方便读。
fputs($fp,implode(PHP_EOL, $arr).PHP_EOL);

ubuntu linux下gcc编译
#include <stdio.h>             
#include <stdlib.h>            
#define MAX 100009999          
#define SHIFT 5                
#define MASK 0x1F              
#define DIGITS 32              
int a[1+MAX/DIGITS];           

void set(int n)      
{
    a[n>>SHIFT]=a[n>>SHIFT]
[解决办法]
(1<<(n&MASK));     
}                                              

void clear(int n)              
{
    a[n>>SHIFT]=a[n>>SHIFT]&(~(1<<(n&MASK)));   
}

int test(int n)                
{
    return a[n>>SHIFT] & (1<<(n&MASK));        
}

int main(int argc, char *argv[])
{
    int i;                     
    int  tp;                                                                                                                                                  
    FILE *ip;
    FILE *op;
    for(i=1;i<=MAX;i++)
    {
        clear(i);
    }
    ip = fopen("qq_before_sort.txt","r");
    while( !feof(ip) )


    {
        fscanf(ip,"%d\n",&tp);
        set(tp);
    }   
    fclose(ip);
    op = fopen("qq_after_sort.txt","w"); 
    for(i=1;i<=MAX;i++)
    {
        if(test(i)){
                fprintf(op, "%d\n",i);
        }
    }
    fclose(op);
    return 0;
}