使用查找表在Java中编程因子

时间:2014-06-24 04:52:50

标签: java caching hashmap factorial

为了改进我的编程,我在Java中尝试这个问题。我到处寻找一个优雅的解决方案,无法找到它。

  

编写一个带有单个参数的程序,计算阶乘并打印出   屏幕上的值。此外,程序必须是交互式的,而不是终止后的   每次计算,并使用先前值表来提高性能。

如何使它在方法调用中检查它是否已经计算了值的阶乘?此代码的任何其他改进,以使其更具可读性或效率,也是值得赞赏的。

这是我到目前为止所写的内容。

public static void main(String[] args) {
    int input = 0;
    Scanner reader = new Scanner(System.in);

    HashMap cache = new HashMap();

    while(1 == 1){
        do{
            try {
                System.out.println("Enter the number you would like to factor");
                input = reader.nextInt();
            } catch (InputMismatchException e){
                reader.next();
            }
        } while(input <= 0);

        if(cache.get(input) != null){
            System.out.println("Found in cache");
            System.out.println(input + "! = " + cache.get(input));
        } 
        else {
            cache.put(input, factorialRecursively(input));
            System.out.println(input + "! = " + factorialRecursively(input));
        }

    }   

}       

public static int factorialIteratively(int a) throws InputMismatchException {
    int temp = 1;
    while(a > 0){
        temp = temp * a;
        a--;
    }
    return temp;
}

public static int factorialRecursively(int a) throws InputMismatchException{
    if (a == 1){
        return 1;
    }
    else {
        return a * factorialRecursively(a-1);
    }
}

1 个答案:

答案 0 :(得分:2)

好的,我会试一试。让我先给你完整的代码答案,并详细介绍每个变化:

public static void main(String[] args) {
    int input = 0;

    try (Scanner reader = new Scanner(System.in)) {

        Map<Integer, Integer> cache = new HashMap<Integer, Integer>();
        cache.put(1, 1);

        while (true) {
            do {
                try {
                    System.out.println("Enter the number you would like to factor");
                    input = reader.nextInt();
                } catch (InputMismatchException e){
                    reader.next();
                    input = 0;
                }
            } while(input <= 0);

            if(cache.get(input) != null) {
                System.out.println("Found in cache");
                System.out.println(input + "! = " + cache.get(input));
            } 
            else {
                int result = factorialRecursively(input, cache);
                System.out.println(input + "! = " + result);
            }
        }   
    }
}       

public static int factorialRecursively(int limit, Map<Integer, Integer> cache) {

    int cacheSize = cache.size();
    if (cacheSize < limit) {
        int nextFactorial = cacheSize + 1; 
        System.out.println("Calculating and caching " + nextFactorial + "!");
        cache.put(nextFactorial, cache.get(cacheSize) * nextFactorial); 
        return factorialRecursively(limit, cache);
    }
    else {
        return cache.get(limit);
    }
}

1)直接回答你的问题:“如何确定计算阶乘的方法,检查它是否已计算出一个值的阶乘”。所以我坚持使用递归方法,尽管你也可以使用相同的概念实现迭代版本 基本上,我们的想法是将结果缓存的引用传递给方法本身(Map<Integer, Integer> cache参数),因此它负责在每个乘法步骤中存储得到的计算因子,而不仅仅是一个全因子具有已被计算。为此,我让方法从下到上计算阶乘,而不是相反。我们将最小的factorial存储在缓存中作为起点(cache.put(1, 1);)。我添加了一条输出消息,显示计算和缓存阶乘的时间,并通过测试代码,您可以看到一个特定的阶乘仅被计算并存储一次。

2)使用Map<Integer, Integer> cache = new HashMap<Integer, Integer>();代替HashMap cache = new HashMap(); a)从Java 1.5开始,集合已经变成通用的(长篇故事,在此范围之外),并且在引用时应该参数化。所以我们在这里说,我想存储整数值(计算因子),我可以使用整数键(因子源)访问。 b)代码编译并允许我们使用整数原语而不是Integer类对象的原因是因为一种名为auto-boxing的机制将整数原语无缝地包装到Integer对象中,反之亦然。同样,超出范围,但应该注意它 c)我们之后的功能是Map接口的功能,HashMap恰好是其实现。除非引用代码依赖于HashMap特定方法(不太可能),否则最好将变量声明为相应的集合接口(如ListArrayList),而不是实施班。

3)InputMismatchException仅由Scanner类抛出,因此不需要被任何不调用Scanner nextInt()方法的代码抛出。

4)使用true代替1 == 1。在实践中等效,但使用布尔值更具可读性。

5)只调用factorialRecursively方法一次。您的代码调用该方法两次,这是不必要的。如果你追求效率和优雅,你应该只调用一次方法并将结果存储在一个变量中。

6)使用try (Scanner reader = new Scanner(System.in)) { ...代替Scanner reader = new Scanner(System.in);Scanner对象必须始终调用其close()方法来清理资源。在较旧的Java版本中,这是使用try {} finally {}语句实现的,但是如果类实现了AutoCloseable接口,则更高版本允许使用此语法(try-with-resources语句)。这意味着始终可以保证调用close()方法。

7)最后但并非最不重要:intInteger的使用,我没有改变。正如@indivisible的评论中所建议的那样,您应该了解data type limitationsint只能保存由31位+符号(-2 ^ 31 -1到2 ^ 31)表示的数字,这会将此代码限制为16 !,之后结果将变为错误。如果您希望生成更大的数字,请使用long / Long。无论如何,真的再次超出了这个问题的范围。

玩得开心:)