Pesquisa em Memória Primária
Algoritmos e Estruturas de Dados II
Pesquisa em Memória Primária

Pesquisa:



Objetivo:


Recuperação de informação em um grande volume de
dados.
Informação é dividida em registros e cada registro contém
uma chave.
Encontrar itens com chaves iguais a chave dada.
Aplicações:


Contas em um banco
Reservas de uma companhia aérea
2
Pesquisa em Memória Primária

Escolha do método de busca



Quantidade de dados envolvidos.
Frequência com que operações de inserção e retirada são
efetuadas.
Métodos de pesquisa:



Pesquisa sequencial
Pesquisa binária
Árvore de pesquisa




Árvores binárias de pesquisa sem balanceamento
Árvores binárias de pesquisa com balanceamento
Pesquisa digital
Hashing
3
Tabelas de Símbolos

Estrutura de dados contendo itens com chaves que
suportam duas operações



Inserção de um novo item
Retorno de um item que contém uma determinada chave.
Tabelas são também conhecidas como dicionários


Chaves – palavras
Item – entradas associadas as palavras (significado,
pronúncia)
4
Tipo Abstrato de Dados

Considerar os algoritmos de pesquisa como tipos
abstratos de dados (TADs), com um conjunto de
operações associado a uma estrutura de dados,


Há independência de implementação para as operações.
Operações:





Inicializar a estrutura de dados
Pesquisar um ou mais registros com uma dada chave
Inserir um novo registro
Remover um registro específico
Ordenar os registros
5
Pesquisa Sequencial

Método de pesquisa mais simples

A partir do primeiro registro, pesquisa sequencialmente até
encontrar a chave procurada

Uma possibilidade de implementação é armazenar os
registros em um vetor.

Inserção de um novo item


Adiciona no final do vetor.
Remoção de um item com chave específica

Localiza o elemento, remove-o e coloca o último item do
vetor em seu lugar.
6
Pesquisa Sequencial
# define MAX
10
typedef int TipoChave;
typedef struct {
TipoChave Chave;
/* outros componentes */
} Registro;
typedef int Indice;
typedef struct {
Registro Item[MAX + 1];
Indice n;
} Tabela;
7
Pesquisa Sequencial
void Inicializa(Tabela *T) {
T->n = 0;
}
/* retorna 0 se não encontrar um registro com a chave x */
Indice Pesquisa(TipoChave x, Tabela *T){
int i;
T->Item[0].Chave = x; /* sentinela */
i = T->n + 1;
do {
i--;
} while (T->Item[i].Chave != x);
return i;
}
8
Pesquisa Sequencial
void Insere(Registro Reg, Tabela *T) {
if (T->n == MAX)
printf("Erro : tabela cheia\n");
else {
T->n++;
T->Item[T->n] = Reg;
}
}
void Remove(TipoChave x, Tabela *T) {
Int idx;
idx = Pesquisa(x, T);
/* se encontrou o item, troca pelo último, reduz o n */
if (idx) T->Item[idx] = T->Item[T->n--];
}
9
Pesquisa Sequencial

Análise:

Pesquisa com sucesso




melhor caso: C(n) = 1
pior caso: C(n) = n
caso médio: C(n) = (n+1) / 2
Pesquisa sem sucesso

C(n) = n + 1
10
Pesquisa Binária

Redução do tempo de busca aplicando o paradigma
dividir para conquistar.
1.
2.
3.
4.

Compare a chave com o registro do meio.
Se for menor, o registro procurado está à esquerda.
Se for maior, está à direita.
Repita.
Restrição: chaves precisam estar ordenadas


Manter chaves ordenadas na inserção pode levar a
comportamento quadrático.
Se chaves estiverem disponíveis no início, um método de
ordenação rápido pode ser usado.
11
Pesquisa Binária

Exemplo: pesquisa pela chave L
A
A
A
C
E
E
E
G
H
I
L
M
N
P
R
A
A
A
C
E
E
E
G
H
I
L
M
N
P
R
H
I
L
M
N
P
R
H
I
L
L
12
Pesquisa Binária

