E 'possibile applicare il Teorema Master per trovare la radice quadrata e cubica

1

Mi è stato chiesto di calcolare il tempo di esecuzione di un algoritmo che trova la radice quadrata e la radice cubica di un determinato numero.

È possibile applicare il teorema del master a riguardo? Per prima cosa, ho bisogno di costruire la relazione ricorsiva ad esso.

Algoritmo ricorsivo: (per radice quadrata)

La radice cubica è simile anche con la minima modifica

float sqrt_recursion(float n, float low, float high) {
    int mid = (low + high) / 2;
    if (Math.abs(mid*mid-n)<0=0.00001) {
        return mid;
    } else {
        if ((mid * mid) > n)
            return  sqrt_recursion(n, low, mid - 1);
        else
            return  sqrt_recursion(n, mid + 1, high);
    }
}

Algoritmo ricorsivo: (per la radice del cubo)

float cbrt_recursion(float n, float low, float high) {
    int mid = (low + high) / 2;
    if (Math.abs(mid*mid*mid-n)<0=0.00001) {
        return mid;
    } else {
        if ((mid * mid *mid) > n)
            return  cbrt_recursion(n, low, mid - 1);
        else
            return  cbrt_recursion(n, mid + 1, high);
    }
}

Il codice sopra utilizza il metodo Newton-Raphson per calcolare la radice quadrata.

La mia analisi:

Non è stato possibile determinare esattamente in quale ordine viene eseguito il ciclo. Non è esattamente come O (log n), perché il valore medio non si riduce sempre, ma si sposta su e giù.

Accodato a me, non converge per risultare altrettanto accurato della ricerca binaria.

L'analisi sopra è corretta?

Aiutami a trovare il tempo di esecuzione preciso

    
posta Sai Avinash 29.10.2014 - 14:00
fonte

1 risposta

5

Il tuo codice ricorsivo corrente è leggermente errato, perché il tipo di mid è int e non float . Una volta corretto, una versione ricorsiva dell'algoritmo iterativo è:

final static float EPSILON = 0.00001;

static float sqrt(float n) {
    // Here, I use high = n for simplicity's sake.
    // In a real application, I'd special-case n = 0, …, 4
    // and start with high = n/2
    return recursiveSqrt(n, 0, n);
}

static float recursiveSqrt(float n, float low, float high) {
    float mid = (low + high) / 2;
    float midSquare = mid * mid;

    // This is the base case of the recursion
    // which corresponds to a loop condition.
    if (math.abs(midSquare - n) < EPSILON) return mid;

    // Anything that's not the base case recurses.
    // Here, we recurse either into the left or right half
    // of the currently processed interval
    if (midSquare > n) return recursiveSqrt(n, low, mid);
    else               return recursiveSqrt(n, mid, high);
}

Ora, il Teorema principale non è interessato all'implementazione specifica della funzione ricorsiva, ma in tre proprietà:

  1. Qual è il tempo di esecuzione in ogni fase, esclusa la ricorsione?
  2. Quanto spesso ricicliamo per invocazione?
  3. In che modo le dimensioni del problema si riducono a ogni invocazione?

Insieme, definiscono i parametri f (n) , a e b nell'equazione del teorema principale

T(n) = a · T(n/b) + f(n)

che descrive la complessità di alcune funzioni ricorsive. Si noti che la funzione f(n) è anche un'espressione di complessità. Descrive l'overhead di iterazione, che può dipendere dalla dimensione del problema in ogni iterazione.

La risposta alla prima domanda è che ogni invocazione ha un tempo di esecuzione costante (esclusa la ricorsione), poiché gli operatori aritmetici, gli operatori di confronto e Math.abs() richiedono tempo costante. L'unico modo per avere un tempo non costante è usare i loop o invocare una funzione o un metodo che ha un tempo non costante - e non facciamo nulla di tutto ciò. Pertanto, f(n) = O(1) .

Successivamente, dobbiamo determinare la frequenza con cui ci rechiamo. Mentre il codice contiene due invocazioni della funzione ricorsiva, solo una di esse verrà eseguita in qualsiasi iterazione. Quindi a = 1 .

Infine, dobbiamo considerare la dimensione del problema. La dimensione del problema di ogni iterazione è non il nostro parametro n . Invece, è l'intervallo high - low . Ad ogni iterazione, dimezza questo intervallo calcolando il punto medio. Pertanto, b = 2 . Non importa dove sia questo intervallo e se un'iterazione preleva la metà inferiore o superiore. Conta solo la dimensione della gamma. La dimensione iniziale dell'intervallo è n .

Ora abbiamo determinato tutti i parametri necessari per applicare il Teorema Master.

I nostri parametri non corrispondono al primo caso in cui f(n) = O(nc) per alcuni parametri c con c < logb(a) : qui abbiamo c = logb(a) = 0 .

Tuttavia, corrisponde immediatamente al secondo caso in cui f(n) = Θ(nc · logk(a)) con k ≥ 0 e c = logb(a) (Il carattere Θ che assomiglia a uno zero è in realtà la lettera greca maiuscola Theta). Qui, c = k = 0 .

Quindi, la complessità totale è T(n) = Θ(nc · logk + 1(n)) = Θ(log n) .

Interpretazione: questo metodo per approssimare una radice quadrata è essenzialmente una ricerca binaria sulla sequenza ordinata di tutti i numeri tra zero e n . Questa sequenza è discreta e tutti i numeri nella sequenza sono epsilon a parte. Ad ogni iterazione, abbiamo limiti inferiori e superiori che delimitano una sottolista che deve contenere l'elemento della lista ricercata. Poiché la sequenza è ordinata, guardiamo l'elemento nel mezzo della sottodirectory e quindi continuiamo a cercare nella sottolista sinistra o destra, a seconda che l'elemento centrale sia più grande o più piccolo dell'elemento desiderato. Di conseguenza, questo algoritmo deve avere le stesse caratteristiche di complessità temporale di una ricerca binaria.

    
risposta data 29.10.2014 - 16:04
fonte

Leggi altre domande sui tag