Saltar a Contenido

Permitiendo contracciones ​

Supongamos ahora una situación más compleja en la que también se pueden eliminar elementos en el arreglo. Un elemento eliminado se reemplaza por el que está en último lugar, de modo que el arreglo se almacene en forma compacta. Queremos evitar el estar almacenando demasiada memoria para un arreglo que alguna vez fue grande pero ahora tiene pocos elementos. Para ello, podemos contraer el arreglo cuando queda muy vacío después de un borrado. Esta es la acción contraria a la expansión que se realiza durante la inserción, y supondremos que también cuesta nn escrituras.

El primer impulso puede ser que, una vez que el arreglo tenga tamaño s>αns > \alpha n, lo contraigamos a tamaño sα\frac{s}{\alpha}. Sin embargo, si volvemos a insertar inmediatamente, el arreglo se volverá a expandir. Por ello, el costo de esta alternativa puede ser muy alto: cada operación costará Θ(n)\Theta(n) escrituras si se elimina un elemento inmediatamente después de expandir, lo que provoca una contracción, luego se vuelve a insertar, lo que provoca otra expansión, luego se vuelve a eliminar, lo que provoca otra contracción, etc.

Peor Caso Contraccion

Para seguir teniendo costo amortizado constante, establecemos que el arreglo se contraerá solamente cuando s≥βns \ge \beta n, para cierto β>α\beta > \alpha, y entonces se contraerá a tamaño γn\gamma n, para un 1<γ<β1<\gamma<\beta. Esto garantiza que la memoria máxima a ser usada es βn\beta n. Nos preguntamos ahora cuál es el costo amortizado de una operación.

Esta vez no funciona una función de tipo ϕ=an−bs\phi = an-bs. Debemos elegir un esquema algo más complejo: ϕ=∣an−bs∣\phi = |an-bs|. Tenemos ahora las siguientes operaciones:

  • Inserción elemental, a costo ci=1c_i=1. El valor de Δϕi\Delta\phi_i es a lo sumo aa, por lo que una cota superior al costo amortizado es ci^≤1+a\hat{c_i} \le 1+a.
  • Borrado elemental (es decir, sin considerar la contracción), a costo ci=1c_i=1. El valor de Δϕi\Delta\phi_i es también a lo sumo aa, por lo que tenemos la misma cota superior ci^≤1+a\hat{c_i} \le 1+a.
  • Expansión, a costo ci=nc_i=n. Esta ocurre cuando n=sn=s, y pasaremos de ϕi−1=∣an−bs∣=∣an−bn∣\phi_{i-1} = |an-bs|=|an-bn| a ϕi=∣an−bsα∣=∣an−bnα∣\phi_i = |an-bs\alpha|=|an-bn\alpha|. Para que nuestro esquema funcione, la expansión debe darse cuando an−bnα≥0an-bn\alpha \ge 0, es decir, que debe valer a≥bαa \ge b\alpha. En este caso, tenemos Δϕi=−b(α−1)n\Delta\phi_i = -b(\alpha-1)n, y tendremos ci^≤0\hat{c_i} \le 0 siempre que b≥1α−1b \ge \frac{1}{\alpha-1}.
  • Contracción, a costo ci=nc_i=n. Esta ocurre cuando s≥βns \ge \beta n, y pasaremos de ϕi−1=∣an−bs∣\phi_{i-1} = |an-bs| a ϕi=∣an−bγn∣\phi_i = |an-b\gamma n|. Para que nuestro esquema funcione, la contracción debe darse cuando an−bγn≤0an-b\gamma n \le 0, es decir, que debe valer a≤bγa \le b\gamma. En este caso, tenemos ϕi−1=bs−an≥bβn−an\phi_{i-1}=bs-an \ge b\beta n-an y ϕi=bγn−an\phi_i=b\gamma n-an, y entonces Δϕi≤−b(β−γ)n\Delta\phi_i \le -b(\beta-\gamma)n. Por lo tanto, tendremos ci^≤0\hat{c_i} \le 0 siempre que b≥1β−γb \ge \frac{1}{\beta-\gamma}.

Tenemos entonces las condiciones bα≤a≤bγb\alpha \le a \le b\gamma, b≥1α−1b \ge \frac{1}{\alpha-1} y b≥1β−γb \ge \frac{1}{\beta-\gamma}. Dado un β\beta fijo (relacionado con la memoria máxima que permitimos desperdiciar), queremos minimizar aa (pues el costo amortizado es 1+a1+a). El menor aa posible es a=bαa = b \alpha. Usar el menor bb posible implica usar el menor γ\gamma posible, pues b≥1β−γb \ge \frac{1}{\beta-\gamma}. Como nuestras desigualdades implican γ≥α\gamma \ge \alpha, elegimos γ=α\gamma = \alpha. Las nuevas cotas inferiores son b≥1α−1b \ge \frac{1}{\alpha-1} y b≥1β−αb \ge \frac{1}{\beta-\alpha}, que decrecen y crecen, respectivamente, con α\alpha. Por lo tanto, el óptimo se da cuando 1α−1=1β−α\frac{1}{\alpha-1} = \frac{1}{\beta-\alpha}, es decir, α=β+12\alpha=\frac{\beta+1}{2}. El costo amortizado es entonces 1+a=1+bα=1+αα−1=2α−1α−1=2ββ−11+a= 1+b\alpha = 1+\frac{\alpha}{\alpha-1}=\frac{2\alpha-1}{\alpha-1} = \frac{2\beta}{\beta-1}.

Concluyendo, podemos garantizar un uso máximo de βn\beta n celdas para almacenar nn elementos, permitiendo inserciones y borrados, a un costo amortizado de 2ββ−1\frac{2\beta}{\beta-1} por operación. Para lograrlo, cuando insertamos y s=ns=n, expandimos el arreglo a s=β+12ns=\frac{\beta+1}{2} n, y cuando borramos y s≥βns\ge\beta n, contraemos el arreglo a s=β+12ns=\frac{\beta+1}{2} n. Por ejemplo, podemos elegir β=3\beta=3 para obtener un costo amortizado de 2⋅33−1=3\frac{2\cdot 3}{3-1} = 3. Notar también que el costo amortizado tiende a 22 para β\beta creciente.

Contraccion

generating algorithms by Puspito from the Noun Project. © 2026 Me. Built with VitePress.