programação ii busca em vetor (search)bfeijo/prog2/progii_busca_vetor.pdf · a ideia da busca...

24
Programação II Busca em Vetor (search) Bruno Feijó Dept. de Informática, PUC-Rio

Upload: vuminh

Post on 24-Dec-2018

221 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Programação II

Busca em Vetor(search)

Bruno FeijóDept. de Informática, PUC-Rio

Page 2: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Busca em Vetor

• Problema:– Entrada:

• vetor v com n elementos• elemento d a procurar

– Saída• m se o elemento procurado está em v[m]• -1 se o elemento procurado não está no vetor

• Tipos de Busca em Vetor– Linear (ou sequencial)– Binária

Page 3: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Busca Linear

Page 4: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Busca Linear em Vetor

int busca(n,vetor v de inteiros,elemento)i = 0para cada i, enquanto i<n

se elemento é igual a v[i]retorna i

retorna -1

int busca(n,int * v, int d){

int i;for (i=0; i<n; i++)

if (d == v[i])return i;

return -1;}

Page 5: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Busca Binária

Page 6: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

A Ideia da Busca Binária

• Vetor deve estar inicialmente ordenado• Idéia:

– Como procurar uma palavra no dicionário sucessivamente abrindo pelo meio a parte que deve conter a palavra

• Procedimento:– compare o elemento d com o elemento do meio de v– se o elemento d for menor, pesquise a primeira metade do vetor– se o elemento d for maior, pesquise a segunda parte do vetor– se o elemento d for igual, retorne a posição– continue o procedimento subdividindo a parte de interesse até

encontrar o elemento d ou chegar ao fim

Page 7: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Algoritmo de Busca Binária

int buscaInt(n,vetor v de inteiros, c) /* c: o elemento procurado */ini = 0fim = n-1enquanto ini ≤ fim

meio = (ini + fim)/2compara c com informaçao em v[meio]

se < então fim = meio-1se > então ini = meio+1se = então retorna meio

retorna -1 para indicar insucesso

Caso de comparar dois inteiros:

static int compInt(int c, int b){

if (c < b)return -1;

else if (c > b)return 1;

elsereturn 0;

}

ini

fim

meio

0

n-1

i

- A função de comparação deve retornar negativo (e.g. -1) se for menor, positivo (e.g. 1) se for maior e zero se for igual.

- Geralmente, c e v[meio] não são do mesmo tipo (e.g. se v é um vetor de ponteiros para uma estrutura, estaremos buscando um de seus componentes).

- Este algoritmo é geral. Só muda o que está em vermelho e itálico. Note que antes de retornar meio, pode haver necessidade de processamento extra, e.g. quando há conjunto de valores iguais e queremos o primeiro:

...{adao,25}{ana, 19} ←{ana, 20}

meio→ {ana, 21}{ana, 25}...

queremos a anamais jovem

Page 8: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Busca Binária em Vetor de Inteiros

int buscaInt(n,vetor v de inteiros, c inteiro) /* c: o elemento procurado */ini = 0fim = n-1enquanto ini ≤ fim

meio = (ini + fim)/2compara c com v[meio]

se < então fim = meio-1se > então ini = meio+1se = então retorna meio

retorna -1 para indicar insucesso

static int compInt(int c, int b){

if (c < b)return -1;

else if (c > b)return 1;

elsereturn 0;

}

int buscaInt(int n, int * v, int c){

int ini=0;int fim=n-1;int meio, cmp;while (ini <= fim){

meio=(ini+fim)/2;cmp = compInt(c,v[meio]);if (cmp < 0)

fim=meio-1;else

if (cmp > 0)ini=meio+1;

elsereturn meio;

}return -1;

}

ini

fim

meio

0

n-1

i

Responda: qual é o valor de ini quando o valor procurado não é encontrado? Há duas situações!

Page 9: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Versão com switch

int buscaInt(int n, int * v, int d){

int ini=0;int fim=n-1;int meio;while (ini <= fim){

meio=(ini+fim)/2;switch (compInt(d,v[meio])){

case -1:fim=meio-1;break;

case 1:ini=meio+1;break;

case 0:return meio;

}}return -1;

}

int compInt(int a, int b){

if (a < b)return -1;

else if (a > b)return 1;

elsereturn 0;

}

Page 10: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Exercício Busca String

Escreva um programa completo que busca um nome em um vetor ordenadoalfabeticamente.Dicas: o que muda está em vermelho e itálico no slide 8. Use strcmp da biblioteca de string.

