2015-09-27 3 views
37

Ho bisogno di scrivere un metodo ricorsivo usando Java chiamato power che prende un doppio x e un intero n e che restituisce x^n. Ecco cosa ho finora.Metodo ricorsivo per x^n ottimizzato per quando n è pari

public static double power(double x, int n) { 
    if (n == 0) 
     return 1; 
    if (n == 1) 
     return x; 
    else 
     return x * (power(x, n-1)); 

} 

Questo codice funziona come previsto. Tuttavia, sto cercando di fare il miglio supplementare ed eseguire il seguente esercizio opzionale:

"Sfida opzionale: è possibile rendere questo metodo più efficiente, quando n è pari, utilizzando x^n = (x^(n/2))^2."

Non sono sicuro di come implementare quell'ultima formula quando n è pari. Non penso di poter usare la ricorsione per quello. Ho cercato di implementare quanto segue, ma non funziona anche perché non riesco a raddoppiare la potenza di un int.

if (n%2 == 0) 
     return (x^(n/2))^2; 

Qualcuno può indicarmi la giusta direzione? Mi sento come se mi mancasse qualcosa di ovvio. Tutto l'aiuto è apprezzato.

+10

Ti ho votato solo per essere uno studente che ha affrontato un problema da solo e ha mostrato un buon codice. Molto bene. Suggerimento: pensa a come incorporare una chiamata ricorsiva nel tuo caso di potenza pari e lo avrai. – duffymo

+0

Grazie! Molto apprezzato! –

+6

La notazione della domanda ti confonde. In Java, '^' significa un XOR bit a bit. Nella notazione quasi-matematica, 'x^2' significa" x alla seconda potenza ". Sì, hai già una risposta, ma volevo rendere esplicite le notazioni combattive. – msw

risposta

23

È esattamente lo stesso principio di x^n == x * (x^(n-1)): inserisci la tua funzione ricorsiva per x^(n/2) e (...)^2, ma assicurarsi che non si inserisce una ricorsione infinita per n == 2 (come 2 è ancora, troppo):

if (n % 2 == 0 && n > 2) 
    return power(power(x, n/2), 2); 
} 

in alternativa, si potrebbe utilizzare una variabile intermedia:

if (n % 2 == 0) { 
    double s = power(x, n/2); 
    return s * s; 
} 

I' Probabilmente gestisco anche 2 come caso speciale, ed evito le condizioni "e" e la variabile extra:

public static double power(double x, int n) { 
    if (n == 0) return 1; 
    if (n == 1) return x; 
    if (n == 2) return x * x; 
    if (n % 2 == 0) return power(power(x, n/2), 2); 
    return x * (power(x, n - 1)); 
} 

P.S. Penso che questo dovrebbe funzionare, troppo :)

public static double power(double x, int n) { 
    if (n == 0) return 1; 
    if (n == 1) return x; 
    if (n == 2) return x * x; 
    return power(x, n % 2) * power(power(x, n/2), 2); 
} 
+5

Nello spirito di ulteriore ottimizzazione, si può notare che se 'n% 2 == 1' (e quindi l'ultima riga è raggiunta), allora' (n-1)% 2 == 0' e quindi l'ultima espressione può essere ulteriormente "srotolato": 'x * potenza (potenza (x, (n-1)/2), 2)'. –

+2

Si possono anche combinare gli ultimi due casi in "potenza di ritorno (x, n% 2) * potenza (potenza (x, n/2), 2);' :) –

+2

Anche questo :) In realtà, sono curioso di sapere ' power (power (x, n/2), 2) 'anche, dato che la maggior parte delle volte in cui l'ho fatto, ho usato' power (x * x, n/2) '(che evita una chiamata di funzione). –

11

Quando n è ancora, la formula è esattamente quello che hai scritto: dividere n a due, chiamare power modo ricorsivo, e piazza il risultato.

Quando n è dispari, la formula è un po 'più complessa: sottrarre 1 da n, effettuare una chiamata ricorsiva per n/2, quadrato il risultato, e moltiplicare per x.

if (n%2 == 0) 
    return (x^(n/2))^2; 
else 
    return x*(x^(n/2))^2; 

n/2 tronca il risultato, quindi la sottrazione di 1 non è fatto in modo esplicito. Ecco un'implementazione in Java:

public static double power(double x, int n) { 
    if (n == 0) return 1; 
    if (n == 1) return x; 
    double pHalf = power(x, n/2); 
    if (n%2 == 0) { 
     return pHalf*pHalf; 
    } else { 
     return x*pHalf*pHalf; 
    } 
} 

Demo.

+0

sembra corretto, ma quando provo ad implementare quel codice in Java, ottengo un errore "L'operatore^non è definito per il tipo argomento (s) double, int. Forse mi manca qualcosa? –

+0

@OmarN Questo dovrebbe essere semplice implementare ([demo] (http://ideone.com/wxk9MQ)). – dasblinkenlight

+1

Downvoter: ti dispiacerebbe condividere le tue ragioni per votare una risposta perfettamente corretta con una demo pienamente funzionante? – dasblinkenlight

6

Suggerimento: L'operazione ^ non eseguirà l'elevamento a potenza in Java, ma la funzione che ha scritto, power volontà.

Inoltre, non dimenticare che la quadratura di un numero equivale a moltiplicarla da sola. Non è necessaria alcuna chiamata di funzione.

6

Fare una piccola modifica alla funzione, si riduce il numero di chiamate ricorsive fatto:

public static double power(double x, int n) { 
    if (n == 0) { 
     return 1; 
    } 
    if (n == 1) { 
     return x; 
    } 

    if (n % 2 == 0) { 
     double temp = power(x, n/2); 
     return temp * temp; 
    } else { 
     return x * (power(x, n - 1)); 
    } 
} 
5

Dal

x^(2n) = (x^n)^2 

è possibile aggiungere questa regola al metodo, sia usando il potere funzione che hai scritto, come suggerito da Stefan Haustein, o usando l'operatore di moltiplicazione regolare, poiché sembra che tu sia autorizzato a farlo.

Si noti che non è necessario per entrambi i casi di base n = 1 e n = 0, uno di essi è sufficiente (utilizzare preferibilmente il caso base n = 0, altrimenti il ​​metodo non sarebbe definito per n = 0) .

public static double power(double x, int n) { 
    if (n == 0) 
     return 1; 
    else if (n % 2 == 0) 
     double val = power(x, n/2); 
     return val * val; 
    else 
     return x * (power(x, n-1)); 
} 

Non è necessario verificare che n> 2 in nessuno dei casi.

0

Questo mi ricorda che è possibile ottimizzare di più e questo codice seguente.

class Solution: 
# @param x, a float 
# @param n, a integer 
# @return a float 
def pow(self, x, n): 
    if n<0: 
     return 1.0/self.pow(x,-n) 
    elif n==0: 
     return 1.0 
    elif n==1: 
     return x 
    else: 
     m = n & (-n) 
     if(m==n): 
      r1 = self.pow(x,n>>1) 
      return r1*r1 
     else: 
      return self.pow(x,m)*self.pow(x,n-m) 

quello che è più il risultato intermedio potrebbe essere memorizzato ed evitare il calcolo ridondante.

Problemi correlati