Estruturas de Dados - Tipos de Coleções
Objetivos da seção
- Aprender como o conceito de coleção pode ser expresso de
forma genérica
- Examinar a interface de três tipos diferentes de coleções: Listas,
Conjuntos e Mapas
Conceito Geral de Coleção
- Uma coleção é uma estrutura de dados que permite armazenar vários objetos
- A coleção é, em si, um objeto também
- As operações que podem ser feitas em coleções variam mas normalmente incluem:
- Adição de elementos
- Remoção de elementos
- Acesso aos elementos
- Pesquisa de elementos
- Indagar sobre atributos
Tipos de Coleções
- Dependendo da forma de fazer as 4 operações básicas (adição, remoção, acesso e
pesquisa), teremos vários tipos de coleções
- Certas operações poderão ter um desempenho melhor ou
pior dependendo do tipo de coleção
- Certas operações poderão ter restrições ou funcionalidade
especial dependendo do tipo de coleção
- Os três grandes tipos de coleções são:
- A lista
- Também chamado "Sequência"
- O conjunto
- O mapa
- Também chamado "Dicionário"
Listas
- Uma lista é uma coleção de elementos arrumados numa ordem linear, isto é, onde cada
elemento tem um antecessor (exceto o primeiro) e um sucessor (exceto o último)
- Normalmente implementada como "Array" ou "Lista Encadeada"
- A Lista pode ser mantida ordenada ou não
- As operações mais importantes de uma coleção do tipo Lista são:
- Adição de elementos
- Adicionar um objeto em qualquer lugar da lista, fornecendo o índice desejado
- Remoção de elementos
- Remover um objeto presente em qualquer lugar da lista, fornecendo o índice desejado
- Acesso aos elementos
- Obter o elemento de qualquer posição da lista, fornecendo o índice desejado
- Iterar sobre os elementos
- Pesquisa de elementos
- Descobrir se um certo elemento está na lista
- Descobrir o índice de um certo elemento na lista (onde está)
- Indagar sobre atributos
- Obter o número de elementos da coleção
Conjuntos
- Um conjunto é uma coleção que não possui elementos duplicados
- Observe que, no conjunto, não há noção de "ordem dos
elementos"
- O Conjunto pode ser mantido ordenado ou não
- Normalmente implementada como "Tabela Hash" ou "Árvore"
- Esses dois tipos de estrutura de dados serão vistos na disciplina Estruturas de Dados
- As operações mais importantes de uma coleção do tipo Conjunto são:
- Adição de elementos
- Adicionar um objeto no conjunto (descartando duplicações)
- Remoção de elementos
- Remover um objeto presente no conjunto
- Acesso aos elementos
- Iterar sobre os elementos
- Pesquisa de elementos
- Descobrir se um certo elemento está na coleção
- Indagar sobre atributos
- Obter o número de elementos
- Como se vê, as operações são semelhantes, embora diferentes, daquelas para uma Lista
Mapas
- Um mapa armazena pares (chave, valor) chamados itens
- Chaves e valores podem ser de qualquer tipo
- Elemento e Valor são sinônimos
- A chave é utilizada para achar um elemento rapidamente
- Estruturas especiais são usadas para que a pesquisa seja rápida
- Diz-se portanto que um mapa "mapeia chaves para valores"
- O Mapa pode ser mantido ordenado ou não (com respeito às
chaves)
- Normalmente implementada como "Tabela Hash" ou "Árvore"
- Esses dois tipos de estrutura de dados serão vistos na disciplina Estruturas de Dados
- As operações mais importantes de uma coleção do tipo Conjunto são:
- Adição de elementos
- Adicionar um item no mapa (fornecendo chave e valor)
- Remoção de elementos
- Remover um item com chave dada
- Acesso aos elementos
- Pesquisa de elementos
- Descobrir se um elemento com chave dada está na coleção
- Indagar sobre atributos
- Obter o número de elementos
- Observe que o acesso à coleção sempre é feita conhecendo a
chave
Coleções em Java
- Java dá suporte muito bom às coleções explicadas acima
- Examinemos primeiro a hierarquia de interfaces fornecidas pelo Java

