惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

S
Secure Thoughts
P
Proofpoint News Feed
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Project Zero
Project Zero
Cyberwarzone
Cyberwarzone
K
Kaspersky official blog
AWS News Blog
AWS News Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
N
News | PayPal Newsroom
S
Schneier on Security
O
OpenAI News
S
Security @ Cisco Blogs
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
月光博客
月光博客
GbyAI
GbyAI
T
Tenable Blog
B
Blog
人人都是产品经理
人人都是产品经理
Engineering at Meta
Engineering at Meta
T
Troy Hunt's Blog
量子位
S
Security Affairs
Security Archives - TechRepublic
Security Archives - TechRepublic
The Cloudflare Blog
W
WeLiveSecurity
U
Unit 42
Application and Cybersecurity Blog
Application and Cybersecurity Blog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
The GitHub Blog
The GitHub Blog
Cloudbric
Cloudbric
A
About on SuperTechFans
Hacker News - Newest:
Hacker News - Newest: "LLM"
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Google DeepMind News
Google DeepMind News
博客园_首页
I
Intezer
P
Proofpoint News Feed
N
News and Events Feed by Topic
SecWiki News
SecWiki News
Microsoft Security Blog
Microsoft Security Blog
TaoSecurity Blog
TaoSecurity Blog
博客园 - 三生石上(FineUI控件)
NISL@THU
NISL@THU
Latest news
Latest news
H
Help Net Security
G
Google Developers Blog
博客园 - Franky
T
The Exploit Database - CXSecurity.com
Cisco Talos Blog
Cisco Talos Blog
Know Your Adversary
Know Your Adversary

博客园 - zim.NET

悼念友人 博客搬家了 函数调用中的黑客技术 3D学习笔记之一句话总结(不断更新中) 混乱你的代码 - zim.NET - 博客园 这么个女孩,你娶吗(转) 被误传了数千年的七句话(精简版_转载) 找工作故事之篇二 找工作故事之开篇 - zim.NET - 博客园 失落的阳光,陈酿的悲伤——许美静 一行命令解决批量重命名 求最长公共子序列 最小生成树算法讨论 用EditPlus打造你自己的IDE 将PPT内容导出为JPG图片 C/C++ 误区:fflush(stdin) 关于"extern" 闲谈成员初始化列表 脑筋急转弯3600题
一个空间换时间算法
zim.NET · 2007-10-09 · via 博客园 - zim.NET

说起空间换时间,想到c/c++语言的话我会想到#define宏定义和内联函数,他们都减少了函数切换时的压栈清栈等工作.对一个简短的函数,的确这些额外的消耗太浪费了.对于"计算素数"的问题,是一个经典的此类问题.

我们常用来找一个范围内的素数(质数)的办法有两种:
(1)筛选法
(2)判定法,即定义法

如:求1100间的所有素数。
分析

用筛选法,先把2100的数存到一个数组中,然后先把2的所有倍数删除掉(即让此数变为0),再删3的倍数,继续往上就是5的倍数,7的倍数……,最后,剩下的数(即数组中不为0的数)就是素数。

用判定法,对2-100内的每个数,根据素数的定义,除本身外没有其它约数来判定是否为素数.这个有个注意的地方是:找约数的时候不用找到n,也不用找到n/2,只要到sqrt(n)就行了.[别问为什么?自己想去咯.] 具体是<?, 这里有int 和double 的比较,有写sqrt(n)+1,也看到有人写sqrt(n+1) 的,哪个是正解自己多思考呵.

验证:
以下是筛选法代码:

