Livro de Sedgewick e Wayne: sec.3.1, p.362. Website do livro: resumo sec.3.1, slides. Código fonte, documentação, e dados de teste de todos os programas do livro: veja algs4.cs.princeton.edu/code/.
Resumo:
Pré-requisitos:
valor da chave kpode ser entendida de duas maneiras: como o valor que a tabela associa com k e como o valor da variável k. Nem sempre a interpretação é óbvia.)
chave valor
8536152 Antonio Silva
7210629 Arthur Costa
8536339 Bruno Carvalho
8536002 Bruno Lima
8067490 Bruno Aires
8536106 Caio Oliveira
...
7581374 Vinicius Lima
8535922 Vitor Sales
5992240 Wellington Lima
8536023 Yan Ferreira
chave valor
www.ebay.com 66.135.192.87
www.princeton.edu 128.112.128.15
www.cs.princeton.edu 128.112.136.35
www.harvard.edu 128.103.60.24
www.yale.edu 130.132.51.8
www.cnn.com 64.236.16.20
www.google.com 216.239.41.99
www.nytimes.com 199.239.136.200
www.apple.com 17.112.152.32
www.slashdot.org 66.35.250.151
www.espn.com 199.181.135.201
www.weather.com 63.111.66.11
www.yahoo.com 216.109.118.65
... ...
www.ime.usp.br 143.107.45.37
Nossas convenções sobre TSs:
| public class ST<Key,Value> | ||
| ST() | cria uma tabela de símbolos vazia | |
| void | put(Key key, Value val) | insere o item (key,val) nesta tabela |
| Value | get(Key key) | busca o valor associado a key |
| boolean | isEmpty() | esta tabela está vazia? |
| boolean | contains(Key key) | a chave key está nesta tabela? |
| Iterable<Key> | keys() | lista todas as chaves desta tabela |
Se a tabela já tem um item com chave igual a key,
a operação put(key, val)
substitui o item antigo pelo novo.
public static void main(String[] args) {
ST<String, Integer> st;
st = new ST<String, Integer>();
for (int i = 0; !StdIn.isEmpty(); i++) {
String key = StdIn.readString();
st.put(key, i);
}
for (String s : st.keys()) // foreach
StdOut.println(s + " " + st.get(s));
}
A primeira palavra lida recebe valor 1, e segunda recebe valor 2, etc. Como não permitimos chaves repetidas, apenas a cópia mais recente de cada palavra fica na TS. Exemplo de entrada (cada palavra tem uma só letra):
key S E A R C H E X A M P L E i 0 1 2 3 4 5 6 7 8 9 10 11 12
Saída:
L 11 P 10 M 9 X 7 H 5 C 4 R 3 A 8 E 12 S 0
public class FrequencyCounter {
public static void main(String[] args) {
int minlen = Integer.parseInt(args[0]);
ST<String, Integer> st = new ST<String, Integer>();
while (!StdIn.isEmpty()) {
String word = StdIn.readString();
if (word.length() < minlen) continue;
if (!st.contains(word)) st.put(word, 1);
else st.put(word, st.get(word) + 1);
}
String max = "";
st.put(max, 0);
for (String word : st.keys()) // foreach
if (st.get(word) > st.get(max))
max = word;
StdOut.println(max + " " + st.get(max));
}
}
Testes:
% java FrequencyCounter 1 < tinyTale.txt it 10 % java FrequencyCounter 8 < tale.txt business 122 % java FrequencyCounter 10 < leipzig1M.txt government 24763
% more tinyTale.txt it was the best of times it was the worst of times it was the age of wisdom it was the age of foolishness it was the epoch of belief it was the epoch of incredulity it was the season of light it was the season of darkness it was the spring of hope it was the winter of despair
| tinyTale.txt | tale.txt | leipzig1M.txt | ||||
| palavras | diferentes | palavras | diferentes | palavras | diferentes | |
| todas as palavras | 60 | 20 | 135 635 | 10 679 | 21 191 455 | 534 580 |
| 8 letras ou mais | 3 | 3 | 14 350 | 5 737 | 4 239 597 | 299 593 |
| 10 letras ou mais | 2 | 2 | 4 582 | 2 260 | 1 610 829 | 165 555 |
SequentialSearchSTo nome
STda classe descrita na API.
public class SequentialSearchST<Key,Value> {
private Node first;
// nó da lista ligada
private class Node {
private Key key;
private Value val;
private Node next;
public Node(Key key, Value val, Node next) { // construtor
this.key = key;
this.val = val;
this.next = next;
}
}
public Value get(Key key) {
for (Node x = first; x != null; x = x.next)
if (key.equals(x.key))
return x.val; // acerto
return null; // falha
}
public void put(Key key, Value val) {
for (Node x = first; x != null; x = x.next)
if (key.equals(x.key)) {
x.val = val;
return;
} // acerto: atualiza val
first = new Node(key, val, first); // falha: acrescenta novo nó
}
}
if (key == x.key)não faz sentido.
O custo médio de uma busca bem-sucedida,
também conhecido como custo de uma busca aleatória bem-sucedida,
é o quociente
c/N,
onde c é a soma dos custos das busca de todas as chaves na tabela
e N é o número total de chaves na tabela.
|
número máximo de chaves tocadas | |
| get() | N |
| put() | N |
Portanto, as duas operações, busca e inserção, são muito lentas. (A inserção é lenta em virtude de nossa convenção de não inserir chaves repetidas na TS.)
SequentialSearchSTno lugar de
STàs palavras de comprimento 8 ou mais no arquivo tale.txt. Segue o gráfico do número de chaves tocadas por cada chamada de put(). Os pontos vermelhos dão a média corrente:
if (!st.contains(word)) st.put(word, 1);
else st.put(word, st.get(word) + 1);
resulta em duas ou três buscas pela mesma chave. Para evitar isso sem mudar o código de FrequencyCounter, podemos usar a técnica de software caching: armazenamos a localização da chave mais recentemente encontrada em uma variável de instância. Faça isso em SequentialSearchST.
Resposta: Se uma chave k fosse null, uma expressão como k.equals(kk) produziria um indesejável Null Pointer Exception.
Resposta:
Eu detesto siglas,
mas não posso evitar.
Ficar repetindo tipo abstrato de dados
um grande número de vezes
é uma alternativa pior.