1的个数
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
求1的个数的算法与性能分析
摘要
本课题研究的是给定十进制数N的情况下,求出现1的个数的算法,算法来源《算法之美》。本文首先依据遍历N个数的思路,通过分析,给出解决问题的算法;然后,在此基础上,提出效率更高的算法,从而,弥补了当N足够大时,运行效率低的不足。最后,将其与之前的算法通过Visual Studio 2010软件进行性能分析。对比两个算法,通过性能分析,比较两者在运行时间和效率上的差异。
关键字:算法,1的个数,性能分析
Abstract
We study the algorithms which under the condition of given decimal number N, and find the number of 1. The algorithm from《The Beauty of algorithm》.This paper based on the traveral N number of ideas, through the analysis, we can give the algorithm to solve the problem;Then the efficient algorithm is put forward in order to make up of the lack of low operating efficiency when N is large enough. Finally, we can analyze the previous algorithm through the Visual Studio 2010. Through performance alalysis, we can compare the two algorithms of the difference between running time and efficiency.
Key words: Algorithm, The number of 1, Performance analysis
1.引言
一直以来,算法被设计用来解决各种问题,它规定了解决问题的运算序列。算法作为一门独立的学科,主要分为设计与分析。最初,人们对于算法的要求仅仅是设计出来可以用来解决问题,但是,随着人们对高效率的渴望,人们不仅希望算法可以用来解决问题,并且可以高效、快速的解决。因此,开启了对算法的分析改进的时代。
一般而言,描述算法优劣的指标主要包括正确性,可读性,健壮性,时间复杂度和空间复杂度。其中,正确性,可读性,健壮性是我们在设计算法时,就应该保证实现的功能。而对算法的空间以及时间的复杂性研究更多的时候是分析已有的算法,通过改进算法,对其效率进行分析。
2.问题的描述
给定一个10进制的数N,写下从1到N的所有数中,出现1的次数。要求写一个算法,求函数()
f N,返回从1到N中出现的1的个数。
例如,当N=5时,写下一组数为1,2,3,4,5,那么,出现1的个数为1;
同理:当N=12时,1,2,3,4,5,6,7,8,9,10,11,12,那么,出现1的个数为5。
3.算法的分析
3.1遍历法
通过分析得出,解决该问题的最简单的算法就是从1开始遍历到N,将其中每一个数中含有1的个数加起来,便可得到出现1的个数。算法如下:ULONGLONG Count1InAInteger(ULONGLONG n)
{
ULONGLONG iNum=0;
while(n!=0)
{
iNum+=(n%10==1)?1:0;
n/=10;
}
return iNum;
}
ULONGLONG f(ULONGLONG n)
{ ULONGLONG iCount=0;
for (ULONGLONG i=1;i<=n;i++)
{
iCount+=Count1InAInteger(i);
}
return iCount;
}
算法的主题思路是首先定义一个无符号的超长整型的数据类型,通过设计函数()f n 实现从1到N 的遍历过程,其中,函数Count1InAIntege 用来判断所经历的的数是否含有数字1,最后,通过调用函数Count1InAIntege 实现最终的目标。以上代码只要加入简单的主函数,就可以运行得到所要的结果。主函数如下所示:
void main()
{
ULONGLONG n=10000;
f(n);
printf("f(n)=%d\n",f(n));
getchar();
}
以上的主函数,我们取N=10000为例,当然也可以设置输入N 。从以上的代码,可以看出,算法虽然被设计的简单易读,但是,在运行过程中,随着N 的不断增大,遍历的数也越来越多,这给空间和时间上都带来了一定的负担,虽然随着科学技术的发展,计算机的内存空间不断的扩充,我们可以暂且忽略这一因素。但是,时间上的效率是我们不得不关注的问题。随着N 的增大,算法的运行效率越来越低。因此,我们必须设计一种新的算法,尽量避免遍历N 个数的过程,从而,提高算法的运行效率。
3.2改进的算法
基于以上算法的缺点,我们不再通过遍历N 个数来统计其中含有数字1的个数,而是,试图探索小于N 的数在每一位上可能出现数字1的次数,然后,通过求和得到最终的结果。
下面我们对每一位可能出现数字1的次数进行讨论,力求得出我们想要的规律。
ⅰ.当N 只是一位数时,即010N ≤<,那么,显然当N=0时,()0f N =;而当010N <<时,()1f N =。
ⅱ.当N为2位数的时,那么各位和十位上都有可能为1。我们发现,各位上出现1的个数不仅与个位上的数有关,还与十位上的数有关。同样,十位上出现1的个数不仅与十位上的数有关,也与个位上的数有关。下面分情况讨论:
①当个位上的数字等于0时,十位上的数等于个位上可能出现的1的个数;
②当个位上的数字大于或等于1时,个位上可能出现的1的个数等于十位上的数字加1(实际上所加数字是1);
③当十位上数字等于1时,十位上出现1的次数等于个位上的数字加1(实际上所加数字为10);
④当十位上数字大于1时,十位上出现1的次数等于10,即10-19。
以上分析得出,当N为两位数时,十位上出现1的个数由个位决定,个位上出现1的个数由十位决定。我们的思想是通过分析各个位上可能出现的1的次数,来设计相应的算法,那么同理,可以分析3位数,4位数以及更多位数出现数字1的总个数。
我们设N=abcde,我们举例分析百位上出现1的次数,当然读者可以同理分析其他位上的数字1出现的次数。
如果百位上的数字为0,那么,百位上出现数字1的次数由高位决定。因为求百位上出现数字1的个数就是要求同时满足小于N的并且百位上出现数字1的数的集合,即高位数字100
⨯。
如果百位上的数字为1,那么,百位上出现数字1的次数既有高位决定,也由低位决定。和以上的分析一样,除了具有高位数字100
⨯个1出现之外,还需要加上满足大于高位数字100
⨯,小于N并且百位上出现数字1的数的集合。
如果百位上的数字大于1,那么,百位上出现1的次数仅由高位决定,即存在(高位数字+1)100
⨯个数字1出现。
以上我们只是分析百位上出现数字1的个数的情况,同理,可以分析其他位上的出现数字1的次数的情况。因此,依据以上的规律,给出代码如下:LONGLONG Sum1s(ULONGLONG n)
{
ULONGLONG iCount=0;
ULONGLONG iFactor=1;
ULONGLONG iLowerNum=0;
ULONGLONG iCurrNum=0;
ULONGLONG iHigherNum=0;
while(n/iFactor!=0)
{
iLowerNum =n-(n/iFactor)*iFactor;