long filter(int end)  //method:  filter  1..end
{
    start 
= time(NULL);
    
    
long count = 0;
    
long len = end +1;
    
int i,j,k;if(end<2return 0;//生成筛选集
    int* p = new int[len];
    
if(p == NULL) return 0;
    
for(i=0; i<len; ++i){
        p[i] 
= i;
    }
    
    
    
//筛选算法
    k = 2;    //作为筛选的除数
    i = k;
    
int max_test = sqrt(end) + 1;
    
while(i< max_test){
        
for(j=k+1; j<len; ++j)
        {
            
if(0 == p[j])
                
continue;
            
else if(p[j] % i ==0) {
                p[j] 
= 0;
            }
                
        }
        
for(j=k+1;j<len;++j)
        {
            
if(p[j] != 0){
                k 
= j;
                
break;
            }
        }
        i 
= k;
    }
//打印结果
    for(i=2;i<end;++i)
        
if(p[i] != 0
        {
            count
++;
            
//printf("%d\t",p[i]);
        }
    end 
= time(NULL);

    printf(

"\nit takes your %f seconds in filter.\n",difftime(end,start));
    printf(
"filter(end): count = %ld",count);
    delete[] p;
return count;

}

以下是判定法代码:

long judge(int beg, int end)  //method: judge every number
{
    start 
= time(NULL);
    
int count = 0;if(beg>end || beg<1return 0;
    
    register 
int i;
    
while(beg<end+1)
    {
        
for(i=2;i<sqrt(beg)+1++i){
            
if(beg % i ==0break;
        }
        
if(i>sqrt(beg)) 
        {
//    printf("%d\t",beg);
            count++;
            
//NULL;
        }
        beg
++;

    }

        
    end 

= time(NULL);

    printf(

"\nit takes your %f seconds in judge.\n",difftime(end,start));
    printf(
"judge(end): count = %ld\n",count);
    
return count;
}

下面看我们的结果:
我测试了从1-1000000内的素数:  耗时和统计结束如下:

it takes your 2.000000 seconds in filter.
filter(end): count = 78498
it takes your 5.000000 seconds in judge.
judge(end): count = 78498
Press any key to continue

这说明在N很大时,筛选法体现出了它的高效.在N比较小时,则看不出来其明显优势咯.筛选法用了很多的内存放要被处理的数据.但是此算法对内存的访问是顺序的,在经过有选择的取出除数(筛选器?)来否定一些保留一些.经过相对比较少的次数完成了对全部数据的筛选工作.在算法复杂度上,尽管还是O(n^2)[与判定法没有什么区别],但事实在其执行次数和访问速度得到了很大的提高.

当然,以上的筛选算法还是可以再改进一下的.

long filter2(int end)  //method:  filter  1..end
{
    start 
= time(NULL);
    
    
long count = 0;
    
long len = (end +1)/2;
    
int i,j,k;if(end<2return 0;//生成筛选集
    int* p = new int[len];
    
if(p == NULL) return 0;
    
for(i=0; i<len; ++i){
        p[i] 
= i*2+1;
    }
    
    
    
//筛选算法
    k = 1;    //作为筛选的除数在数组中的下标
    i = k;
    
int max_test = sqrt(end) + 1;
    
while(p[i]< max_test){
        
for(j = k+1;j<len;++j)
        {
            
if(0 == p[j])
                
continue;
            
else if(p[j] % p[i] ==0) {
                p[j] 
= 0;
            }
                
        }
        
for(j=k+1;j<len;++j)
        {
            
if(p[j] != 0)
            {
                k 
= j;
                
break;
            }
        }
        i 
= k;
    }
//打印结果
    for(i=1;i<len;++i)
        
if(p[i] != 0
        {
            count
++;
        
//    printf("%d\t",p[i]);
        }
    end 
= time(NULL);

    printf(

"\nit takes your %f seconds in filter.\n",difftime(end,start));
    printf(
"filter2(end): count = %ld",count);
    delete[] p;
return count;

}

以上的算法没有实质改进,不过其所用的内存少了一半,在进行比较等操作时循环也只有原来一半,所用的总时间和上面的筛选算法比也只是一半多一点,我觉得最重要的是,申请的内存少了,函数失败可能性变少,而且这个改进是比较有必要的,若任由它作无谓的计算,我会很心痛咯.呵呵.

注:虽然因判定法只用了几个变量,我想声明为寄存器变量,可是你知道的,"尽可能"并不是"一定",何况即使得到了,还不够快.硬件和软件算法的改善都有效果,硬件要成本,算法要技术。怎么办?掠拌.