Skip to Content
Algoritmos y Estructuras de Datos 2Recurrencias y Jerarquía de Funciones

Recurrencias y Jerarquía de Funciones

Algoritmo divide y vencerás

Divide y vencerás es un paradigma de diseño de algoritmos que consiste en resolver un problema dividiéndolo en subproblemas más pequeños, resolviendo los subproblemas y combinando sus soluciones para resolver el problema original.

El esquema de este algoritmo es el siguiente:

fun  DyV(x)  ret  yif  x  suficientemente simple  then  y:=ad_hoc(x)else  descomponer  x  en  x1,x2,,xafor  i:=1  to  a  do  yi:=DyV(xi)  od{    combinar  y1,y2,,ya  para obtener la solucioˊn  y  de  x    }fiend  fun\begin{aligned} &\fun \; DyV(x) \; \ret \; y \\ &\quad \if \; x \; \textnormal{suficientemente simple} \; \then \; y:=ad\_hoc(x) \\ &\quad \else \; \textnormal{descomponer} \; x \; \textnormal{en} \; x_1,x_2,\ldots,x_a \\ &\quad \quad \for \; i:=1 \; \too \; a \; \do \; y_i:=DyV(x_i) \; \od \\ &\quad \quad \{- \;\; \textnormal{combinar} \; y_1,y_2,\ldots,y_a \; \textnormal{para obtener la solución} \; y \; \textnormal{de} \; x \;\; -\} \\ &\quad \fi \\ &\bfend \; \fun \end{aligned}

Los xix_i son subproblemas de xx, podemos considerarlos fracciones de xx:

xi=xb|x_i| = \frac{x}{b}

Si tomamos por ejemplo el algoritmo Merge Sort:

  • xx simple” == fragmento de arreglo de tamaño 010 \lor 1
  • “descomponer” == dividir en dos mitades (b=2)(b=2)
  • a=2a = 2
  • “combinar” == intercalar

Recurrencias divide y vencerás

Para calcular el costo computacional de DyVDyV definimos una función recursiva r(n)r(n) de la siguiente forma:

