实现Horner函数递归?

时间:2019-12-22 15:45:25

标签: java algorithm recursion

对于一个练习,我必须将Horner函数实现为递归方法,该方法是将任何数字系统转换为Decimal(例如101101²的公式),它是((((((((1·2 + 0) ·2)+ 1)·2)+ 1)·2 + 0)·2 + 1 =45₁₀

现在,该方法获得两个参数,一个数字数组和一个数字系统,例如2个代表二进制。

现在,如果我要使用第三个参数作为“计数器”来遍历数组,那么我将没有问题,但是我无法弄清楚。我可以使用辅助方法,但是我尝试了许多不同的方法,但没有一种有效。也许我在想比实际要复杂的多。有人可以给我小费以引导我朝正确的方向吗? ^^

2 个答案:

答案 0 :(得分:0)

我将执行以下操作,其中$ a是包含数字的字符串,$ b是系统

$multiplier = (int)$b;
$result = 0;
while (len($a) > 1) {
  $digit = (int)substr($a, -1);
  $result += $digit * $multiplier;
  $a = substr($a, 0, -1);      
  $multiplier = $multiplier * $b;
}
$result += ((int)$a) * $multiplier;

答案 1 :(得分:0)

我想下面的代码可以满足您的要求:

public class Main {

    /**
     * Hepler method to convert codepoints ('digitCodePoints') into their decimal corresponding
     * number (to be used with {@link #horner(java.lang.String, java.lang.String) horner method})
     * depending on the alphabet ('alphabetCodePoints').
     * @param digitCodePoints the raw digits of the number (most significant digit first).
     * @param alphabetCodePoints the raw alphabet codepoints of the system (least significant codepoint first). For example "01" for binary.
     * @return 
     */
    private static int[] toDigits(final int[] digitCodePoints,
                                  final int[] alphabetCodePoints) {
        final int[] result = new int[digitCodePoints.length];
        for (int d = 0; d < digitCodePoints.length; ++d) {

            //Find where is the digitCodePoints[d] located in alphabetCodePoints:
            int index = 0;
            while (digitCodePoints[d] != alphabetCodePoints[index]) //Will throw ArrayIndexOutOfBoundsException if the digitCodePoints[d] is not found in alphabetCodePoints.
                ++index;

            result[d] = index;
        }
        return result;
    }

    /**
     * Works on codepoints.
     * @param digits the codepoints' literal which stores the digits of the number.
     * @param alphabet the alphabet of the system for which the convertion will take place. For example "01" for binary. Least significant digit comes first.
     * @return the decimal value of the resulting number.
     */
    public static int horner(final String digits,
                             final String alphabet) {
        final int[] alphabetCPs = alphabet.codePoints().toArray();
        return horner(toDigits(digits.codePoints().toArray(), alphabetCPs), alphabetCPs.length);
    }

    public static int horner(final int[] digits,
                             final int system) {
        return horner(digits, 0, digits.length, system);
    }

    /**
     * Standard method for converting 'digits' to their decimal number by Horner's method.
     * @param digits the digits of each place (most significant digit first).
     * @param offset the offset of 'digits' where we should end recursing.
     * @param length the length of 'digits' starting at 'offset'.
     * @param system the system for the convertion. For example 2 for binary, 16 for hexadecimal, and so on.
     * @return the decimal value of the resulting number.
     */
    public static int horner(final int[] digits,
                             final int offset,
                             final int length,
                             final int system) {
        return horner(digits, offset, offset + length - 1, 1, system);
    }

    /**
     * Main recursive method.
     * @param digits the digits of each place (most significant digit first).
     * @param offset the offset of 'digits' where we should end recursing.
     * @param index the index in digits to calculate next.
     * @param step how 'fast' we are traversing the array 'digits'. Typically 1. This exists mainly to create a different method signature than {@link #horner(int[], int, int, int) this} method.
     * @param system the system for the convertion. For example 2 for binary, 16 for hexadecimal, and so on.
     * @return the decimal value of the resulting number.
     */
    private static int horner(final int[] digits,
                              final int offset,
                              final int index,
                              final int step,
                              final int system) {
        if (digits[index] >= system)
            throw new IllegalArgumentException("digits[" + index + "]==" + digits[index] + " does not belong to the system " + system + '.');
        return index - step < offset
               ? digits[index]
               : horner(digits, offset, /* here you can see the usage of 'step': */ index - step, step, system) * system + digits[index];
    }

    public static void main(final String[] args) {
        System.out.println(horner(   new int[]{1, 0, 1, 1}   ,    2   )); //11.
        System.out.println(horner(   new int[]{0xF, 0xF}     ,    16  )); //255.
        System.out.println(horner( /* the number: */ "ffff" , /* the alphabet: */ "0123456789abcdef" )); //65535.
    }
}

如果您在了解step参数的功能时遇到麻烦,请考虑使其始终等于1!这就是遍历数组的 fast 的方式。例如,值2表示仅考虑半个数字。它可能会使事情复杂一些,但是我创建它的目的是使主要递归方法的方法签名与其他方法不同。通过将step替换为1,您只能使用最后一个 horner 方法。

无论如何,我为每种方法都嵌入了一些javadoc(注释),以帮助您了解我在做什么。主要实现是最后一个 horner 方法。