20. Diccionarios#
Los diccionarios son una estructura de datos que permiten almacenar pares de elementos (clave, valor)
. La clave es un valor único que nos permite identificar al valor asociado. Los diccionarios se pueden implementar sobre distintas estructuras de datos como tablas de hash y árboles, entre otros.
Podemos pensar a los diccionarios como una guía telefónica, donde el nombre de la persona es la clave y el número de teléfono es el valor asociado y podemos buscar rapidamente un número utilizando un índice para no tener que recorrer toda la guía telefónica.
Figura 20.1 Guía telefónica#
Cada implementación tiene sus propias características y ventajas, sin embargo, en general, los diccionarios son estructuras de datos eficientes para la búsqueda y recuperación de valores asociados a una clave.
Otra forma de pensar a los diccionarios es como una generalización de los arreglos, donde en lugar de utilizar índices enteros para acceder a los elementos, utilizamos claves de cualquier tipo.
Los diccionarios tienen muchísimas aplicaciones en la vida cotidiana y en la programación, por ejemplo, en la implementación de bases de datos, en la implementación de sistemas de cache, en la implementación de sistemas de búsqueda, entre otros.
20.1. Conjunto de claves#
Las claves de un diccionario tienen que ser únicas, es decir, no puede haber dos elementos con la misma clave. Si se intenta agregar un elemento con una clave que ya existe, se reemplaza el valor asociado a la clave existente por el nuevo valor, por lo tanto las claves se deben poder comparar para determinar si son iguales o no. Si además se desea que las claves estén ordenadas las claves deben soportar orden total.
20.2. Operaciones#
Los diccionarios deben soportar las siguientes operaciones:
Put
Agrega el par (clave, valor) al diccionario. Si la clave ya existe, se reemplaza el valor asociado a la clave existente por el nuevo valor.
Get
Devuelve el valor asociado a la clave.
Size
Devuelve la cantidad de elementos en el diccionario.
Exist
Determina si una clave existe en el diccionario.
Remove
Elimina el par (clave, valor) del diccionario.
Keys
Devuelve una lista con todas las claves del diccionario.
Values
Devuelve una lista con todos los valores del diccionario.
Cómo se mencionó anteriormente, el orden de las operaciones puede variar dependiendo de la implementación del diccionario.
A continuación el orden esperado en una implementación de diccionario sobre tabla de hash:
Operación |
Orden |
---|---|
|
\(O(1)\) |
|
\(O(1)\) |
|
\(O(1)\) |
|
\(O(1)\) |
|
\(O(1)\) |
|
\(O(n)\) |
|
\(O(n)\) |
20.3. Implementación en Go#
En Go, los diccionarios se pueden implementar usando el tipo de dato map
. Un map
es una colección de pares clave-valor, donde las claves son únicas y los valores pueden ser de cualquier tipo. La sintaxis para declarar un map
es la siguiente:
var m map[TipoClave]TipoValor
Donde TipoClave
es el tipo de dato de la clave y TipoValor
es el tipo de dato del valor. Por ejemplo, para declarar un map
que asocie nombres de personas con sus edades, podemos hacer lo siguiente:
var edades map[string]int
En este caso, la clave es de tipo string
y el valor es de tipo int
. Para inicializar un map
se puede utilizar la función make
:
edades = make(map[string]int)
Para agregar un par clave-valor al map
se puede hacer de la siguiente manera:
edades["Juan"] = 25
Para obtener el valor asociado a una clave se puede hacer de la siguiente manera:
fmt.Println(edades["Juan"])
Para eliminar un par clave-valor se puede hacer de la siguiente manera:
delete(edades, "Juan")
Para verificar si una clave existe en el map
se puede hacer de la siguiente manera:
if _, ok := edades["Juan"]; ok {
fmt.Println("La clave existe")
} else {
fmt.Println("La clave no existe")
}
Para recorrer un map
se puede hacer de la siguiente manera:
for clave, valor := range edades {
fmt.Println(clave, valor)
}
20.4. Ejercicios#
Dada la siguiente definición del tipo de datos
Dictionary
. Implementar un diccionario génerico.// Dictionary implementa un diccionario genérico basado en un map de Go. // Las claves deben ser de un tipo comparable y los valores pueden ser de cualquier tipo. type Dictionary[K comparable, V any] struct { dict map[K]V }
Implementar un diccionario similar al ejercicio anterior pero sobre árboles AVL.
// AVLDictionary implementa un diccionario genérico basado en un árbol AVL. // Las claves deben ser de un tipo comparable y los valores pueden ser de cualquier tipo. type AVLDictionary[K types.Ordered, V any] struct { tree *AVLTree[K, V] }
Analizar y comparar el orden de las operaciones de los diccionarios de los ejercicios anteriores.