10.4. Indices BTree Es un árbol con raı́z donde: Cada nodo x tiene: 1. N [x] número de claves 2. Las claves están ordenadas de menor a mayor k1 [x] < . . . < kn [x] 3. Una variable Boolean hoja[x] que es verdadera cuando el nodo x es una hoja. Si el nodo es interno, tiene n[x] + 1 punteros a hijos ki [x] separa los rangos que se almacenan las hojas están a la misma altura dado un t ≥ 2, nodos excepto la raı́z tiene t − 1 claves como mı́nimo y 2t − 1 claves como máximo. Ejemplo: Dibujo B-TREE del alfabeto con t = 3 P C A B D E F G T M J K L N O Q R S X U V Y Z Dado n ≥ 1, entonces cualquier n-key B-Tree de altura h y mı́nimo grado t2 satisface que h ≤ logt n+1 2 n ≥ 1 + (t − 1) ≥ 1 + (t − 1) ≥ 2th − 1 68 h ! 2ti−1 i=1 th " −1 t−1 # #nodos 1 1 t-1 t-1 t-1 / / / / / ...... t-1 ..... t-1 ..... t-1 t-1 k clave de búsqueda x nodo en el B-tree (inicialmente la raı́z leaf [x] indica si x es hoja n[x] indica numero de claves en el nodo ci [x] entrega puntero a hijo i en el nodo x Procedure BT REE SEARCH(k, x) i:= 1 while i ≤ n[x] and k > keyi [x] do i := i + 1 if i ≤ n[x] and k = keyi [x] then return (x, i) if leaf [x] the return nil else [ DISK READ(ci [x]) return BT REE SEARCH(k, ci [x])] end BT REE SEARCH Procedure BT REE SP LIT CHILD(x, i, y) / y es el i-ésimo hijo de x que es dividido z := Allocate N ode() leaf [z] := leaf [y] n[z] := t − 1 for j = 1 to t − 1 do keyj [z] := keyj+t [y] if not leaf [y] then for j = 1 to t do cj [z] := cj+t [y] n[y] := t − 1 for j = n[x] + 1 downto i + 1 do cj+1 [x] := cj [x] ci+1 [x] := z for j = n[x] downto i do keyj+1 [x] := keyj [x] keyi [x] := keyt [y] n[x] := n[x] + 1 DISK W RIT E(y) DISK W RIT E(z) DISK W RIT E(x) end BT REE SP LIT CHILD 69 2 t-1 t-1 2t Procedure BT REE IN SERT (T, k) r := root(T ) if n[r] = 2t − 1 then [ s := Allocate N ode() root[T ] := s leaf [s] := f alse n[s] := 0 c1 [s] := r BT REE SP LIT CHILD(s, 1, r) BT REE IN SERT N ON F U LL(s, k)] else BT REE IN SERT N ON F U LL(r, k) end BT REE IN SERT Procedure BT REE IN SERT N ON F U LL(x, k) i:= n[x] if leaf [x] then [ while i ≥ 1 and k < keyi [x] do [ keyi+1 [x] := keyi [x] i := i − 1] keyi+1 [x] := k n[x] := n[x] + 1 DISK W RIT E(x) else [ while i ≥ 1 and k < keyi [x] do i := i − 1 i:= i+1 DISK READ(ci [x]) if n[ci [x]] = 2t − 1 then [ BT REE SP LIT CHILD(x, i, ci [x]) if k > keyi [x] then i:= i+1] BT REE IN SERT N ON F U LL(ci [x], k) end BT REE IN SERT N ON F U LL 70 11. Heaps Una estructura heap puede ser vista como un árbol completo donde: A[P AREN T (i)] ≥ A[i] Usando una representación de arreglos de un árbol completo: P AREN T (i) return $i/2% LCHILD(i) return 2i RCHILD(i) return 2i + 1 Procedure BU ILD HEAP (A) heap size := length(A) for i = (length(A)/2 dowto 1 do HEAP IF Y (A, i) end BU ILD HEAP Procedure HEAP IF Y (A, i) l:= Left(i) r:= Right(i) if l ≤ heap size(A) and A[l] > A[i] then largest := l else largest : = i if r ≤ heap size(A) and A[r] > A[largest] then largest := r if largest &= i then [ exchange(A[i], A[largest]) HEAP IF Y (A, largest) ] end HEAP IF Y El costo computacional del algoritmo HEAPIFY de un subárbol de tamaño n y con raı́z i es de Θ(1) para encontrar la relación entre los elementos i, hijo izquierdo de i e hijo derecho de i, más el tiempo de ejecutar el HEAPIFY con un subárbol con la raı́z siendo uno de los hijos de i. Cada subárbol hijo tiene como máximo un tamaño 2n/3, con el peor caso cuando el último nivel está lleno a la mitad. Entonces el sistema recurrente del algoritmo HEAPIFY es: T (n) ≤ T (2n/3) + Θ(1) Con solución T (n) = O(logn) Para la función BUILD HEAP , se puede determinar un peor caso en forma simple. Hay un número de O(n) de llamadas a HEAPIFY con cada una de ellas de O(logn). Entonces, el BUILD HEAP tiene de orden O(nlogn). Un lı́mite más ajustado es por: 71 T (n) ≤ 0 ! k="logn# O(n ' n 2 (O(k) = O(n k+1 1/2 ) = O(n) (1 − 1/2)2 72 0 ! k="logn# k ) 2k 12. 12.1. Otros ı́ndices Tries Este es un arbol donde los nodos son caracteres de un alfabeto y un camino desde la raı́z representa una palabra dentro del vocabulario. Las hojas contienen punteros a la ocurrencias de esas palabras en el base de datos. 12 22 41 50 65 79 Este es un texto. Un texto tiene muchas palabras. Palabras están compuestas de caracteres caracteres:79 a o c compuestas:65 p palabras:41,50 t texto:12,22 Figura 21: Trie de vocabulario Si se tienen n caracteres, entonces el árbol tiene como máximo un camino de orden O(n), es decir, insertar o buscar tendrá complejida de O(n). De acuerdo a la ley de Heaps, el vocabulario en un texto de tamaño n crece en e orden O(nβ ), donde β es un valor entre 0 y 1, dependiendo del texto. 12.2. Árbol de sufijo 79 a o c 65 a p l a b r . x t '' 73 12 o Figura 22: Trie de sufijo 41 '' 50 a t e . 22 79 a o c 65 p t . . 41 '' 50 8 12 6 '' 22 Figura 23: Árbol de sufijo 12.3. Arreglo de sufijo 12 22 41 50 65 79 Este es un texto. Un texto tiene muchas palabras. Palabras están compuestas de caracteres cara pala text 79 65 41 50 12 22 Figura 24: Arreglo de sufijo 13. Introducción General a Grafos Definición: Un grafo G consiste de dos conjuntos V y E. V es un conjunto finito y no vacı́o de vértices. E es un conjunto de arcos, definidos en términos de un par de vértices. En un grafo adireccional, los pares (v1 , v2 ) y (v2 , v1 ) son equivalentes. El orden de un grafo es el número de vértices que tiene. El grado de un vértice es el número de non-loop arcos donde el vértice participa. 74 structureGRAPH declare EM P T Y GRAP H() → graph ADDN ODE(graph, edge) → graph ADDEDGE(graph, edge) → graph N ODEOU T (graph, node) → graph EDGEOU T (graph, node) → graph EDGES(graph) → Set(edge) N ODES(graph) → Set(node) ADJAC(graph, node) → Set(node) for all g ∈ GRAP H, i, j, k, l, v, w ∈ N ode let N ODES(EM P T Y GRAP H()) ::= EM P T Y SET N ODES(ADDN ODE(g, v)) ::= IN SERT (N ODES(g), v) N ODES(ADDEDGE(g, REL(i, j))) ::= IN SERT (IN SERT (N ODES(g), i)j) EDGES(EM P T Y GRAP H()) ::= EM P T Y SET EDGES(ADDN ODE(g, v)) ::= EDGES(g) EDGES(ADDEDGE(g, REL(i, j))) ::= IN SERT (EDGES(g), REL(i, j)) ADJAC(EM P T Y GRAP H(), v) ::= EM P T Y SET ADJAC(ADDN ODE(g, w), v) ::= ADJAC(g, v) ADJAC(ADDEDGE(g, REL(i, j)), v) ::= if v = i then IN SERT (ADJAC(g, v), j) else if v = j then IN SERT (ADJAC(g, v), i) else ADJAC(g, v) N ODEDOU T (EM P T Y GRAP H(), v) ::= EM P T Y GRAP H N ODEOU T (ADDN ODE(g, w), v) ::= if v = w then N ODOU T (g, v) else ADDN ODE(N ODEOU T (g, v), w) N ODEOU T (ADDEDGE(g, REL(i, j)), v) ::= if v = i or v = j then N ODOU T (g, v) else ADDEDGE(N ODEOU T (g, v), REL(i, j)) EDGEDOU T (EM P T Y GRAP H(), REL(i, j)) ::= EM P T Y GRAP H EDGEOU T (ADDN ODE(g, w), REL(i.j)) ::= ADDN ODE(EDGEOU T (g, REL(i, j)), v) EDGEOU T (ADDEDGE(g, REL(k, l)), REL(i, j)) ::= if REL(k, l) = REL(i, j) then g else ADDEDGE(EDGEOU T (g, REL(i, j)), REL(k, l)) Consideramos dos tipos de representaciones de grafos: (1) Matriz de adyacencia, donde se crea una matriz n × n (n el número de vértices). El elemento (i, j) es 1 si existe un arco que une esos vértices, de lo contrario es cero; (2) Listas de adyacencia, donde por cada vértice existe una lista de los vértices. Algoritmos importantes asociados a Grafos los dos tipos de recorridos. Dado un grafo no dirigido G = (V, E) con n vértices, un arreglo A(n) inicialmente en cero y una lista (fila) Q, los algoritmos de recorrido que visita todos los nodos alcanzables desde v con G, Q y A variables globales: 75 Procedure DEP T H F IRST SEARCH(v) A(v) := 1 for each w ∈ V adjacent to v do if A(w) = 0 then call DEP T H F IRST SEARCH(w) end DEP T H F IRST SEARCH(v) Procedure BREADT H F IRST SEARCH(v) A(v) := 1 inicializa Q con vértice v while Q not empty do[ call DELET E(v, Q) for all vértices w adjacent to v do [ if A(w) = 0 then [ call ADD(w, Q) call A(w) := 1]]] end BREADT H F IRST SEARCH(v) 76