- Observe que um Map não é uma Collection pois uma Collection não trabalha com chaves
- Porém, podemos obter uma "visão de Collection" de todas as chaves de um Map
- E podemos obter uma "visão de Collection" de todas os valores
de um Map
- Os métodos principais são como segue:
- Os métodos destacados são os mais usados
Tipo de Coleção |
Coleção Java |
Tipo de Método |
Nome do Método |
Todas as coleções com exceção de Mapas |
Collection |
Adição |
add(Object elemento) |
Remoção |
remove(Object elemento) |
clear() |
Acesso |
iterator() |
Pesquisa |
contains(Object elemento) |
Atributos |
size() |
List |
Vector
ArrayList
LinkedList |
Adição |
add(int index, Object elemento) |
Remoção |
remove(int index) |
Acesso |
get(index) |
listIterator
(iterador que pode andar para trás) |
Pesquisa |
indexOf(Object elemento) |
Conjunto |
HashSet
TreeSet |
|
Nenhum método a mais |
Map |
HashMap
TreeMap |
Adição |
put(Object key, Object value) |
Remoção |
remove(Object key) |
clear() |
Acesso |
get(Object key)
(Isso também é "pesquisa") |
Set entrySet()
(retorna os itens como conjunto) |
Set keySet()
(retorna as chaves como conjunto) |
Collection values()
(retorna os valores como Collection) |
Pesquisa |
get(Object key)
(Isso também é "acesso") |
Atributos |
size() |
- A hierarquia de classes e interfaces de Collection segue:

- A hierarquia de classes e interfaces de Map segue:

