Aula 03 - Dicionários
Quando começamos a chegar no fim de DevLife usamos cada vez mais Dicionários em nosso código. Os usamos para representar coleções de pares chave->valor em que para cada chave existe exatamente um valor. Como era possível compor dicionários dentro de dicionários dentro de dicionários (e por aí vai) conseguíamos usá-los para representar hierarquias complexas. O tipo Map representa de maneira abstrata esse tipo de estrutura de dados.
O tipo Map
Um Map é uma mapeamento chave $\rightarrow$ valor em que cada chave pode estar a associada a um único valor. Note que um valor pode estar associado a várias chaves, mas cada chave só possui um valor. As seguintes operações são suportadas:
NOVO_MAP()- cria um novoMapSET(M, K, V)- associa o valorVà chaveK. Se a chaveKjá existir substitui o valor.GET(M, K)- devolve o valor associado a chaveK. Se não houver retornaVAZIOREMOVE(M, K)- remove o par com chaveK. Se não houver não faz nada.TAMANHO(M)- devolve o número de chaves que possuem um valor associado
Neste roteiro desenvolveremos juntos os algoritmos necessários para implementar uma versão simplificada do Map usando duas List.
Construindo em cima de outras ADT
Uma das grandes vantagens de definir (e usar) ADTs é que podemos construir algoritimos em mais alto nível. Podemos dizer, simplesmente, que vamos usar uma variável do tipo Array e/ou List e apontar para quais operações são suportadas. Isso nos ajuda a manter os algoritmos compactos e a dar enfoque nas ideias mais importantes para o problema que queremos resolver.
Dica 1
ADTs são conhecimento básico em Computação. Não precisamos repetir, toda vez, o código para implementar o tipo List. Basta dizer que está usando esse tipo.
A implementação mais simples Map é usando duas listas:
KEYS(M)é umListcontendo uma lista de todas as chaves doMapMVALUES(M)é umListcontendo uma lista de todas os valores doMapM
Exercício 1
Resposta
Uma maneira fácil de fazer isto é
KEYS(M)=[ "pastel de queijo", "pastel de carne", "pastel de soja" ]VALUES(M)=[ 2, 1, 5 ]
A ordem aqui não importa, desde que sejamos consistentes e mantenhamos a equivalência de índices para que as chaves e valores continuem "casadas".
Exercício 2
Resposta
Eles são iguais! O conjunto de chaves de ambos é igual e para toda chave o valor devolvido é o mesmo. Para um Map a ordem não importa, somente a presença da chave e o valor associado a ela.
Exercício 3
Resposta
Próxima seção ;)
Vamos usar as seguintes convenções a partir de agora
M_K = KEYS(M)M_V = VALUES(M)
A ideia central é Dada uma associação chave-valor (K, V), se guardamos a chave K no índice i de M_K guardaremos o valor V no mesmo índice i em M_V.
De maneira mais formal, seja $M$ um Map, $N=$TAMANHO(M_K) e $(K, V)$ uma associação chave valor presente em M, então
$$ (K, V) \in M \Leftrightarrow \exists 0 \leq i < N \;\;\text{ tal que }\;\; M_K[i] = K,\; M_V[i] = V $$
Vamos agora desenvolver alguns algoritmos simples para nos familiarizarmos com essa dupla de listas.
Exercício 4
Exercício 5
Resposta
Lousa
Exercício 6
Resposta
Lousa
As operações REMOVE e TAMANHO são variações dos que já foram construídos nessa aula. Para registrar, escreva-os abaixo.
Exercício 7
Exercício 8
Agora acesse o PrairieLearn e implemente esse algoritmos no exercício prático.