当前位置:编程学习 > JAVA >>

大计算场景下 N个自然数的全排列问题

  题目看起来很简单,但是要关注两个问题:
               1. 避免使用递归算法,因为这样会使计算复杂度成指数级别上升
               2. 巨大的计算量下,如何把计算工作切分成若干模块,并行。 现代计算机的特点是多核心,家用PC双核,四核,server上18路,36路核心。把大数据运算切分到各个核心上会事半功倍。
              
                因此我花了周六写了一个代码, 用非递归算法求全排列, 用特定的算法的把计算量分割成若干单元,用java线程池运算。 运算结果写本地文件。
               我的本地机器 2.93HZ双核CPU, 4G内存, win7系统,最高作了16个自然数的全排列,进行了一共4亿六千万次的运算,2分钟内完成。这个成绩还是可以的。
              
                更进一步,如果还想提高运算能力, 我会考虑用x86集群, 每个机器上启动一个JVM, 各个JVM之间tcp通信协同作业, 能将运算速度再提高一个数量级。
                有兴趣研究更深入算法或者技术实现的可以联系我,以下是我的代码:
               
                 #代码开源共享,但是转载的时候请注明出处,谢谢合作!!
                
[java]  
import java.io.FileWriter;  
import java.io.IOException;  
import java.math.BigInteger;  
import java.text.SimpleDateFormat;  
import java.util.ArrayList;  
import java.util.Arrays;  
import java.util.Collections;  
import java.util.Date;  
import java.util.concurrent.Callable;  
import java.util.concurrent.ExecutorService;  
import java.util.concurrent.Executors;  
import java.util.concurrent.Future;  
  
/** 
 * 非递归算法 + 分割成若干计算单位并发运算  
 * 在高计算量下会有明显优势,但是在计算量较小,线程切换会有开销 
 * 本地机器 2.93HZ双核CPU, 4G内存, win7系统, 16个数的全排列,一共4亿7千万次运算,2分钟内完成 
 * 如果更进一步,可以考虑用x86机器做集群运算,每个机器上启动一个JVM, JVM之间用tcp通信协调,一起跑 
 * 有兴趣想深入研究可以联系我 
 *  
 * @author 蒋彪 版权所有 转载请注明出处 
 * @param <E> 
 * @param <T> 
 * @mail nanjingjiangb@hotmail.com 
 * @data 2013/3/4 
 */  
public class CombinationTest<E> {  
  
    // 计算模块的线程执行框架,线程数保持在CPU核数 + 1, 可以最大榨取机器性能  
    // private final static ExecutorService exec = Executors  
    // .newFixedThreadPool(1);  
    private final static ExecutorService exec = Executors.newCachedThreadPool();  
  
    public static void main(String[] args) {  
  
        if (args.length < 1) {  
            return;  
        }  
        // 先将这串数字正排序,预先处理  
        Arrays.sort(args);  
        ArrayList<Integer> min = Util.changeStringsToArray(args);  
  
        Arrays.sort(args, Collections.reverseOrder());  
        ArrayList<Integer> max = Util.changeStringsToArray(args);  
  
        ArrayList diffBlock = getStepData(min, max);  
  
        for (int k = 0; k < diffBlock.size() - 1; k++) {  
            CombinationArg task = new CombinationArgNoRecursion();  
            task.setPn((ArrayList<Integer>) diffBlock.get(k));  
            task.setMax((ArrayList<Integer>) diffBlock.get(k + 1));  
            Future future = exec.submit(task);  
            // future.get();  
        }  
  
        // exec.shutdown();  
    }  
  
    /** 
     * 分割待排序数据,分割成若干个起点的小块计算量 算法待优化,可考虑CPU,内存等限制计算快的大小 
     *  
     * @param pn 
     * @return 
     */  
    public static ArrayList getStepData(ArrayList<Integer> min,  
            ArrayList<Integer> max) {  
  
        ArrayList result = new ArrayList();  
        // 循环把第二位和第一位交换  
        // 比如,原始数据是1,2,3 ,4, 5  
        // 那么可以分割成 12345 ~ 21345 ~ 31245~ 41235~ 51234 几个近似区间来计算  
        result.add((ArrayList) min.clone());  
        for (int j = 1; j < max.size(); j++) {  
            Collections.swap(min, j, 0);  
            result.add((ArrayList) min.clone());  
        }  
        result.add(max);  
        return result;  
    }  
  
}  
  
/** 
 * 全排列组合算法接口 继承自Callable,方便在多线程环境下扩展 
 *  
 * @author 蒋彪 版权所有 转载请注明出处 
 * @param <E> 
 * @param <T> 
 * @mail nanjingjiangb@hotmail.com 
 * @data 2013/3/4 
 */  
inte易做图ce CombinationArg<E, T> extends Callable<T> {  
  
    /** 
     * 输出全排列的方法 在多JVM并行环境考虑打印到分散式文档,或者内存数据库中 
     *  
     * @param pn 
     *            inputData 
     */  
    void printPermutation(ArrayList<E> pn);  
  
    void setMax(ArrayList max);  
  
    /** 
     * 得到全排列的具体算法 有递归和非递归等多种算法实现 
     *  
     * @param pn 
     *       &n
补充:软件开发 , Java ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,