Previous Contents Next

Apéndice B   Búsquedas dentro de un rango

Un problema clásico en geometría computacional es la búsqueda dentro de un rango. El problema se puede definir de la siguiente manera:
Tenemos un conjunto de puntos en el espacio n-dimensional. Se trata de encontrar de forma eficiente el conjunto de puntos cuyas coordenadas se encuentran situadas dentro de un rango. En el caso de dos dimensiones el rango especificado podría ser [x1:x2]×[y1:y2], indicando que las coordenadas de los puntos que se devuelven tienen que estar comprendidas entre dichos intervalos.

Se pueden encontrar varias propuestas en la literatura de tipos de datos para realizar estas búsquedas. En [de Berg et al.1997] se presentan algunas de las estructuras de datos más eficientes para realizar estas consultas, de las cuales se ha seleccionado la que presenta una menor complejidad en el tiempo de consulta. La estructura seleccionada es el árbol de rango (Range Tree) que es una ampliación del clásico árbol binario en una dimensión. En la siguiente sección se comenta la estructura del árbol binario y la forma de interrogar a dicho árbol, analizándose la complejidad de dicha estructura. En la Sección B.2 se detalla cómo se puede crear la estructura de árbol de rango y cómo se realiza la consulta de rango a dicha estructura.

B.1   Búsqueda unidimensional

Una búsqueda en una única dimensión es trivial: ordenamos todos los valores en un vector y simplemente realizamos una búsqueda lineal viendo qué valores se encuentran entre el rango especificado. Sin embargo aquí vamos a introducir una estructura de datos llamada árbol binario y que sirve de base para ampliar a mayores dimensiones. Cada nodo de este árbol tendrá la siguiente información: Un valor V, un puntero a un subárbol izquierda L y otro a un subárbol derecha R. Dado un conjunto de valores ordenados de menor a mayor, la creación del árbol binario se puede definir de forma recursiva tal como se muestra en la Figura B.1.

Algoritmo de creación de un árbol binario Alg_CAB
Entrada: Lista de valores ordenados L.
Salida: Nodo raíz del árbol creado T.
Si Longitud(L)=1 entonces /*Un único elemento*/
  Crear un nuevo nodo N con V=Obtener_Elemento(L) y los punteros de los subárboles apuntando a un árbol vacío.
sino
 Obtener el nodo cuyo valor es el central de la lista de valores (la mediana): vmed
  Particionar la lista L en dos sublistas L1 y L2 de tal forma que L1 contiene todos los elementos menores o iguales a vmed y L2 los estrictamente mayores.
  Crear un nuevo nodo N con V=vmed. El puntero izquierdo L apuntará al árbol devuelto en la llamada a la función Alg_CAB(L1) y el derecho R ídem Alg_CAB(L2).
FinSi
Devolver N.

Figure B.1: Algoritmo de creación de un árbol binario.

Si tenemos los siguientes valores: 3, 5, 10, 15, 16, 20, 22, 23, 30, el resultado de la creación de este árbol se puede observar en la Figura B.2. Los valores almacenados en los nodos internos permiten guiar la búsqueda hacia los valores en las hojas. Todos los valores en el subárbol izquierdo de un determinado nodo contienen valores menores o iguales que el valor almacenado en dicho nodo, mientras que en el subárbol derecho estos valores son mayores.


Figure B.2: Árbol binario creado indicando el nodo de partición.

El método de consulta parte de un determinado rango a buscar [x1:x2] y devuelve los puntos del árbol que se encuentran dentro de ese rango. El método se divide en dos fases: primero encontrar el nodo de partición para, a continuación, ir explorando a partir de este nodo e ir devolviendo los valores dentro del rango. Este nodo de partición (vpart) es aquel nodo del árbol cuyo valor es mayor que x1 y menor que x2, es decir se encuentra dentro del rango a buscar, y que además tiene menor profundidad (más próximo a la raíz). En la Figura B.2 se muestra el nodo de partición para un rango de búsqueda de [4:15]. La Figura B.3 muestra el resultado de buscar un determinado rango en el árbol binario. Primero encontramos el nodo de partición. Después buscamos por el hijo izquierdo, quedándonos con los subárboles derechos que se encuentren dentro del rango, mientras que cuando buscamos por el hijo derecho nos quedamos con los subárboles izquierdos. En la Figura B.5 se detalla el método de consulta de rango.


