package org.study;
/**
* 功能: 输入给定值,求该值范围内的完数。
* 完数: 一个数的所有因子之和等于数本身。
* 例如: 6=1+2+3;
*/
public class PerfectNumber
{
//保存所有因子值;
private int[] factors;
//有效因子数目,同时也做index用。
private int factorSize;
public PerfectNumber()
{
this(512);
}
public PerfectNumber(int factorNum)
{
factors = new int[factorNum];
factorSize=0;
//任何数的第一个因子为1
factors[factorSize++]=1;
}
public void reset()
{
//factors[0]=1 有效
factorSize=1;
}
/**
* 求输入值范围内的所有完数,并打印。
*/
public void getAllPerfectNumbers(int limit)
{
for(int i=4; i<= limit; i++)
{
//重置factors的有效标志位
reset();
if(isPerfectNumber(i))
{
System.out.print(i+"\t");
}
}
}
/**
* 判断输入的数,是否是完数。若是返回true,否则返回false。
*/
public boolean isPerfectNumber(int input)
{
int mid =(int)Math.sqrt(input);
int another = 0;
int sum = 0;
//一个数的因子有小的部分和大的部分,求到小的就可以得到大的。
for(int i=2; i<=mid; i++)
{
if(input % i == 0)
{
factors[factorSize++] = i;
another = input / i;
//若它的另一个因子不同则保存,否则丢弃。
if(another != i)
{
factors[factorSize++] = another;
}
}
}
//求所有因子之和
for(int i=0; i<factorSize; i++)
{
sum+=factors[i];
//System.out.println("input = "+input+", factors["+i+"] = "+factors[i]);
}
if(sum == input)
return true;
else
return false;
}
public static void main(String[] args)
{
PerfectNumber pn = new PerfectNumber();
//打印出1000范围内的所有完数
pn.getAllPerfectNumbers(1000);
}
}
该方法求解1000, 0000以内的完数,耗时130多秒,求解到4个完数。
后来经过思索,想到了多线程方式求解,改进了一下时间。程序如下:
package org.study;
import java.util.concurrent.CountDownLatch;
/**
* 功能: 输入给定值,求该值范围内的完数。
* 完数: 一个数的所有因子之和等于数本身。
* 例如: 6=1+2+3;
*/
public class PerfectNumber implements Runnable
{
private static final int DEFAULT = 512;
//保存所有因子值;
private int[] factors;
//有效因子数目,同时也做index用。
private int factorSize;
private int start;
private int end;
private CountDownLatch cdl;
public PerfectNumber()
{
this(DEFAULT);
}
public PerfectNumber(int factorNum)
{
factors = new int[factorNum];
factorSize=0;
//任何数的第一个因子为1
factors[factorSize++]=1;
}
public PerfectNumber(int start, int end, CountDownLatch cdl)
{
this(DEFAULT);
this.start = start;
this.end = end;
this.cdl = cdl;
}
public void reset()
{
//factors[0]=1 有效
factorSize=1;
}
/**
* 判断输入的数,是否是完数。若是返回true,否则返回false。
*/
public boolean isPerfectNumber(int input)
{
int mid =(int)Math.sqrt(input);
int another = 0;
int sum = 0;
//一个数的因子有小的部分和大的部分,求到小的就可以得到大的。
for(int i=2; i<=mid; i++)
{
if(input % i == 0)
{
factors[factorSize++] = i;
another = input / i;
//若它的另一个因子不同则保存,否则丢弃。
if(another != i)
{
factors[factorSize++] = another;
}
}
}
//求所有因子之和
for(int i=0; i<factorSize; i++)
{
sum+=factors[i];
//System.out.println("input = "+input+", factors["+i+"] = "+factors[i]);
}
if(sum == input)
return true;
else
return false;
}
public void run()
{
for(int i=start; i<= end; i++)
{
//重置factors的有效标志位
reset();
if(isPerfectNumber(i))
{
System.out.print(i+"\t");
}
}
//线程执行完成,线程计数器减1
cdl.countDown();
}
public static void main(String[] args)
{
final int limit = 10000000;
final int THREAD_NUM = 5;
CountDownLatch cdl = new CountDownLatch(THREAD_NUM);
//打印出1000范围内的所有完数
System.out.println("All perfect numbers of "+limit);
java.util.Date start = new java.util.Date();
for(int i=0; i< THREAD_NUM; i++)
{
Runnable pn = new PerfectNumber(limit*i/THREAD_NUM+1, limit*(i+1)/THREAD_NUM, cdl);
Thread t = new Thread(pn);
t.start();
}
//等待所有线程都执行完成
try
{
cdl.await();
}
catch (Exception e)
{
e.printStackTrace();
}
java.util.Date end = new java.util.Date();
System.out.println("\n cost "+(end.getTime()-start.getTime())/1000.0+" s");
}
}
经过改进,使用多线程方式求解,使用5个线程求解耗时69.406秒, 使用10个线程求解耗时65.453秒。多线程也只能到这里。下一步看能不能优化算法了?