标题:求优化下程序,这个程序能用,就是运行太慢,求优化下能加快速度
只看楼主
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 20楼 rjsp
1.zip (51.58 KB)
2012-11-10 17:00
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
给你提供一个文件,你运行一下看看。不是要按照这个文件中字符的顺序输出,而是按照aaaaaaaa、aaaaaaac、aaaaaaag等这个随机排列的顺序输出。我上个提供的结果,就是按照这样结果输出的,虽然提供的文件中第一个8字符不是aaaaaaaa。但是它输出的时候结果是aaaaaaaa 1。
----- 你说话很绕口,我一直都是按照排列顺序输出的,和你的要求是一致的,你认真点行不行?

1.zip
----- 我运行了,很OK。你觉得有什么问题就直说,别打哑谜
2012-11-12 08:54
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
备注一下将 'a' 'g' 'c' 't' 转化 0 1 2 3 的一种数学方法是 %36%5
printf( "%d %d %d %d\n", 'a'%36%5, 'g'%36%5, 'c'%36%5, 't'%36%5 ); 输出为 0 1 2 3
2012-11-12 10:47
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 23楼 rjsp
你的程序没有问题。我也试了,小文件能用(几千,上万吧),有结果。我的文件超过20万个字符串,你的程序就无法运行了。一点就关闭了。
2012-11-14 09:12
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 22楼 rjsp
最后一个问题了,我的文件太大,1.8个G,大概17亿个字符吧。一点就关闭了。小文件的话,可以运行的,结果很好!
2012-11-14 09:49
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
以下是引用a13780393在2012-11-14 09:49:40的发言:

最后一个问题了,我的文件太大,1.8个G,大概17亿个字符吧。一点就关闭了。小文件的话,可以运行的,结果很好!

你用的是12楼的代码吧,那代码中没有使用任何空间增长的代码,所以和文件大小应当无关
我想唯一的问题有可能是你的fgetc库可能有问题,你告诉我你使用的操作系统和编译器是什么?
另外,下午我自己生成个随机的1.8G文件测试一下
2012-11-14 10:09
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
我用如下代码生成了一个1.8G的测试文件
程序代码:
    FILE* file = fopen( "result1.txt", "wb" );
    if( !file )
        return 1;
    for( size_t i=0; i<180000000; ++i )
    {
        fputc( "agct"[rand()%4], file );
    }
    fclose( file );
然后用12楼的代码,在15秒内就处理完这个1.8G的文件,没有出现任何错误

我的操作系统是32位windows xp
用编译器VC++2008 SP1编译运行测试通过
用编译器MinGW 4.7.2编译运行测试通过

现在我怀疑你的文件中除了a g c t @ \n之外的其他字符,你将
        default: // 出现了agct之外的字符
            fclose( fin );
            return 2;
        }
改为
        default: // 出现了agct之外的字符
            printf( "出现非法字符%c\n", (char)c );
            fclose( fin );
            return 2;
        }
试试看
2012-11-14 10:56
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 27楼 rjsp
3.rar (394.85 KB)
你运行一下,这个文件,这个是我从1.8G个文件中随机截取了一部分,无法运行。输出结果就是“出现非法字符”但是不知道是什么字符。
2012-11-14 14:41
rjsp
Rank: 20Rank: 20Rank: 20Rank: 20Rank: 20
等 级:版主
威 望:507
帖 子:8890
专家分:53117
注 册:2011-1-18
得分:0 
我来跟你讲讲文本格式吧
在Unix/Linux/MAC中,文本文件的行间隔用 \n
而Windows中用 \r\n
但用户是无须关心这种差别的,因为只要使用文本格式(而非二进制格式)打开文件,Unix/Linux/MAC下会将\n原样读出来写进去,而Windows会将文本中的\r\n读成\n,而将写入的\n写成\r\n。也就是,库函数本身已经做了相应的转化。
但你不能将Unix/Linux/MAC中文本格式用Windows库处理,反之亦不可,否则就是牛头对马嘴了。
而你给的这个3.txt中,文件间隔竟然用的是\r,^_^

为了适合你这个文件,我将代码改一下,你以后换文件格式时记得改代码,也就是case '\r': case '\n':那两行
程序代码:
#include <stdio.h>
#include <string.h>
#include <assert.h>

void dna8_val2str( unsigned long val, char str[8] )
{
    assert( val < (1ul<<(8*2)) );

    for( size_t i=0; i<8; ++i )
    {
        str[7-i] = "agct"[val%4];
        val >>= 2;
    }
}

int main()
{
    unsigned long words = 0;
    unsigned long numbers[65536] = { 0 };

    // 处理
    FILE* fin = fopen( "3.txt", "r" );
    if( !fin )
        return 1;
    int bav = 0;
    unsigned long val = 0;
    for( int c; c=fgetc(fin), c!=EOF; )
    {
        switch( c )
        {
        case '@': // 遇到@则结束
            break;
        case '\r':
        //case '\n':
            ++words;
            continue;
        case 'a':
        case 'g':
        case 'c':
        case 't':
            val = ((val<<2)&0xFFFF) | (c%36%5);
            if(bav<7) // 不足8个有效字符时先等等
                ++bav;
            else
                ++numbers[val];
            break;
        default: // 出现了agct之外的字符
            long pos = ftell(fin)-1;
            if( c>0x20 && c<0xFF ) // 可显示的字符,就显示其本身
                printf( "--- 0x%08lX处出现非法字符\'%c\'\n", pos, (char)c );
            else // 不可显示的字符,就显示其对应的ASCII值
                printf( "--- 0x%08lX处出现非法字符0x%02hhX\n", pos, (char)c );
        }
    }
    fclose( fin );

    // 输出
    FILE* fout = fopen( "result2.txt", "w" );
    if( !fout )
        return 3;
    fprintf( fout, "The Number of total words are %ld\n", words );
    fprintf( fout,"The Expect Number words are %f\n", words/65536.0 );
    for( int i=0; i<65536; ++i )
    {
        // if( numbers[i] !=0 )
        {
            char str[8];
            dna8_val2str( i, str );
            fprintf( fout, "%.8s\t%ld\t%f\n", str, numbers[i], numbers[i]/65536.0 );
        }
    }
    fclose( fout );
    printf( "处理完毕\n" );

    return 0;
}
另外注意一下,我用unsigned long计数,也就是数量不可以超过4亿。如果数量超过,你得改类型,还得改相应的ftell


[ 本帖最后由 rjsp 于 2012-11-15 09:02 编辑 ]
2012-11-14 16:10
a13780393
Rank: 1
等 级:新手上路
帖 子:45
专家分:0
注 册:2012-10-6
得分:0 
回复 29楼 rjsp
原来如此,明白了,太感谢你了。说实话如果你现在让我给你付款我都愿意,帮了我大忙了。这个程序运行非常快,能节省我95%的时间。我的原文件有将近20亿个字符,你刚才说现在这个只能读取4亿个字符,如果要更多的话,是把哪个地方改一下?我没看明白。愿帮人帮到底,不胜感激!!!
2012-11-14 16:52



参与讨论请移步原网站贴子:https://bbs.bccn.net/thread-386526-1-1.html




关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.038029 second(s), 8 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved