Está en la página 1de 16

TDA DICCIONARIO

INTRODUCCIÓN

- Un diccionario (tabla, aplicación, mapping, array asociativo, almacenamiento asociativo) es una colección de pares
clave/valor.

- Se puede puede acceder a un elemento del diccionario, o establecer éste, mediante su clave y el operador de
subíndice:
ASOCIACIONES

- Se establece una asociación entre un valor del dominio (clave) y un valor de la imagen (valor del diccionario). La
estructura de datos necesaria para representar un diccionario deberá ser una colección (por ejemplo, una lista) de
asociaciones.

template <class K, class V>

class association {
friend bool operator == (const association<K, V> & left,
const association<K, V> & right);
/* Necesita: dos asociaciaciones, left y right.
Produce: cierto si las claves de ambas coinciden. */
friend bool operator == (const association<K, V> & left,
const K & rightKey);
/* Necesita: una asociación y una clave.
Produce: cierto si la clave de la asociación
coincide con la clave dada. */

public:
// el campo valor es accesible V valueField;
// constructors
association (const K & initialKey = K(),
const V & initialValue = V());
association (const association<K, V> & source);
// se puede asignar una asociación o un valor
V & operator = (const association<K, V>
& anAssociation);
/* Necesita: una asociación.
Modifica: la asociación receptora cambiando el valor
al de la asociación dada. */
V & operator = (const V & value);
/* Necesita: un valor de tipo V.
Modifica: la asociación receptora cambiando
el valor por el dado. */

// observadores
K key () const;
/* Produce: la clave de la asociación receptora. */
V value () const;
/* Produce: el valor de la asociación receptora. */
protected:
// el campo clave no se puede alterar
const K keyField;
};

template <class K, class V>

association<K, V>::association (const K & initialKey,


const V & initialValue) : keyField(initialKey),
valueField(initialValue)
{
}

template <class K, class V>

V & association<K, V>::operator =


(const association<K, V> & anAssociation)
{
valueField = anAssociation.valueField;
return valueField;
}
CLASE ABSTRACTA PARA DICCIONARIOS

template <class K, class V>

class dictionary {
public:
virtual V & operator [] (const K & key) = 0;
/* Necesita: una clave.
Modifica: el diccionario receptor si la clave no
existe.
Añade al diccionario un nuevo par formado
por la clave dada y un valor por defecto.
Produce: el valor correspondiente a la clave
dada. */
virtual void deleteAllValues () = 0;
/* Modifica: el diccionario receptor haciendo que
sea vacío. */
virtual bool includesKey (const K & key) = 0;
/* Necesita: una clave.
Produce: cierto si la clave se encuentra en el
diccionario. */
virtual bool isEmpty () const = 0;
/* Produce: cierto si el diccionario está vacío. */
virtual void removeKey (const K & key) = 0;
/* Necesita: una clave.
Modifica: el diccionario receptor borrando, si
existe, el par de clave la dada. */
protected:
association<K, V> * associatedWith (const K &) = 0;
/* Necesita: una clave.
Produce: la dirección de la asociación
correspondiente a la clave dada en el
diccionario receptor.
Excepción: si no se encuentra la clave retorna 0.
*/
};

REPRESENTACIÓN DE DICCIONARIOS MEDIANTE LISTAS DE ASOCIACIONES

template <class K, class V>

class dictionaryList : public dictionary<K, V> {


friend class dictionaryListIterator<K, V>;
public:
// constructores
dictionaryList (const V & initial = V());
/* Necesita: un valor de tipo V opcional, initial.
Produce: un diccionario vacío y pone initial como
valor por defecto para nuevas asociaciones. */
dictionaryList (const dictionaryList<K,V> & source);
// protocolo de un diccionario
virtual V & operator [] (const K & key);
/* Coste t.: O(n) */
virtual void deleteAllValues ();
/* Coste t.: O(n) */
virtual bool includesKey (const K & key);
/* Coste t.: O(n) */
virtual bool isEmpty () const;
/* Coste t.: O(1) */
virtual void removeKey (const K & key);
/* Coste t.: O(n) */
// operaciones adicionales
void setInitial (const V & initial);
/* Necesita: un valor de tipo V.
Modifica: el diccionario receptor poniendo
el valor por defecto al valor dado. */
protected:
// área de datos
listLink<association<K,V> *> data;
V initialValue;
// operación interna
association<K, V> * associatedWith (const K &);
/* Coste t.: O(n). */
}