Atenção: a função strcmp(a,b) já faz o trabalho de retornar -1 se a <b, +1 se a>b e 0 se a=b.Entretanto, por razões didáticas (e de treino para a prova), a recomendação é criar uma funçãochamada compString para substituir a compInt do código do slide “Busca Binária em Vetor de Inteiros”(mesmo que essa compString seja apenas o uso direto da strcmp).

Page 11: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Exercício com Estrutura

Escreva um programa completo que monta um vetor de ponteiros para estrutura Pessoa (ordenado crescentemente por nome e idade) e busca um nome nesse vetor (sem se preocupar com a idade).

struct pessoa{

char * nome;int idade;

};typedef struct pessoa Pessoa;

Page 12: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Solução do Exercício com Estrutura

...int main(void){

...i = buscaPes(N, tabPessoa, "daniela");...

}

#include <string.h>#include "pessoa.h"

static int compPessoa(char * a, Pessoa * b){

return strcmp(a,b->nome);}

int buscaPes(int n, Pessoa ** v, char * nome){

int ini=0;int fim=n-1;int meio, cmp;while (ini <= fim){

meio=(ini+fim)/2;cmp=compPessoa(nome,v[meio]);if (cmp<0)

fim=meio-1;else if (cmp>0)

ini=meio+1;else

return meio;}return -1;

}

Page 13: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Variações

• O vetor tem um critério complexo de ordenação (i.e. um critério primário e vários secundários de desempate)

– Por exemplo, um campeonato que pode estar ordenado com o critério primário de Pontos Ganhos (PG) e desempate por Saldo de Gols (SG) e Gols Pró (GP).

– Neste caso, a função de comparação deve ter expressões booleanas que representem o critério. Por exemplo:

• Tipo de informação retornada– O índice do elemento encontrado ou -1– O endereco do elemento encontrado (i.e. o ponteiro)– O valor de um campo específico ou outra informação qualquer– Verdade (e.g. 1) se encontrou, ou Falso (0), caso contrário

• Tratamento de repetições

static int compTime(int pg, int sg, int gp, Campeonato * time){

if (pg < time->pg || (pg == time->pg && sg < time->sg) || ...)return -1;

else if (pg > time->pg || (pg == time->pg && pg > time-> sg) || ...)return 1;

elsereturn 0;

}

Page 14: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Exercício com Estrutura e Critério Secundário

Escreva um programa completo, que monta um vetor de ponteiros paraestrutura Pessoa (ordenado crescentemente por nome e idade) e buscaum nome com uma determinada idade nesse vetor.

struct pessoa{

char nome[81];int idade;

};typedef struct pessoa Pessoa;

Page 15: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

int buscaPessoa(int n, Pessoa ** v,char * nome)

{int ini=0;int fim=n-1;int meio, cmp;while (ini <= fim){

meio=(ini+fim)/2;cmp=compPessoa(nome,v[meio]);if (cmp<0)

fim=meio-1;else if (cmp>0)

ini=meio+1;else

return meio;}return -1;

} int main(void){

Pessoa * tab[N];Pessoa * p;...p = buscaPessoa(N,tab,nome);if (p==NULL)

printf("elemento nao existe\n");idade = p->idade;...

}

Busca que Retorna o Endereço do ElementoPessoa * buscaPessoa(int n, Pessoa ** v,char * nome){

int ini=0;int fim=n-1;int meio, cmp;while (ini <= fim){

meio=(ini+fim)/2;cmp=compPessoa(nome,v[meio]);if (cmp<0)

fim=meio-1;else if (cmp>0)

ini=meio+1;else

return v[meio];}return NULL;

}

Page 16: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Busca que Trata de Repetições

• Considere um tipo que representa as licenças dos funcionário de uma empresa, definido pela estrutura a seguir:

struct licenca {char nome[51]; /* nome do funcionario */Data inicio; /* data de inicio da licenca */Data final; /* data de final da licenca */

};

typedef struct licenca Licenca;

• Os campos inicio e final são do tipo Data, descrito a seguir:struct data {

int dia, mes, ano;};typedef struct data Data;

• Escreva uma função que faça uma busca binária em um vetor de ponteiros para o tipo Licenca, cujos elementos estão em ordem cronológica, de acordo com a data de início das licenças, com desempate pela ordem alfabética de acordo com o nome dos funcionários. Se existir mais de uma licença com início na data procurada, a função deve retornar o índice da primeira delas. Se não houver uma licença com a data procurada, a função deve retornar -1. Sua função deve ter o seguinte cabeçalho:

int busca (Licenca ** v, int n, Data d);

