Умножение чисел с помощью рекурсии

294
22 июля 2018, 00:10

Стараюсь понять как работает рекурсия. Вот пример как перемножить два числа с помощью цикла:

public int mult(int a, int b){
    int sum=0;
    for (int i=0;i<b;i++){
        sum+=a;
    }
    return sum;
}

Пожалуйста подскажите, как переделать этот цикл с помощью рекурсии ? (используя только сложение)

Answer 1

Решение в лоб достаточно тривиальное, но даже здесь надо учитывать наличие граблей:

private int mult_step(int summand, int steps_count){
    if (steps_count > 0)
        return summand + mult(summand, steps_count - 1);
    else
        return 0;
}
public int mult(int a, int b){
    int summand, steps_count;
    Boolean negate;
    if(a > b){
        summand = a;
        steps_count = Math.abs(b);
        negate = (b < 0);
    } else{
        summand = b;
        steps_count = Math.abs(a);
        negate = (a < 0);
    }
    int sum = mult_step(summand, steps_count);
    return negate ? -sum : sum;
}

То есть сначала мы спускаемся вглубь по цепочке из b элементов, после чего начинаем подниматься обратно, накапливая сумму.

Поясню, о каких граблях шла речь:

  1. Множители могут быть отрицательными. Если это не учесть, то будет бесконечная рекурсия.

  2. При больших b цепочка получится длиннее, чем может вместить в себя стек. Поэтому в качестве длины цепочки надо брать наименьший из множителей.

Answer 2
function int mult(int a, int b){
    int sum = a;
    if(b>1){
        sum += mult(a,b-1);
    }
    return sum;
}

Могу ошибаться. Не знаю зачем вообще нужны эти задачки на рекурсию. Ее нужно по возможности избегать

Answer 3

Можно по аналогии с алгоритмом быстрого возведения в степень:

public static int mul(int a, int b){
    if (b < 0) return -mul(a, -b); // обработка отрицательных значений
    if (b == 1) return a;          // тривиальные условия выхода 
    if ((b & 1) == 1)  return a + mul(a, b-1); // обработка нечётных
    return mul(a, b >> 1) << 1;                // логарифмический спуск на чётных
}

Рабочее демо на js:

function mul(a, b) { 
  if (b < 0) return -mul(a, -b); 
  if (b == 1) return a; 
  if ((b&1) == 1)  return a + mul(a, b-1); 
  return mul(a, b >> 1) << 1; 
  // за счёт деления на 2 мы получаем всего logN итераций 
} 
 
[ 
  [2, 7], 
  [3, 8], 
  [-13, -17], 
].forEach(([a, b]) => console.log( 
  a, b,  
  mul(a, b),  
  mul(a, b) === a*b 
));

Answer 4

Можно еще так:

int mult(int min, int max) {
    if (min == max) {
        return max;
    }
    return mult(++min, max);
}

Но все зависит от того, что за операции нужно делать.

READ ALSO
Проблема с заменой фрагмента

Проблема с заменой фрагмента

Имеется класс WorkoutDetailFragment который наследуется от FragmentПри попытке замены этого фрагмента выводится ошибка

175
Spring Data. Как создать been из интерфейса?

Spring Data. Как создать been из интерфейса?

Хочу научиться использовать Spring Data без Spring Boot

183
Java EE 8. Не работает валидатор

Java EE 8. Не работает валидатор

Не работает валидатор, те

212