template <class K, class V>

dictionaryList<K, V>::dictionaryList (const V & initial)


: data(), initialValue(initial)
{
}

template <class K, class V>

dictionaryList<K, V>::dictionaryList
(const dictionaryList<K, V> & source)
: data(), initialValue(source.initialValue)
{
listLinkIterator<association<K,V>*> itr(source.data);
for(itr.init();!itr;++itr)
(*this)[itr()->key()]=itr()->valueField;
}

template <class K, class V>

association<K, V> * dictionaryList<K, V>::associatedWith


(const K & key)
{
listLinkIterator<association<K, V> *> itr(data);
// buscar la clave
for (itr.init(); ! itr; ++itr)
if (itr()->key() == key)
return itr();
// no encontrado
return 0;
}

template <class K, class V>

V & dictionaryList<K, V>::operator [] (const K & key)


{
association<K, V> * newassoc = associatedWith(key);
// si no existe crea una nueva
if (! newassoc) {
newassoc = new association<K, V>(key, initialValue);
assert(newassoc != 0);
data.add(newassoc);
}
return newassoc->valueField;
}
template <class K, class V>

void dictionaryList<K, V>::deleteAllValues ()


{
data.deleteAllValues();
}

template <class K, class V>

bool dictionaryList<K, V>::includesKey (const K & key)


{
return associatedWith(key) != 0;
}

template <class K, class V>

bool dictionaryList<K, V>::isEmpty () const


{
return data.isEmpty();
}

template <class K, class V>

void dictionaryList<K, V>::removeKey (const K & key)


{
listLinkIterator<association<K, V> *> itr(data);
for (itr.init(); ! itr; ++itr)
if (itr()->key() == key)
itr.removeCurrent();
}
ITERADOR PARA LA CLASE dictionaryList<K,V>

template <class K, class V>

class dictionaryListIterator : public


listLinkIterator<association<K, V> *> {
public:
// constructores
dictionaryListIterator (dictionaryList<K, V> & dict);
dictionaryListIterator
(const dictionaryListIterator<K, V> & source);
};

template <class K, class V>

dictionaryListIterator<K, V>::dictionaryListIterator
(dictionaryList<K, V> & dict)
: listLinkIterator<association<K, V> *>(dict.data)
{
}

template <class K, class V>

dictionaryListIterator<K, V>::dictionaryListIterator
(const dictionaryListIterator<K, V> & source)
: listLinkIterator<association<K, V> *>(source)
{
}
APLICACIÓN DE DICCIONARIOS

- Una posible aplicación de los diccionarios, es la utilización de éstos para representar matrices esparcidas (matrices
en las que hay un elevado número de términos nulos). Sólo se guardan las componentes que no son nulas, indicando la
posición (fila y columna) que ocupan en la matriz.

- En está representación el acceso a un elemento de la matriz m es el habitual: m[i][j]. Donde i es la clave que
permite obtener la fila i de la matriz (diccionario fila), si existe, y j es la clave que permite obtener, si existe, el elemento de
índice j en el diccionario fila.
CLASE PARA MATRICES ESPARCIDAS

template <class T>

class sparseMatrix {
public:
// constructores
sparseMatrix (const T & initial = T ());
// operación de acceso y modificación
dictionaryList<int, T> & operator []
(const unsigned int & row) const;
// test de existencia de una fila
bool includesKey (const unsigned int & row) const;
// test de existencia de un elemento
bool includesKey (const unsigned int & row,
const unsigned int & column) const;
private:
// área de datos
T initialValue;
dictionaryList<int, dictionaryList<int, T> *> data;
};

