Pesquisa Ordenação e Pesquisa de Dados Marco Antonio Montebello Júnior [email protected] Pesquisa Seqüencial ou Linear Varredura serial da tabela Pode ser aplicada em tabelas representadas por arrays, arquivos ou listas ligadas Desempenho do algoritmo de pesquisa seqüencial é sofrível NC = (n+1)/2 NC: número de comparações n: número de elementos da tabela Obtenção da fórmula NC = 1 * p1 + 2 * p2 + 3 * p3 + 4 * p4 + ... + n-1 * pn-1 + n * pn NC = 1 * 1/n + 2 * 1/n + 3 * 1/n + 4 * 1/n + ....+ n * 1/n NC = 1/n * (1+2+3+4+5+...+n) NC = 1/n * (n * (n+1) / 2) NC = (n2 + n) / 2n NC = (n + 1) / 2 p1, p2, p3, ..., pn = probabilidade de se encontrar o elemento Técnicas para se melhorar o desempenho do algoritmo de pesquisa seqüencial Melhorias por sofisticação no algoritmo Melhorias baseadas nos dados a serem pesquisados Sentinela: sentinela nada mais é do que a agregação do dado que se deseja procurar ao final da tabela sobre qual se vai executar a pesquisa Número total de comparações para o pior caso é 2n+1 Uso da sentinela permite fazer uma única comparação em cada ciclo, reduzindo em 50% o número de comparações para o pior caso, que passa a ser n+1 Técnicas para se melhorar o desempenho do algoritmo de pesquisa seqüencial As principais desvantagens do uso de sentinelas são: A necessidade de se alterar a tabela, adicionando um elemento "estrangeiro" a ela. A eliminação de uma comparação permite um ganho muito pequeno de velocidade no programa O programador deve garantir a presença de uma posição vazia no final da tabela, não devendo utilizála para nenhum outro propósito (deve-se redobrar a atenção em operações de inserção). Algoritmos Busca em tabela Busca em tabela melhorado Busca com sentinela Pesquisa binária Algoritmo 1: Busca em tabela Uma forma intuitiva é construir um algoritmo que pesquise em todas posições de uma tabela a ocorrência de um certo elemento procurado. Isso pode ser realizado por uma estrutura de repetição do tipo “para até” Nesse algoritmo percebemos que são executadas n comparações porque existe comparação até o final, mesmo o elemento tendo sido encontrado na primeira posição. 40 1 22 88 13 65 Algoritmo 1: Busca em tabela Início achou false para aux 1 até n se tab[aux] = dado então achou true ind aux fim_se fim_para se achou = true então escreva “Dado na posição”, ind senão escreva “Dado não achado!” fim_se fim. Algoritmo 2: Busca em tabela melhorado Uma evolução do algoritmo anterior poderia contemplar a interrupção da pesquisa, tão logo o elemento procurado seja encontrado na tabela. O número de comparações que será realizado depende da distribuição dos dados na tabela. Se esta distribuição for aleatória, podemos esperar que na melhor situação, encontraremos o dado na primeira posição e na pior situação, teremos que percorrer toda a tabela, e assim por diante. Dessa forma, na média o algoritmo executa n/2 repetições da estrutura do tipo “enquanto” 40 1 22 88 13 65 Algoritmo 2: Busca em tabela melhorado Início Achou false Procura true Ind 0 Enquanto (procura = true) faça Ind Ind + 1 Se Ind > n então Procura false Senão Procura (tab[ind] <> dado) Fim_se Fim_enquanto Se Ind < = n então Achou true Fim_se Se (achou = true) então Escreva “Dado na posição”, Ind Senão Escreva “Dado não achado” Fim_se Fim. Algoritmo 3: Busca com sentinela O algoritmo tem o seguinte inconveniente: Para cada valor de “ind” a rotina deve fazer duas comparações, a primeira para saber se “procura” é true (verdadeira) e a segunda para testar o valor de “ind” (ind > n). Podemos apresentar um algoritmo que realiza a busca somente com uma única comparação. Algoritmo 3: Busca com sentinela Se soubéssemos que o elemento a ser procurado se encontra na tabela, não teríamos necessidade de fazer o teste de fim de tabela, pois, o dado seria encontrado antes do final. Uma solução é colocar “dado” no final da tabela, que deve ser acrescida de uma posição para este fim. Dessa forma, temos a necessidade de um único teste: o de comparação com “dado”. Caso o valor de “ind” seja igual a “n” saberemos que o elemento procurado não se encontra na tabela. 40 01 22 88 13 65 Dado Procurado Algoritmo 3: Busca com sentinela Início achou false ind 1 tab[n]dado enquanto (tab[ind] <> dado) faça Ind Ind +1 fim_enquanto achou (ind <> n) se (achou = true) então escreva “Dado na posição”, ind senão escreva “Dado não achado!” fim_se Fim. Algoritmo 3: Busca com sentinela Agora temos um algoritmo mais eficiente, pois, com as últimas modificações, o algoritmo encontra um elemento, na média n/2 pesquisas e em cada uma delas, executa apenas uma comparação. Algoritmo 4: Pesquisa Binária Os algoritmos 1, 2 e 3 consideram que a pesquisa será feita na forma seqüencial e têm a característica de serem simples, porém, podem exigir a inspeção de todos os elementos no caso do elemento procurado não existir na tabela. A procura binária é uma alternativa, mais eficiente em relação a procura seqüencial, exigindo, contudo, que os elementos sobre os quais a procura será realizada se encontrem ordenados. Algoritmo 4: Pesquisa Binária Utilizando a procura binária, consideramos em primeiro lugar o elemento que se encontra no meio da tabela. Se este elemento é maior que o elemento que estamos procurando (por “maior”, entenda-se “aparece depois”), então podemos garantir que o elemento que estamos procurando não se encontra na segunda metade da tabela. Algoritmo 4: Pesquisa Binária Repetimos então o processo da procura binária para a primeira metade da tabela. Se o elemento no meio da tabela é menor do que o elemento que estamos procurando (por “menor”, entenda-se “aparece antes”), então podemos garantir que o elemento que estamos procurando não se encontra na primeira metade da tabela. Se o elemento no meio da tabela for igual ao elemento que estamos procurando, então a procura termina. Notamos que em cada passo a procura binária reduz o número de elementos a considerar para a metade (e daí o seu nome) Algoritmo 4: Pesquisa Binária Início Achou false Inicio 1 Fim n Meio (1+n) div 2 Enquanto (dado <> tab[Meio] e (Inicio <> Fim) faça Se (dado > tab[Meio]) então Inicio Meio +1 Senão Fim Meio Fim_se Meio (Inicio + Fim) div 2 Fim_enquanto Achou (dado = tab[meio]) Se (achou = true) então Escreva “Dado na posição”,meio Senão Escreva “Dado não achado!” Fim_se Fim Algoritmo 4: Pesquisa Binária Na procura binária somos capazes de reduzir pela metade o número de elementos a considerar sempre que efetuamos uma comparação. Assim, se começarmos com “maxelementos”, o número de elementos depois de uma passagem é maxelementos/2, depois, maxelementos/4 e assim, sucessivamente. No caso geral, o número de elementos depois de n passagens é maxelementos/2n. O algoritmo termina quando o número de elementos é menor do que 1, ou seja, terminamos depois de n passagens se: Maxelementos/2n < 1 Maxelementos < 2n log2 maxelementos < n Dessa forma, para uma tabela com maxelementos, a procura binária não exige mais do que 1 + log2 maxelementos passagens. Algoritmo 4: Pesquisa Binária