Page 17: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Busca que Trata de Repetições

int busca(Licenca ** v, int n, Data d){int ini=0, fim=n-1, meio, cmp;while (ini <= fim){ meio = (ini+fim)/2;cmp = compData(d,v[meio]); // usa v[meio]->inicioif (cmp < 0) // -1fim = meio–1;

else if (cmp > 0) // 1ini = meio+1;

else{

while(meio>0 && compData(d,v[meio-1])==0) meio--; // procura primeira ocorrencia, caso contrário e’ aleatorio

return meio;}

} return -1; /* não encontrou */

}

escreva compData usando ano, mes e dia

Page 18: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

TÓPICOS AVANÇADOS

Page 19: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Binary Search da stdlib do C

void * bsearch(void * info, void * v, int n, int tam,int (*cmp)(const void *, const void *));

info: ponteiro para a informação que se deseja buscarv: vetor de ponteiros genéricos (ordenado)n: número de elementos do vetortam: tamanho em bytes de cada elemento (use sizeof para especificar)cmp: ponteiro para função que compara elementos genéricos, sendo o primeiro

o endereço da informação e o segundo é o ponteiro para um dos elementosdo vetor. O critério de comparação deve ser o mesmo da ordenação de vint nome(const void * a, const void * b);deve retornar <0 se a<b, >0 se a>b e 0 se a == b

chamada: int d = 23;int * p;p = (int *)bsearch(&d,v,N,sizeof(int),compInt); // N é o tamanho de vi = p-v; // indice do elemento encontrado

const é para garantir quea função não modificaráos valores dos elementosstatic int compInt(const void * a, const void * b)

{int * info = (int *)a; // converte o ponteiro genericoint * bb = (int *)b; // converte o ponteiro genericoif (*info < *bb) // faz as comparacoes. Atenção para o *

return -1;else if (*info > *bb)

return 1;else

return 0;}

Page 20: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Análise de Complexidade

Page 21: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Busca Linear em Vetor

int busca(n,vetor v de inteiros,elemento)i = 0para cada i, enquanto i<n

se elemento é igual a v[i]retorna i

retorna -1

Pior Caso: o elemento não está no vetorNeste caso são necessárias n comparaçõesT(n) = n → O(n) Linear !

Melhor Caso: o elemento é o primeiro → O (1)

Caso Médio:n/2 comparações

T(n) = n/2 → O(n) Também Linear !

Se o vetor estivesse ordenado, poderíamos escrever uma função mais eficiente (onde retornaríamos -1 quando o elemento fosse menor do que v[i]), mas a complexidade continuaria O(n).Um algoritmo pode ter a mesma complexidade de um outro, porém pode ser mais, ou menos, eficiente. Eficiência e Complexidade são coisas diferentes !

int busca(n,int * v, int d){

int i;for (i=0; i<n; i++)

if (d == v[i])return i;

return -1;}

Na análise de complexidade, procuramos o “Pior Caso”, o “Melhor Caso” e o “Caso Médio”

Page 22: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Análise da Complexidade

• Pior Caso: elemento não está no vetor– cada repetição do loop gasta um tempo constante– a questão é, portanto: quantas vezes o loop será repetido?

• cada repetição do loop reduz o tamanho da busca pela metade:• repetição 1 → tamanho da busca é n /2• repetição 2 → tamanho da busca é n / 22

• repetição 3 → tamanho da busca é n /23

• ...• repetição i → tamanho da busca é n /2i

– as repetições param quando o tamanho da busca for 1, isto é n /2i = 1ou seja: 2i = n

– Portanto: i = log n, isto é: o loop é repetido log n vezes– Ou seja: T(n) = log n → O(log n)

• Melhor Caso: elemento está no meio → O(1)• Caso Médio (dedução mais complicada): O(log n)

Page 23: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Complexidades Comuns (notação Big O)

Notação Big OO(1) Tempo constanteO(log n) Tempo logarítmicoO(n) Tempo linearO(n log n) Tempo loglinear (ou quaselinear)O(n2) Tempo quadrático

Limite n2

nnnT21

21)( 2 −=

Quase linear

n

Page 24: Programação II Busca em Vetor (search)bfeijo/prog2/ProgII_Busca_Vetor.pdf · A Ideia da Busca Binária • Vetor deve estar inicialmente ordenado • Idéia: – Como procurar uma

Diferença entre n e log n

36 seg100 anos94 608 000 000301 ano946 080 000211 mês2 592 000161 dia86 400121 h3 600910 min60061 min60

3 seg10 seg10O(log n)O(n)tamanho