template <class T>

sparseMatrix<T>::sparseMatrix (const T & initial)


: data(), initialValue(initial)
{
}
template <class T>

dictionaryList<int, T> & sparseMatrix<T>::operator []


(const unsigned int & row) const
{
if (data.includesKey(row))
return *data[row];
// crear una nueva fila y pone el valor inicial
data[row] = new dictionaryList<int, T>(initialValue);
assert(data[row] != 0);
return *data[row];
}

template <class T>

bool sparseMatrix<T>::includesKey
(const unsigned int & row) const
{
// comprueba si existe la fila indicada
return data.includesKey(row);
}

template <class T>

bool sparseMatrix<T>::includesKey
(const unsigned int & row, const unsigned int & column)
const
{
// si la fila no existe la crea
return data[row]->includesKey(column);
}
SKIP LISTS

- Una skip list es una estructura de datos muy sencilla que permite la implementación de un TDA diccionario con
poco esfuerzo de manera eficiente. Las skip lists consiguen tener rendimiento Q(log n) en promedio en búsquedas y
actualizaciones gracias al uso de aleatorización.

- Una skip list S consiste en un cierto número de listas enlazadas no vacías, ordenadas por las claves de los
elementos que contienen, y numeradas de 1 en adelante, de modo que se satisface:

1. Todos los elementos de X pertenecen a la lista 1.


2. Si x pertenece a la lista i entonces, con probabilidad q, x pertenece también a la lista i+1.

- Cada elemento se almacenará en un nodo, que asimismo contendrá tantos apunt adores como correspondan al
nivel del elemento. Cada uno de dichos apuntadores apunta al sucesor de x en la correspondiente lista. Adicionalmente,
usaremos un nodo ficticio de cabecera con apuntadores a los primeros elementos de cada lista. El nivel de cad a skip list es
el máximo nivel de entre sus elementos y éste será el número de apuntadores en el header.

tipo ptr_nodo = ↑nodo


nodo = tupla
info: elem
suc: tabla[...] de ptr_nodo
ftupla
skiplist = tupla
header: ptr_nodo
nivel: nat
ftupla
Ftipo
Ejemplo de skip list

accion buscar(ent S: skiplist; ent k: clave;


sal v: valor; sal esta: bool)
var p: ptr_nodo; l: nat fiar

p := S.header; l := S.nivel
mientras l > 0 hacer
k’ := clave(p↑.suc[l]↑.info)
@ k’ = ¥ si p↑.suc[l] = nil
si k £ k’ entonces
l := l – 1
sino
p := p↑.suc[l]
fsi
fmientras
@ clave(p↑.info) < k £ clave(p↑.suc[l]↑.info)
si k = clave(p↑.suc[l]↑.info) entonces
v := valor(p↑.suc[l]↑.info)
esta := cierto
sino
esta := falso
fsi
faccion

- Inserción de un nuevo elemento:

Se busca en la skip list la clave k dada. Se anota en un vector de apuntadores los últimos nodos examinados en
cada nivel. Dichos nodos son los potenciales predecesores del nuevo nodo. Basta incluir la instrucción:
pred[l] := p
antes de bajar de nivel (l := l -1).

Si la clave k ya existe, se modifica el valor asociado y se termina.

En caso contrario, se crea un nuevo nodo con la clave y valor dados, utilizando un procedimiento aleatorio para
decidir el nivel del elemento.

r := 1
mientras p < random() hacer
r := r + 1
fmientras
p := nuevo(nodo)
p↑.suc := nuevo(tabla [...] de ptr_nodo, r)
p↑.info := ák, vñ
Se enlaza el nuevo nodo en las r primeras listas:

p↑.suc[i] := pred[i]↑.suc[i]
pred[i]↑.suc[i] := p

También podría gustarte