Ordenação, Notas de estudo de Engenharia Informática
wellington-cassio-faria-8
wellington-cassio-faria-8

Ordenação, Notas de estudo de Engenharia Informática

25 páginas
39Números de download
1000+Número de visitas
Descrição
Algoritmos de Ordenação
30 pontos
Pontos de download necessários para baixar
este documento
Baixar o documento
Pré-visualização3 páginas / 25
Esta é apenas uma pré-visualização
3 mostrados em 25 páginas
Esta é apenas uma pré-visualização
3 mostrados em 25 páginas
Esta é apenas uma pré-visualização
3 mostrados em 25 páginas
Esta é apenas uma pré-visualização
3 mostrados em 25 páginas
19 MAKROS Books Ordenação e Pesquisa No mundo da computação, talvez as tarefas mais fundamentais e extensivamente analisadas sejam ordenação e pesquisa. Essas rotinas são utilizadas em pratica- mente todos os programas de banco de dados, bem como em compiladores, in- terpretadores e sistemas operacionais. Este capítulo introduz os conceitos básicos de ordenação e pesquisa. Como você verá, ordenar e pesquisar ilustram diversas técnicas de programação em €. Como o objetivo de ordenar os dados geralmente é facilitar e acelerar o processo de pesquisa nesses dados, discutimos primeiro a ordenação. ag Ordenação Ordenação é o processo de arranjar um conjunto de informações semelhantes numa ordem crescente ou decrescente. Especificamente, dada uma lista ordenada i de n elementos, então N< Cap. 19 Ordenação» pesquisa asa as 503 a Em que velocidade ele pode ordenar as informações no caso médio? Qual a velocidade do seu melhor e pior casos? n m EH Esse algoritmo apresenta um comportamento natural ou não-natural? E Ele rearranja elementos com chaves iguais? Olhe, agora, atentamente para esses critérios. Evidentemente a velocida- de em que um algoritmo particular ordena é de grande importância. A veloci- dade em que uma matriz pode ser classificada está diretamente relacionada com o número de comparações e o número de trocas que ocorrem, com as trocas exigindo mais tempo. Uma comparação ocorre quando um elemento da matriz é comparado a outro; uma troca ocorre quando dois elementos na matriz ocupam um o lugar do outro. Como você verá em breve, algumas ordenações variam o tempo de ordenação de um elemento de forma exponencial e outras de forma logarítmica. Os tempos de processamento para o pior e melhor casos são importantes se você espera, frequentemente, encontrar uma dessas situações. Normalmente, uma ordenação tem um bom caso médio, mas um terrível pior caso. Diz-se que uma ordenação tem um comportamento natural se ela traba- lha o mínimo quando a lista já está ordenada, trabalha mais quanto mais desor- denada estiver a lista e o maior tempo quando a lista está em ordem inversa. A determinação do quanto uma ordenação trabalha é baseada no número de comparações e trocas que ela deve executar. Tara entender por que rearranjar elementos com chaves iguais pode ser importante, imagine um banco de dados como uma lista postal, que é ordenada de acordo com uma chave principal e uma subchave. A chave principal é o CEP e, dentro dos códigos de CEP, o sobrenome é a subchave. Quando um novo endereço for acrescentado à lista e esta for reordenada, as subchaves (isto é, os sobrenomes com os mesmos códigos de CEP) não devem ser arranjadas. Para garantir que isso não aconteça, uma ordenação não deve trocar as chaves prin- cipais de mesmo valor. A discussão que se segue examina, primeiro, as ordenações representa- tivas de cada categoria e, então, analisa a eficiência de cada uma. Mais adiante, você aprenderá métodos mais aperfeiçoados de ordenação. A Ordenação Bolha — O Demônio das Trocas A ordenação mais conhecida (e mais difamada) é a ordenação bolha. Sua popula- ridade vem do seu nome fácil e de sua simplicidade. Porém, é uma das piores ordenações já concebidas. Soa so É Completo eTotak Ê & ii da do aaa fica fude A ordenação bolha é uma ordenação por trocas. Ela envolve repetidas comparações e, se necessário, a troca de dois elementos adjacentes. Os elementos são como bolhas em um tanque de água — cada uma procura o seu próprio nível. A forma mais simples da ordenação bolha é mostrada aqui: !* A ordenação bolha. */ void bubble(char *item, int count) í register int a, b; register char t; for (a=l; a=a; --b) if(item[b-1] > item[b]) ( !* troca os elementos */ t = item[b-1]; item[b-1] item[b); item[b] = t; No código anterior, item é um ponteiro para uma matriz de caracteres a ser ordenada e count é o número de elementos da matriz. A ordenação bolha é dirigida por dois laços. Dado que existem count elementos na matriz, o laço mais externo faz a matriz ser varrida count-l vezes. Isso garante que, na pior hipótese, todo elemento estará na posição correta quando a função terminar. O laço mais interno faz as comparações c as trocas. (Uma versão ligeiramente melhorada da ordenação bolha termina se não ocorre nenhuma troca, mas isso acrescenta uma outra comparação a cada passagem pelo laço interno.) Essa versão da ordenação bolha pode ser utilizada para ordenar uma matriz de caracteres em ordem ascendente. Por exemplo, o programa seguinte ordena uma string digitada no teclado. !*Sort Driver*/ tinclude finclude tinclude void bubble(char *item, int count); “a 44 $ “ ,6 Cap. 19 DS Brdeliaçõõo Postal SS void main(void) í char s[80]; printf ("Digite uma string:"); gets(s); bubble(s, strlents)); printf("A string ordenada é: &s.in”, s); Para ver como funciona a ordenação bolha, assuma que a matriz a ser ordenada contenha dcab. Cada passo é mostrado aqui: inicial dcab passo 1 ad ocb passo 2 abadc passo 3 abcad Ao analisar qualquer ordenação, você deve determinar quantas com- parações e trocas serão realizadas para o menor, médio e pior casos. Com a ordenação bolha, o número de comparações é sempre o mesmo, porque os dois laços for repetem o número especificado de vezes, estando a lista inicialmente ordenada ou não. Isso significa que a ordenação bolha sempre executa 1% Lu — 1) comparações, onde n é o número de elementos a ser ordenado. Essa fórmula deriva do fato de que o laço mais externo executa n —1 vezes e o laço mais interno n/2 vezes. Multiplicando-se um pelo outro obtemos a fórmula anterior. O número de trocas é zero, para o melhor caso, em uma lista já ordenada. O número de trocas para 0 caso médio e o pior caso são médio Y(n2 -n) pior Yu? 0) Está fora do escopo deste livro explicar a origem das fórmulas anteriores, mas você pode observar que, à medida que a lista se torna menos ordenada, o número de elementos fora de ordem se aproxima do número de comparações. (Lembre-se de que, na ordenação bolha, existem três trocas para cada elemento fora de ordem.) Essa é uma ordenação n-guadrado, pois seu tempo de execução é um múltiplo do quadrado do número de elementos. Esse tipo de algoritmo é muito ineficiente quando aplicado a um grande número de elementos, porque o tempo de execução está diretamente relacionado com o número de comparações e trocas. Por exemplo, ignorando o tempo que leva para trocar qualquer elemento fora 506 Vs C— Câmpleto tia 0 LO CMS Cap19 da posição, assuma que cada comparação leva 0,001 segundos. Para ordenar 10 elementos, são gastos 0,05 segundos, para ordenar 100 elementos, serão gastos 5 segundos, e ordenar 1.000 elementos, tomará 500 segundos. Uma ordenação de 100.000 elementos, o tamanho de uma pequena lista telefônica, levaria em torno de 5.000.000 segundos ou 1.400 horas ou por volta de dois meses de ordenação contínua! A Figura 19.1 mostra como o tempo de execução aumenta com relação ao tamanho da matriz. Tempo de Execução 1 Figura 19.1 Tempo de execução denmaoidenáção ntemirelação ão iamanhé da matriz, Você pode fazer ligeiras melhorias na ordenação bolha para que ela fique mais rápida. Por exemplo, a ordenação bolha tem uma peculiaridade: um ele- mento fora de ordem na “extremidade grande” (como o “a” no exemplo deab) irá para a sua posição correta em um passo, mas um elemento desordenado na “extremidade pequena” (como o “d”) subirá vagarosamente para seu lugar apro- priado. [sso sugere uma melhoria na ordenação bolha. Em vez de sempre ler a matriz na mesma direção, pode-se inverter a direção entre passos subsegiientes. Dessa forma, elementos muito fora do lugar irão mais rapidamente para suas posições corretas. Essa versão da ordenação bolha é chamada de ordenação osci- lante, devido ao seu movimento de vaivém sobre a matriz. f* A ordenação oscilante. */ void shaker (char *item, int count) Cap. 19 , * Drdctaçãoo peilisa É DEDO GNL 507 register int a; int exchange; char t; do ( exchange = 0; for (a=count-1; a>0; --a) ( if(item[a-l]>item[a]) ( t = item[a-1); item[a-1] — item[al; item[a] = t; exchange - 1; ) for (a=1; aitem[al) ( t = item[a-1); item[a-1] = item[a); item[a] = t; exchange = : 3 ) while(exchange); /*ordena até que não existam mais trocas*/ : Embora a ordenação oscilante seja uma melhoria da ordenação bolha, ela ainda é exccutada na ordem de um algoritmo »-guadrado, porque o número de com- parações não foi alterado e o número de trocas foi reduzido de uma constante relativamente pequena. A ordenação oscilante é melhor que a ordenação bolha, mas existem ordenações ainda melhores. Ordenação por Seleção A ordenação por seleção seleciona o elemento de menor valor e troca-o pelo primeiro elemento. Então, para os 1-1 elementos restantes, é encontrado o ele- mento de menor chave, trocado pelo segundo elemento e assim por diante. As trocas continuam até os dois últimos elementos. Por exemplo, se o método de seleção fosse utilizado na matriz bdac, cada passo se apresentaria como: inicial bad ac passo 1 ad be passo 2 a bad c passo 3 abcd 508 : LA C 4 Completo É Tó Fo é 822.85 % Cópia O código a seguir mostra uma ordenação por seleção simples. /* A ordenação por seleção. */ void select(char *item, int count) f register int a, b, c; int exchange; char t; for(a=0; a=0 && t=0; j=j-gap) item[j+gapl = item[jl; itemlj+gapl = x; ) Você deve ter observado que o laço for mais interno tem duas condições de teste. A comparação x=0 evita que os limites da matriz item sejam ultrapassados. Essas verificações extras degenerarão até certo ponto o desempenho da ordena- ção Shell. Versões um pouco diferentes da ordenação Shell empregam elementos especiais de matriz, chamados sentinelas, que não fazem parte realmente da ma- triz a ser ordenada. Sentinclas guardam valores especiais de terminação, que in- dicam o menor e o maior elemento possível. Dessa forma, as verificações dos limites são desnecessárias. No entanto, usar sentinelas requer um conhecimento específico dos dados, o que limita a gencralização da função de ordenação. A análise da ordenação Shell apresenta alguns problemas matemáticos que estão além do objetivo desta discussão. O tempo de execução é proporcional a 12 n para sc ordenar n elementos. Essa é uma redução significativa com relação às ordenações n-quadrado. Para entender o quanto essa ordenação é melhor, ob- serve a Figura 19.3, que mostra os gráficos das ordenações nº en!2 Porém, antes de se decidir pela ordenação Shell, você deve saber que a ordenação quicksort é ainda melhor. s : us A Cap. 19 « a Ás . a 513 g F x á 8 & 5 Ê Figura 19,3 Ascurvasent. DDS 9 4 9 dedos º 7 a rem . . + Quicksort A quicksort, inventada e denominada por C.A.R. Hoare, é superior a todas as outras ordenações deste livro, e geralmente é considerada o melhor algoritmo de ordenação de propósito geral atualmente disponível. É bascada no método de ordenação por trocas. Isso é surpreendente, quando se considera o terrível desempenho da ordenação bolha! A quicksort é bascada na idéia de partições. O procedimento geral é selecionar um valor, chamado de comparando, e, então, fazer a partição da matriz em duas seções, com todos os elementos maiores ou iguais ao valor da partição de um lado e os menores do outro. Esse processo é repetido para cada seção restante até que a matriz esteja ordenada. Por exemplo, dada a matriz fedacb e usando o valor d para a partição, o primeiro passo da quicksort rearranja a matriz como seguc: início fedacb passol bcadef Esse processo é, então, repetido para cada seção — isto é, bca c def. Como você pode ver, o processo é essencialmente recursivo por natureza e, certamente, as implementações mais claras da quicksort são algoritmos recursivos. 514 : C = Completo e Total PR Éap.19 Você pode selecionar o valor do comparando intermediário de duas for- mas. Você pode escolhê-lo aleatoriamente ou selecioná-lo fazendo a média de um pequeno conjunto de valores retirado da matriz. Para uma ordenação ótima, você deveria selecionar um valor que estivesse precisamente no centro da faixa de valores. Porém, isso não é fácil para a maioria dos conjuntos de dados. No pior caso, o valor escolhido está em uma extremidade e, mesmo nesse caso, quick- sort ainda tem um bom rendimento. A versão seguinte da quicksort seleciona o elemento intermediário da matriz. Embora isso nem sempre resulte em uma boa escolha, a ordenação ainda é efetuada corretamente. !* Função de inicialização da Quicksort. */ void quick(char *item, int count) f gs(item, O, count-1) /* A Quicksort. */ void qgs(char *item, int left, int right) register int i, j; char x, y; i = left; j = right; x = item[(left+right)/2]; do while(item[illeft) j--; if(i0 && j>left) j--; if(i0 && j>left) j--; ifti + wnile(i mo sq % 2% 4*ctcimiottadE SO Css tinclude tinclude gdefine NUM ELEMENTS 4 /* Esse é um número arbitrário que deve ser determinado dinamicamente para cada lista.*/ struct address ( char name [30]; char street [40]; char city [20]; char state[3]; char zip[11]; jainfo; struct address addrs [NUM ELEMENTS] = ( "A, Alexander", "101 lst St”, “Olney”, “Ga", "55555", "B. Bertrand”, "22 2nd Ave", "Oakland", "Pa", "34232", "C. Carlisle”, “33 3rd Elvd”, "ava", "Or", "92000", "D. Dodger", "4 Fourth Dr", "Fresno", "Mi", "45678" J; void quick disk(FILE *fp, int count); void qs disk(FILE *fp, int left, int right); void swap all fields(FILE *fp, long à, long 5); char *get zip(FILE *fp, long rec); void maintvoid) f FILE *fp; /* primeiro, crie um arquivo para ser ordenado */ if((fp-=fopen ("mlist”, “wb"))==NULL) ( printf ("O arquivo não pode ser aberto para escrita.in'"); exit (1); : printf ("Gravando dados não ordenados para disco. in"); fwrite (addrs, sizeof (addrs), 1, fp); fclose (fp); !* agora, ordene o arquivo */ if((fp=fopen("mlist", "rb+"))==NULL) ( printf ("O arquivo não pode ser aberto para leitura/escrita. Mn"); exit (1); , fprintf ("Ordenando arquivo de disco. An"); Cap. 19 NR Ordendição é pasquisa * * quick disk(fp, NUM ELEMENTS) ; fclose(fp); printf(“Lista ordenada. in"); ) /* Um quicksort para arquivos. */ void quick disk(FILE *fp, int count) ( as disk(fp, 0, count-1); ) void gs disk(FILE *fp, int left, int right) f long int i, 5; char x[100]; i = left; j=right; strcpy(tx, get zipí(fp, (long) (i+j)/2)); /* obtém o CEP inter- mediário */ do ( while(strcemp(get zip(fp,i),x)0 && j>left) j--; if(ic=3) swap all fields(fp, i, 5); i++; j--: ) ) whiletiitem[mid]) low = mid+1; else return mid; /* encontrou */ return -
Até o momento nenhum comentário
Esta é apenas uma pré-visualização
3 mostrados em 25 páginas