Exemplos de Uso das Coleções em Java
- Problema a resolver:
- Leia um arquivo contendo linhas com dois campos separados por ":"
- Insira cada linha numa coleção
- Se a coleção for um mapa, o primeiro campo é a chave, o segundo campo é a valor
- Se a coleção não for um mapa, insira a linha inteira como String
- Leia um segundo arquivo linha por linha e pesquise se cada linha está na coleção,
imprimindo quantos elementos foram descobertos
Implementação com 6 tipos de Coleções
import java.io.*;
import java.util.*;
public class TestaColecoes {
public static void main(String[] args) {
if(args.length < 3) {
sintaxe();
}
try {
BufferedReader arqDados = new BufferedReader(new FileReader(args[1]));
BufferedReader arqPesquisa = new BufferedReader(new FileReader(args[2]));
if(args[0].equals("-v")) {
testaColecao(new ArrayList(), arqDados, arqPesquisa);
} else if(args[0].equals("-le")) {
testaColecao(new LinkedList(), arqDados, arqPesquisa);
} else if(args[0].equals("-hs")) {
testaColecao(new HashSet(), arqDados, arqPesquisa);
} else if(args[0].equals("-ts")) {
testaColecao(new TreeSet(), arqDados, arqPesquisa);
} else if(args[0].equals("-hm")) {
testaMapa(new HashMap(), arqDados, arqPesquisa);
} else if(args[0].equals("-tm")) {
testaMapa(new TreeMap(), arqDados, arqPesquisa);
} else {
sintaxe();
}
} catch(IOException e) {
System.err.println(e);
System.exit(1);
}
}
static void sintaxe() {
System.err.println("Sintaxe: TestaColecoes [-v|-le|-hs|-ts|-hm|-tm] arquivoDados arquivoAPesquisar");
System.exit(1);
}
static void testaColecao(Collection colecao, BufferedReader arqDados, BufferedReader arqPesquisa) throws IOException {
long init = System.currentTimeMillis();
carregaColeção(colecao, arqDados);
long fimCarga = System.currentTimeMillis();
int numAchados = pesquisaColeção(colecao, arqPesquisa);
long fimPesquisa = System.currentTimeMillis();
System.out.println("Elementos achados usando " + colecao.getClass().getName() + ": " + numAchados);
System.out.println("Carga de dados demorou " + ((fimCarga - init)/1000.0) + " segundos");
System.out.println("Pesquisa de dados demorou " + ((fimPesquisa - fimCarga)/1000.0) + " segundos");
System.out.println("Total de tempo " + ((fimPesquisa - init)/1000.0) + " segundos");
}
static void carregaColeção(Collection colecao, BufferedReader arqDados) throws IOException {
String linha;
while((linha = arqDados.readLine()) != null) {
colecao.add(linha);
}
}
static int pesquisaColeção(Collection colecao, BufferedReader arqPesquisa) throws IOException {
String linha;
int numAchados = 0;
while((linha = arqPesquisa.readLine()) != null) {
if(colecao.contains(linha)) {
numAchados++;
}
}
return numAchados;
}
static void testaMapa(Map mapa, BufferedReader arqDados, BufferedReader arqPesquisa) throws IOException {
long init = System.currentTimeMillis();
carregaMapa(mapa, arqDados);
long fimCarga = System.currentTimeMillis();
int numAchados = pesquisaMapa(mapa, arqPesquisa);
long fimPesquisa = System.currentTimeMillis();
System.out.println("Elementos achados usando " + mapa.getClass().getName() + ": " + numAchados);
System.out.println("Carga de dados demorou " + ((fimCarga - init)/1000.0) + " segundos");
System.out.println("Pesquisa de dados demorou " + ((fimPesquisa - fimCarga)/1000.0) + " segundos");
System.out.println("Total de tempo " + ((fimPesquisa - init)/1000.0) + " segundos");
}
static void carregaMapa(Map mapa, BufferedReader arqDados) throws IOException {
String linha;
while((linha = arqDados.readLine()) != null) {
StringTokenizer st = new StringTokenizer(linha, ":");
String chave = st.nextToken();
mapa.put(chave, st.nextToken());
}
}
static int pesquisaMapa(Map mapa, BufferedReader arqPesquisa) throws IOException {
String linha;
int numAchados = 0;
while((linha = arqPesquisa.readLine()) != null) {
StringTokenizer st = new StringTokenizer(linha, ":");
String chave = st.nextToken();
if(mapa.get(chave) != null) {
numAchados++;
}
}
return numAchados;
}
}
- Para testar o programa, um arquivo de dados é criado com muitas linhas:
java GeraDados 20000 >dados.txt
- Depois, o programa é rodado 6 vezes, uma para cada tipo de coleção
- No caso que testei, usei o mesmo arquivo para dados e pesquisa:
java TestaColecoes -xxx dados.txt dados.txt
(onde xxx = -v, -le, -hs, -ts, -hm, -tm)
Exemplo:
C:\...\src>java TestaColecoes -tm dados.txt dados.txt
Elementos achados usando java.util.HashMap: 20000
Carga de dados demorou 1.252 segundos
Pesquisa de dados demorou 0.501 segundos
Total de tempo 1.753 segundos
- As medições de tempo dão os seguintes resultados:
Coleção |
Tempo de carga de dados (segundos) |
Tempo de pesquisa de dados (segundos) |
Tempo total (segundos) |
ArrayList |
0.6 |
54.7 |
55.3 |
LinkedList |
0.7 |
154.1 |
154.8 |
HashSet |
0.8 |
0.7 |
1.5 |
TreeSet |
1.1 |
0.8 |
1.9 |
HashMap |
1.3 |
0.5 |
1.8 |
TreeMap |
1.5 |
0.7 |
2.3 |
- Como se pode ver, alguma coleções são muito mais rápidas do que outras
- Então, por que não usar sempre a mais rápida???
Como Escolher entre Coleções?
- As regras básicas para escolher entre coleções seguem
- Primeiro, a aplicação dita se você vai precisar de Lista, Conjunto ou Mapa
- Se sua aplicação precisar manter duplicatas, use Lista
- Se precisar fazer muita pesquisa, fuja da lista!
- Se sua aplicação não precisar manter duplicatas e não usa chaves, use Conjunto
- Se sua aplicação não precisar manter duplicatas e usa chaves, use Mapa
- Depois, se precisar de uma Lista
- Use ArrayList se acessar por índice for comum (ex.
pesquisa binária)
- Use LinkedList se inserir ou remover elementos do meio com
frequência
- Se precisar de um Conjunto
- Use HashSet se não precisar de um conjunto ordenado
- Use TreeSet se precisar de um conjunto ordenado
- Se precisar de um Mapa
- Use HashMap se não precisar de um mapa ordenado
- Use TreeMap se precisar de um mapa ordenado
ed-2 programa anterior
próxima