Exemplo: pesquisa pela chave J
A
A
A
C
E
E
E
G
H
I
L
M
N
P
R
A
A
A
C
E
E
E
G
H
I
L
M
N
P
R
H
I
L
M
N
P
R
H
I
L
L
13
Pesquisa Binária
Indice Binaria(TipoChave x, Tabela *T) {
Indice i, Esq, Dir;
if (T->n == 0) return 0; /* vetor vazio */
Esq = 1;
Dir = T->n;
do {
i = (Esq + Dir) / 2;
if (x > T->Item[i].Chave)
Esq = i + 1; /* procura na partição direita */
else
Dir = i - 1; /* procura na partição esquerda */
}
while ((x != T->Item[i].Chave) && (Esq <= Dir));
if (x == T->Item[i].Chave)
return i;
else
return 0;
14
Pesquisa Binária

Análise

Tamanho do vetor:



𝑛 𝑛
2 4
𝑛, , , ..., 1=
𝑛 𝑛 𝑛
𝑛
,
,
,
...,
20 21 22
2𝑙𝑜𝑔2 𝑛
Cerca de 𝑙𝑜𝑔2 𝑛 passos: O(logn).
Ressalva


Alto custo para manter a tabela ordenada: a cada inserção
na posição p da tabela implica no deslocamento de n-p+1
registros a partir da posição p para as posições seguintes.
Portanto, a pesquisa binária não deve ser usada em
aplicações muito dinâmicas.
15
Árvore Binária de Pesquisa

Estrutura de dados constituída de nós.

Cada nó (pai) pode apontar para até dois outros nós
(filhos): denotados por esquerda e direita.

O nó que não possui pai é chamado de raiz. Nós sem
filho são nós folha.

Árvores binárias de pesquisa mantêm a propriedade
de que um nó possui chave maior que a de seu filho à
esquerda e menor que a de seu filho à direita.
16
Árvore Binária de Pesquisa
1
2
4
7
2
6
3
3
5
4
6
9
8
1
17
Árvore Binária de Pesquisa
Nó 1 é o nó
raiz
1
Nó 2 é pai de 4 e 5
2
4
7
1
2
6
3
3
5
4
6
9
8
Nós 4 e 5 são os filhos
à esquerda e direita de
2
18
Árvore Binária de Pesquisa

Busca

Compare a chave com o elemento raiz.

Se for menor, o registro procurado só pode estar à
esquerda.

Se for maior, só pode estar à direita.
19
Árvore Binária de Pesquisa
struct arvore {
struct arvore *esq;
struct arvore *dir;
Registro reg;
};
struct arvore *cria_arvore(Registro reg) {
struct arvore *novo;
novo = malloc(sizeof(struct arvore));
novo->esq = NULL;
novo->dir = NULL;
novo->reg = reg;
}
0
Árvore Binária de Pesquisa: Busca
void Pesquisa(Registro *x, struct arvore *t) {
if (t == NULL) {
printf("Registro não esta presente na árvore\n");
}
else
if (x->Chave < t->reg.Chave)
Pesquisa(x, t->Esq); /* busca no filho esquerdo */
else if (x->Chave > t->reg.Chave)
Pesquisa(x, t->Dir); /* busca no filho direito */
else
*x = t->reg;
}
Árvore Binária de Pesquisa: Inserção


O elemento vai ser inserido como uma folha da
árvore de busca
Vamos procurar o lugar de inserção navegando da
raiz até a folha onde ele será inserido
Árvore Binária de Pesquisa: Inserção
4.5
6
5
4
8
7
2
1
B
A
3
9
C
Árvore Binária de Pesquisa: Inserção
6
4.5
4
5
8
7
2
1
B
A
3
9
C
Árvore Binária de Pesquisa: Inserção
6
5
4.5
4
8
7
2
1
B
A
3
9
C
Árvore Binária de Pesquisa: Inserção
6
5
4
2
1
8
7
A
4.5
3
B
9
C
Árvore Binária de Pesquisa: Inserção
void insere_elemento(struct arvore *t, Registro reg) {
if(reg.Chave < t->reg.Chave) {
/* chave menor */
if (t->esq) { insere_elemento(t->esq, reg); }
else { /* achou local de inserção */
struct arvore *novo = cria_arvore(reg);
t->esq = novo;
}
} else {
/* chave maior ou igual ao nodo atual */
if (t->dir) { insere_elemento(t->dir, reg); }
else {
struct arvore *novo = cria_arvore(reg);
t->dir = novo;
}
}
}
Árvore Binária de Pesquisa: Remoção



Remover folhas
Remover nós com um filho
Remover nós com
dois filhos
6
5
4
8
7
2
1
B
A
3
9
C
Árvore Binária de Pesquisa: Remoção

Nó com 1 filho
6
5
4
8
7
2
1
B
A
3
9
C
Árvore Binária de Pesquisa: Remoção

Nó com 1 filho
6
5
2
1
8
7
3
B
A
9
C
Árvore Binária de Pesquisa: Remoção


Nó com 2 filhos
Substituído pelo registro mais à
esquerda da sub-árvore á
direita ou pelo registro mais à
5
direita da sub-árvore à
esquerda.
4
6
8
7
2
1
B
A
3
9
C
Árvore Binária de Pesquisa: Remoção


Nó com 2 filhos
Substituído pelo registro mais à
esquerda da sub-árvore á
direita ou pelo registro mais à
5
direita da sub-árvore à
esquerda.
4
7
8
7
2
1
B
A
3
9
C
Árvore Binária de Pesquisa: Remoção
struct arvore *remove(struct arvore *t, TipoChave Chave) {
struct arvore *aux;
if(t == NULL) { printf(“elemento ausente\n”); }
else if(Chave < t->reg.Chave){ t->esq=remove(t->esq, Chave); }
else if(Chave > t->reg.Chave){ t->dir=remove(t->dir, Chave); }
else if (t->esq == NULL && t->dir == NULL) {
free(t); return NULL; /* zero filhos */
}
else if(t->esq == NULL) {
aux = t->dir; free(t); return aux; /* 1 filho direita */
}
else if(t->dir == NULL) {
aux = t->esq; free(t); return aux; /* 1 filho esquerda */
} else { /* 2 filhos */
struct arvore *suc = acha_menor(t->dir);
t->reg = suc->reg;
t->dir = remove(t->dir, suc->reg.Chave);
return t;
}
return t;
}
Árvore Binária de Pesquisa: Remoção
void acha_menor(arvore *t) {
if(t->esq == NULL) {
return t;
}
return acha_menor(t->esq);
}
Árvore Binária de Pesquisa: Análise

Número de comparações: busca com sucesso



melhor caso: C(n) = O(1)
pior caso: C(n) = O(n)
caso médio: C(n) = O(log n)
Download

aedsii_pesquisa_seq_..