t(n)={c,  n1at(n/b)+g(n),  n>1\begin{aligned} t(n) &= \begin{cases} c & ,\; n \leq 1 \\ a * t(n / b) + g(n) & ,\; n > 1 \end{cases} \end{aligned}

Donde cc es una constante que representa el costo computacional de la función ad_hocad\_hoc y g(n)g(n) es el costo computacional de procesos de descomposición/combinación.

Podemos determinar el orden de t(n)t(n) de la siguiente forma:

t(n)={nlogba,  a>bknk  log  n,  a=bknk,  a<bk\begin{aligned} t(n) &= \begin{cases} n^{\log_b a} & ,\; a > b^k \\ n^k \; \log \; n & ,\; a = b^k \\ n^k & ,\; a < b^k \end{cases} \end{aligned}

Ejemplo:

proc  f1(in  n:nat)if  n1  then  skipelsefor  i:=1  to  8  do  f1(n  div  2)  odfor  i:=1  to  n3  do  t:=1  odfiend  proc\begin{aligned} &\proc \; f_1 (\bfin \; n : \nat) \\ &\quad \if \; n \leq 1 \; \then \; \skip \\ &\quad \else \\ &\quad \quad \for \; i:=1 \; \too \; 8 \; \do \; f_1(n \; \textnormal{div} \; 2) \; \od \\ &\quad \quad \for \; i:=1 \; \too \; n^3 \; \do \; t:=1 \; \od \\ &\quad \fi \\ &\bfend \; \proc \end{aligned}

Siguiendo el anterior esquema, obtenemos:

r(n)={0,  n1i=18  r(n/2)+i=1n3  1,  n>1\begin{aligned} r(n) &= \begin{cases} 0 & ,\; n \leq 1 \\ \displaystyle{\sum^8_{i=1} \; r(n/2)} + \displaystyle{\sum^{n^3}_{i=1} \; 1} & ,\; n > 1 \\ \end{cases} \end{aligned}

El primer término de la sucesión corresponde a la cantidad de veces que se llama a la función f1f_1 y el segundo término corresponde a la cantidad de veces que se ejecuta la instrucción t:=1t:=1.

r(n)={0,  n18r(n/2)+n3,  n>1\begin{aligned} r(n) &= \begin{cases} 0 & ,\; n \leq 1 \\ 8 * r(n/2) + n^3 & ,\; n > 1 \\ \end{cases} \end{aligned}

Planteada la recurrencia tenemos que:

  • a=8a = 8
  • b=2b = 2
  • g(n)=n3    k=3g(n) = n^3 \implies k = 3
  • 8>23    8 > 2^3 \implies el orden de r(n)r(n) es n3  log  nn^3 \; \log \; n

Algoritmo de búsqueda binaria

La búsqueda binaria es un algoritmo para encontrar un elemento en una lista ordenada. Dividiendo repetidamente la lista en mitades y comparando el elemento buscado con el elemento del medio.

{1lftn+1  0rgtn    a  estaˊ ordenado}fun  binary_search_rec(a:array[1..n]  of  T,  x:T,  lft,rgt:nat)  ret  i:natvar  mid:natif  lft>rgt    i:=0lftrgtmid:=(lft+rgt)  div  2if  x<a[mid]i:=binary_search_rec(a,x,lft,mid1)x=a[mid]i:=midx>a[mid]i:=binary_search_rec(a,x,mid+1,rgt)fifiend  fun{i=0    x  no estaˊ en  a[lft,rgt]    (ichar"338=0    x=a[i])}{n0}fun  binary_search(a:array[1..n]  of  T,  x:T)  ret  i:nati:=binary_search_rec(a,x,1,n)end  fun{i=0    x  no estaˊ en  a    (ichar"338=0    x=a[i])}\begin{aligned} &\\ &\{ 1 \leq lft \leq n+1 \; \land 0 \leq rgt \leq n \; \land \; a \; \textnormal{está ordenado} \} \\ &\fun \; binary\_search\_rec(a: \array[1..n] \; \of \; T , \; x: T, \; lft, rgt: \nat) \; \ret \; i : \nat \\ &\quad \var \; mid: \nat \\ &\quad \if \; lft > rgt \; \to \; i := 0 \\ &\quad \quad lft \leq rgt \to mid := (lft + rgt) \; \textnormal{div} \; 2 \\ &\quad \quad \quad \if \; x < a[mid] \to i := binary\_search\_rec(a, x, lft, mid - 1) \\ &\quad \quad \quad \quad x = a[mid] \to i := mid \\ &\quad \quad \quad \quad x > a[mid] \to i := binary\_search\_rec(a, x, mid + 1, rgt) \\ &\quad \quad \quad \fi \\ &\quad \fi \\ &\bfend \; \fun \\ &\{ i = 0 \implies x \; \textnormal{no está en} \; a[lft,rgt] \; \land \; (i \not=0 \implies x = a[i]) \} \\ &\\ &\\ &\{ n \geq 0 \} \\ &\fun \; binary\_search(a: \array[1..n] \; \of \; T , \; x: T) \; \ret \; i : \nat \\ &\quad i := binary\_search\_rec(a, x, 1, n) \\ &\bfend \; \fun \\ &\{ i = 0 \implies x \; \textnormal{no está en} \; a \; \land \; (i \not=0 \implies x = a[i]) \} \end{aligned}

Jerarquía de funciones

Es posible ordenar las funciones de acuerdo a su crecimiento. Se denota f(n)g(n)f(n) \sqsubset g(n) si gg crece más rápido que ff, y f(n)g(n)f(n) \simeq g(n) si crecen al mismo ritmo.

Podemos establecer la siguiente jerarquía de funciones:

1log(log(log(n)))log(log  n)log(n)n0.001nnlog  nn1.001n1001.01nn1001.01n1.02n100n10000n(n1)!n!nn\begin{aligned} &1 \sqsubset \log(\log(\log(n))) \sqsubset \log(\log \; n) \sqsubset \log(n) \sqsubset n^{0.001} \sqsubset n \\ &\sqsubset n \log \; n \sqsubset n^{1.001} \sqsubset n^{100} \sqsubset 1.01^{n} \sqsubset n^{100} * 1.01^n \\ &\sqsubset 1.02^n \sqsubset 100^n \sqsubset 10000^n \sqsubset (n-1)! \sqsubset n! \sqsubset n^n \end{aligned}

Propiedades:

  • No afectan las constantes multiplicativas
  • Sea a,b>1    loga  nlogb  na, b > 1 \implies \log_a \; n \simeq \log_b \; n
  • Sea f(n)>0f(n) > 0 para casi todo nNn \in \NN:
g(n)h(n)    f(n)g(n)f(n)h(n)g(n)h(n)    f(n)g(n)f(n)h(n)\begin{aligned} &g(n) \sqsubset h(n) \iff f(n)g(n) \sqsubset f(n)h(n) \\ &g(n) \simeq h(n) \iff f(n)g(n) \simeq f(n)h(n) \end{aligned}
  • Sea limnh(n)=\displaystyle{\lim_{n \to \infty}} h(n) = \infty:
f(n)g(n)    f(h(n))g(h(n))f(n)g(n)    f(h(n))g(h(n))\begin{aligned} &f(n) \sqsubset g(n) \iff f(h(n)) \sqsubset g(h(n)) \\ &f(n) \simeq g(n) \iff f(h(n)) \simeq g(h(n)) \end{aligned}
  • Sean limn+f(n)==limn+g(n)\displaystyle{\lim_{n \to +\infty}} f(n) = \infty = \displaystyle{\lim_{n \to +\infty}} g(n) y limn+f(n)g(n)\displaystyle{\lim_{n \to +\infty}} \frac{f(n)}{g(n)} existente:
limnf(n)g(n)=0    f(n)g(n)limnf(n)g(n)=    g(n)f(n)caso contrario    f(n)g(n)\begin{aligned} &\displaystyle{\lim_{n \to \infty}} \frac{f(n)}{g(n)} = 0 \implies f(n) \sqsubset g(n) \\ &\displaystyle{\lim_{n \to \infty}}\frac{f(n)}{g(n)} = \infty \implies g(n) \sqsubset f(n) \\ &\textnormal{caso contrario} \implies f(n) \simeq g(n) \end{aligned}
Última vez actualizado el