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秒。多线程也只能到这里。下一步看能不能优化算法了?
求给定值范围内的所有完数
最新推荐文章于 2023-12-19 00:20:47 发布