Figure B.3: Obtención de los puntos dentro de un rango.

La función Devolver_Subárbol() devuelve una lista con todos los puntos que pertenecen al árbol pasado como parámetro a la función.

La creación de este árbol se puede realizar con una complejidad temporal de °(nlog n) y una espacial de °(n). En cuanto a la complejidad de la consulta, siendo k el número de puntos devueltos se tiene una complejidad temporal de °(k+log n).

B.2   Árboles de rango

Este tipo de árbol permite obtener, de manera eficiente, los puntos dentro de un espacio bidimensional cuyas coordenadas se encuentran dentro de un determinado rango. Si P es el conjunto de puntos totales, una consulta de rango ([x1:x2]×[y1:y2]) en dos dimensiones sobre P devolverá todos aquellos puntos que estén situados dentro del rectángulo definido por el rango de consulta. Un punto p=(px,py) está situado dentro de dicho rectángulo si se cumple que:
px Î [x1:x2]    y    py Î [y1:y2]

Una consulta de este tipo se puede dividir en dos subconsultas, una para las coordenadas x y otra para las y. El árbol de rango es un árbol binario en el cual se han utilizado las coordenadas x de los puntos para su construcción. La consulta principal se realiza sobre estas coordenadas. Asociado a cada nodo de este árbol principal tenemos un árbol binario como el descrito en la anterior sección pero construido a partir de las coordenadas y de los puntos hijos de este nodo. La construcción de esta estructura es idéntica a la del árbol binario, excepto que el primer paso del algoritmo debe ser construir un árbol binario, asociado al nodo en cuestión, con las coordenadas y de los puntos (ver Figura B.4).


Figure B.4: Árbol de rango con el árbol binario asociado.

En cuanto a la consulta, el algoritmo también es muy similar al descrito para consulta en árboles binarios. Se realiza una consulta sobre las coordenadas x del árbol, y cuando se llamaba a la función Devolver_Subárbol ahora se debe realizar una consulta al árbol asociado con el rango de las y.

Si tenemos un conjunto P de n puntos, la creación de un árbol de rango se puede realizar con una complejidad temporal de °(nlog n) y una espacial de °(nlog n). En cuanto a la complejidad de la consulta, siendo k el número de puntos devueltos se tiene una complejidad temporal de °(k+log2 n).


Algoritmo de consulta en un árbol binario Alg_CoAB
Entrada: Un árbol T y un rango de búsqueda [x1:x2]
Salida: Lista de puntos del árbol que se encuentran dentro del rango.
Crear una lista vacía Lista
vpart=raíz( T)
xpart=valor(vpart)
mientras vpart no es hoja y (x2 £ xpart o x1 > xpart) hacer
  Si x2 £ xpart entonces
    vpart=Hijo_izquierdo(vpart)
  sino
    vpart=Hijo_derecho(vpart)
  FinSi
  xpart=valor(vpart)
FinMientras  

Si vpart es hoja entonces
  Si (xpart ³ x1 y xpart £ x2) entonces Insertar xpart en Lista FinSi
sino
  /* Primero se sigue el camino de la izquierda */
  v=vpart
  v=Hijo_izquierdo(v)
  mientras v no es hoja hacer
    xv=valor(v)
    Si x1 £ xv entonces
     Concatenar (Lista, Devolver_Subárbol(Hijo_derecho(v)))
     v=Hijo_izquierdo(v)
    sino
     v=Hijo_derecho(v)
    FinSi
  FinMientras
  /* El nodo hoja también debe de ser chequeado */
  Si (xv ³ x1 y xv £ x2) entonces Insertar xv en Lista FinSi
  /* Ahora se continúa por la derecha */
  v=vpart
  v=Hijo_derecho(v)
  mientras v no es hoja hacer
    xv=valor(v)
    Si x2 ³ xv entonces
     Concatenar (Lista, Devolver_Subárbol(Hijo_izquierdo(v)))
     v=Hijo_derecho(v)
    sino
     v=Hijo_izquierdo(v)
   FinSi
  FinMientras
  /* El nodo hoja también debe de ser chequeado */
  Si (xv ³ x1 y xv £ x2) entonces Insertar xv en Lista FinSi
FinSi
Devolver Lista

Figure B.5: Algoritmo de consulta de un árbol binario.


Previous Contents Next