Classificação Ordenação de Dados Marco Antonio Montebello Júnior marco.antonio@aes.edu.br...

Preview:

Citation preview

ClassificaçãoOrdenação de Dados

Marco Antonio Montebello Júniormarco.antonio@aes.edu.br

Ordenação e Pesquisa de Dados

Ordenação dos dados

Facilitar e aumentar a eficiência das operações de pesquisa sobre esses dados

Pode ser crescente ou decrescente A seqüência de entrada, normalmente, é um

vetor com n elementos Outras possibilidades de estruturas de dados

como por exemplo, uma lista encadeada

Ainda mais...

Na prática os números a serem ordenados, raramente, são valores isolados

Normalmente, cada número é componente de um conjunto de dados denominado registro

E o conjunto de registros forma uma tabela Cada registro contém uma chave, que é o valor a ser ordenado,

e demais valores que sempre acompanham a chave Numa operação de ordenação, sempre que for preciso trocar a

posição de uma chave, será necessário alterar a posição de todos os elementos do registro

Na prática, quando os registros possuem uma grande quantidade de dados (além da chave), a ordenação é realizada sobre um vetor (ou lista) de ponteiros para os registros, com o objetivo de minimizar as operações de movimentação de dados

ExemplosContigüidade Física

Tabela não ordenada Tabela ordenada

Reg Chave Outros campos1 3 xxx xxx xxx2 7 yyy yyy yyy3 5 zzz zzz zzz4 1 kkk kkk kkk5 4 ttt ttt ttt6 2 uuu uuu uuu

Reg Chave Outros campos1 1 kkk kkk kkk2 2 uuu uuu uuu3 3 xxx xxx xxx4 4 ttt ttt ttt5 5 zzz zzz zzz6 7 yyy yyy yyy

As entradas são fisicamente rearranjadas (todos os elementos de um registro são ordenados fisicamente)

ExemploVetor Indireto de Ordenação As entradas são mantidas nas posições originais. A seqüência é

dada por um vetor gerado durante o processo de classificação (não envolve movimentação dos registros em uma tabela).

Tabela desordenada Vetor de ordenação

Reg Chave Outros campos1 3 xxx xxx xxx2 7 yyy yyy yyy3 5 zzz zzz zzz4 1 kkk kkk kkk5 4 ttt ttt ttt6 2 uuu uuu uuu

Índice da tabela1 42 63 14 55 36 2

ExemploEncadeamento As entradas são mantidas nas posições originais. É formada uma lista encadeada com a ordenação. Utiliza-se um

campo a mais na tabela para armazenamento da lista, e não mais o vetor adicional (vetor indireto de ordenação). É preciso utilizar um ponteiro para o primeiro elemento

Reg. Chave Demais Campos Próx.1 3 xxx xxx xxx xxx xxx xxx 52 7 yyy yyy yyy yyy yyy yyy -3 5 zzz zzz zzz zzz zzz zzz 24 1 kkk kkk kkk kkk kkk kkk 65 4 ttt ttt ttt ttt ttt ttt 36 2 uuu uuu uuu uuu uuu uuu 1

4Ponteiro para o primeiro elemento da tabela (reg. 4 contém chave 1)

Ordenação Interna versus Ordenação Externa A ordenação interna é utilizada num conjunto de dados

pequeno Neste caso a ordenação pode ser realizada inteiramente

(ou quase inteiramente) na memória principal A ordenação externa é utilizada num conjunto de dados

grandes A conseqüência é que a ordenação não pode ser

realizada na memória principal Nesse caso a ordenação é realizada sobre dados

armazenados na memória secundária (disco, fita, etc.)

Principais métodos de ordenação interna Ordenação por Inserção

Inserção Direta Incrementos Decrescentes (Shell Sort)

Ordenação por Troca Método da Bolha (Bubble Sort) Método da Troca e Partição (Quicksort)

Ordenação por Seleção Seleção Direta Seleção em Árvore (Heapsort)

Ordenação por Inserção

Nesse método os elementos são inseridos em sua posição correta, em relação aos elementos já classificados

Duas possibilidades : Inserção Direta Método Shell

Inserção Direta

É o método mais simples Utilizado para um conjunto pequeno de dados Possui baixa eficiência Nesse método o vetor a ser ordenado é dividido

em dois segmentos: O primeiro segmento contém os elementos já

ordenados; O segundo segmento contém os elementos a serem

ordenados

Algoritmo – Inserção Direta

Primeiro elemento está no vetor ordenado e os demais no vetor desordenado;

Retirar o primeiro elemento do vetor desordenado e colocá-lo no vetor ordenado, na sua posição correta;

Repetir o processo para todos os elementos do vetor desordenado.

Algoritmo – Inserção DiretaConst

TAM = 10Tipos

v = vetor[1..TAM] de inteiros +-------------------------+Var | Exemplo: |

vet: v | | i, j, k, temp: inteiro | 5 | 2 3 4 8 7 | achei: lógico | 2 5 | 3 4 8 7 |

| 2 3 5 | 4 8 7 | Início | 2 3 4 5 | 8 7 |

Para i = 1 até TAM Faça | 2 3 4 5 8 | 7 | leia (vet[i]) | 2 3 4 5 7 8 ||

Fim-Para +-------------------------+Para i = 2 até TAM Faça

j = 1achei = FALSOEnquanto (j < i) E (NÃO achei) Faça /* Compara o */

Se vet[i] < vet[j] Então /* vet[i] com */achei = VERDADEIRO /* os que estão */

Senão /* à sua */j = j + 1 /* esquerda */

Fim-SeFim-EnquantoSe achei Então

temp = vet[i]k = i - 1Enquanto k >= j Faça /* Desloca o */

vet[k+1] = vet[k] /* vetor para */k = k – 1 /* a direita */

Fim-Enquantovet[j] = temp

Fim-SeFim-Para

Fim.

Algoritmo – Outra versãoConst

TAM = 10Tipos

v = vetor[1..TAM] de inteiros Var

vet: v i, j, k, temp: inteiro achei: lógico

Início Para i = 1 até TAM Faça

leia (vet[i]) Fim-ParaPara j = 2 até TAM Faça

chave = vet[j]i = j - 1Enquanto (i > 0) E (vet[i] > chave) Faça

vet[i + 1] = vet[i]i = i - 1

Fim-Enquantovet[i+1] = chave

Fim-ParaFim.

Incrementos Decrescentes (Shell Sort) Proposto por Ronald L. Shell (1959) É uma extensão do algoritmo de inserção direta A diferença com relação à inserção direta é o

número de segmentos do vetor Na inserção direta é considerado um único

segmento do vetor onde os elementos são inseridos ordenadamente

No método do Shell são considerados diversos segmentos

Descrição do Método Shell Sort

A ordenação é realizada em diversos passos. A cada passo está associado um incremento I, o qual determina os elementos que pertencem a cada um dos segmentos: segmento 1 - vet[1], vet[1 + I], vet[1 + 2I], ... segmento 2 - vet[2], vet[2 + I], vet[2 + 2I], ... ... segmento k - vet[k], vet[k + I], vet[k + 2I], ...

Descrição do Método Shell Sort A cada passo todos os elementos (segmentos) são

ordenados isoladamente por inserção direta. No final de cada passo o processo é repetido para um

novo incremento I igual a metade do anterior, até que seja executado um passo com incremento I = 1.

O valor do incremento I é sempre uma potência inteira de 2. O valor do incremento inicial é dado por 2**NP, onde NP é o número de passos para ordenar o vetor (fornecido pelo usuário, NP é uma aproximação inicial).

Assim, para NP = 3 o valor do incremento em cada passo seria: I = 2 ** 3 = 8 (23) I = 2 ** 2 = 4 (22) I = 2 ** 1 = 2 (21) I = 2 ** 0 = 1 (20)

Exemplo: NP = 2

1 5 9 2 6 10 3 7 11 4 8 1215 19 50 27 20 41 40 45 25 13 35 10

1 2 3 4 5 6 7 8 9 10 11 1215 27 40 13 19 20 45 35 50 41 25 10

15 19 50 20 27 41 25 40 45 10 13 35

Vetor original (Desordenado)

Primeiro passo: I = 2 ** NP = 4 (22)

Aplicando inserção direta em cada segmento

Obtém-se o vetor

1 2 3 4 5 6 7 8 9 10 11 1215 20 25 10 19 27 40 13 50 41 45 35

Exemplo: NP = 2

1 3 5 7 9 11 2 4 6 8 10 1215 25 19 40 50 45 20 10 27 13 41 35

15 19 25 40 45 50 10 13 20 27 35 41

1 2 3 4 5 6 7 8 9 10 11 1215 10 19 13 25 20 40 27 45 35 50 41

Segundo passo: I = I DIV 2 = 2 (I/2) ou NP = NP - 1, I = 2 ** NP = 2 (21)

Segmento 1 Segmento 2

Aplicando inserção direta em cada segmento:

Obtém-se o vetor

Exemplo: NP = 2

Terceiro passo: I = I DIV 2 = 1ou: NP = NP - 1, I = 2 ** NP = 1 (20)

Nesse último passo os elementos estão próximos das suas posições finais, o que leva a um menor número de trocas.

Aplicando inserção direta ao vetor obtido no passo anterior obtém-se o vetor ordenado:

1 2 3 4 5 6 7 8 9 10 11 1210 13 15 19 20 25 27 35 40 41 45 50

Algoritmo do Método ShellConst TAM = 12Tipos v = vetor[1..TAM] de inteirosVar vet: v

np, i, j, inc : inteiro Início

Para i = 1 até TAM Faça Leia (vet[i]) Fim-Para

Leia (np)

Para i = np até 0 Passo -1 Façainc = 2 ** i //2i

Para j = 1 até inc FaçaMétodo_Shell (vet, inc, j, TAM)Fim-ParaFim-Para

Fim.

Algoritmo do Método ShellProcedimento Método_Shell (Ref vet, r, s, n)InícioVar

i, j, k, temp: inteiroachei: lógicoPara i = (s + r) até n passo r Faça

j = sachei = FALSOEnquanto (j < i) E (NÃO achei) Faça

Se vet[i] < vet[j] Entãoachei = VERDADEIRO

Senãoj = j + r

Fim-SeFim-EnquantoSe achei Então

temp = vet[i]k = i + rEnquanto k > (j - r) Faça

vet[k + r] = vet[k]k = k - r

Fim-Enquantovet[j] = temp

Fim-SeFim-Para

Fim-Método_Shell

Ordenação por Troca

Durante o caminhamento no vetor, se dois elementos são encontrados fora de ordem, suas posições são trocadas

São realizadas comparações sucessivas de pares de elementos

A estratégia de escolha dos pares de elementos estabelece a diferença entre os dois métodos de ordenação por troca.

Dois métodos principais: Método da Bolha (Bubble Sort) Método da Partição (Quick Sort)

Método da Bolha (Bubble Sort)

É um método bastante simples, porém lento O nome bolha se deve ao fato de que os valores

flutuam até a sua correta posição como bolhas O algoritmo é o seguinte:

A cada passo, cada elemento é comparado com o próximo. Se o elemento estiver fora de ordem, a troca é realizada;

Realizam-se tantos passos quantos necessários até que não ocorram mais trocas.

Obs.: Logo no primeiro passo o maior valor vai para o fim

Exemplo do Mecanismo do Método Bolha 500 85 515 60 910 170 890 275 650 430

Passo 1: 85 500 60 515 170 910 890 910 275 910 650 910 430 910 85 500 60 515 170 890 275 650 430 910Passo 2: 85 60 500 170 515 275 650 430 890 910Passo 3: 60 85 170 500 275 515 430 650 890 910Passo 4: 60 85 170 275 500 430 515 650 890 910Passo 5: 60 85 170 275 430 500 515 650 890 910Passo 6: nenhuma troca

Algoritmo do Método Bolha/*Nesse algoritmo, a cada passo, a variável k contém a última posição trocada.

Após esta, todas já estão classificadas.*/Const

TAM = 20Tipos

v = vetor[1..TAM] de inteirosVar

vet: vi, temp, lim, k: inteirotroca: lógico

InícioPara i = 1 até TAM Faça

Leia (vet[i]) Fim-Para troca = VERDADEIROlim = TAM - 1Enquanto troca Faça

troca = FALSOPara i = 1 até lim Faça

Se vet[i] > vet[i + 1] Entãotemp = vet[i]vet[i] = vet[i + 1]vet[i + 1] = tempk = itroca = VERDADEIRO

Fim-SeFim-paralim = k

Fim-EnquantoFim.

Método da Troca e Partição (Quick Sort) É o mais rápido entre os métodos apresentados

até o momento E também o mais utilizado Foi proposto por C. A. R. Hoare em 1962 Parte do princípio que é mais rápido classificar

dois vetores com n/2 elementos cada um, do que um com n elementos (dividir um problema maior em dois menores)

Descrição do Método Quick Sort

A parte mais delicada do método é o particionamento do vetor

O vetor é particionado em três segmentos: V[1], ..., V[i - 1] V[i] V[i + 1], ..., V[n] (segmento 1) (segmento 2) (segmento 3)

A partição é realizada através da escolha arbitrária de um elemento (V[i]) de modo que os elementos no segmento 1 sejam menores, e os elementos no segmento 3 sejam maiores do que o elemento escolhido V[i]

Descrição do Método Quick Sort

Após a ordenação dos segmentos 1 e 3, tem-se o vetor original classificado. O processo de partição pode ser repetido para os segmentos 1 e 3

Obs.: Quando um segmento apresenta um número de elementos menor ou igual a M (um número pré-estabelecido), aplica-se um método simples de ordenação

Algoritmo do Quick Sort Escolher arbitrariamente um elemento do vetor

(normalmente o meio) e colocá-lo em uma variável auxiliar X;

Inicializar dois ponteiros I e J (I = 1 e J = n); Percorrer o vetor a partir da esquerda até que se

encontre um V[I] >= X (incrementando o valor de I); Percorrer o vetor a partir da direita até que se encontre

um V[J] <= X (decrementando o valor de J); Trocar os elementos V[I] e V[J] (estão fora de lugar) e

fazer: I = I + 1 e J = J - 1; Continuar esse processo até que I e J se cruzem em

algum ponto do vetor; Após obtidos os dois segmentos do vetor através do

processo de partição, cada um é ordenado recursivamente

Quicksort – Exemplo (1)

Quicksort – Exemplo (2)

Quicksort – Exemplo (3)

Quicksort – Exemplo (4)

Quicksort – Exemplo (5)

Quicksort – Exemplo (6)

Quicksort – Animação

Algoritmo em pseudocódigoProcedimento QuickSort (esq, dir: inteiro)Início

Varx, i, j, aux: inteiroi = esqj = dirx = v[(i + j) DIV 2]Repita //FaçaEnquanto x > v[i] Façai = i + 1Fim-EnquantoEnquanto x < v[i] Façaj = j - 1Fim-EnquantoSe i <= j Entãoaux = v[i]v[i] = v[j]v[j] = auxi = i + 1j = j - 1Fim-SeAté Que i > j //Enquanto i < jSe esq < j EntãoQuickSort (esq, j)Fim-SeSe dir > i EntãoQuickSort (i, dir)Fim-Se

Fim.

Ordenação por Seleção

É realizada uma seleção sucessiva do menor (ou maior) valor contido no vetor

A cada passo este menor (maior) valor é colocado na sua posição correta

Repete-se o processo para o segmento que contém os elementos não selecionados

Duas possibilidades: Seleção direta Seleção em árvore

Seleção Direta

A cada passo encontra-se o menor elemento dentro do segmento com os elementos não selecionados;

Troca-se este elemento com o primeiro elemento do segmento;

Atualiza-se o tamanho do segmento (menos um elemento);

Este processo é repetido até que o segmento fique com apenas um elemento

Exemplo

19 25 10 18 35 17 15 13 TAM = 810 25 19 18 35 17 15 13 TAM = 710 13 19 18 35 17 15 25 TAM = 610 13 15 18 35 17 19 25 TAM = 510 13 15 17 35 18 19 25 TAM = 410 13 15 17 18 35 19 25 TAM = 310 13 15 17 18 19 35 25 TAM = 210 13 15 17 18 19 25 35 TAM = 1

Algoritmo da Seleção DiretaConst

TAM = 15Tipos

v = vetor[1..TAM] de inteirosVar

vet: vi, j, temp, pos_menor: inteiro

InícioPara i = 1 até TAM FaçaLeia (vet[i])Fim-ParaPara i = 1 até TAM - 1 Façapos_menor = iPara j = i + 1 até TAM FaçaSe vet[j] < vet[pos_menor] Entãopos_menor = jFim-SeFim-Paratemp = vet[i]vet[i] = vet[pos_menor]vet[pos_menor] = tempFim-Para

Fim.

Seleção em Árvore (Heap Sort)

Utiliza uma estrutura de árvore binária para a ordenação

A ordenação é realizada em duas fases

Seleção em Árvore (Heap Sort)Fase 1 Monta-se uma árvore binária (heap) contendo todos os

elementos do vetor de forma que o valor contido em qualquer nodo seja maior do que os valores de seus sucessores. A árvore binária é estruturada no próprio vetor da seguinte forma: sucessor à esquerda de i: 2i + 1 (se 2i + 1 < n) sucessor à direita de i: 2i + 2 (se 2i + 2 < n)

Transformação da árvore num heap: é realizada do menor nível até a raiz, trocando-se cada nodo com o maior de seus sucessores imediatos. Repete-se este processo até cada nodo ser maior que seus sucessores imediatos

Seleção em Árvore (Heap Sort)Fase 2 Após a formação do heap segue-se a fase de

classificação propriamente dita, na qual o valor que está na raiz da árvore (maior valor contido na árvore) é colocado na sua posição correta, trocando-o com o elemento de maior índice da árvore (a árvore fica com 1 elemento a menos).

Este novo elemento colocado na raiz pode violar a propriedade do heap, de modo que deve-se restaurar o heap novamente. Este procedimento é repetido até que a árvore fique com um único elemento.

Exemplos de Heaps

98

66 10

98

10 66

98

80 66

112444

32

98

98 66

Exemplos de Não Heaps

98

12 66

112444

78

66

98 10

Heap – Exemplo (1)

Entrada: Heap:

Heap – Exemplo (2)

Heap – Exemplo (3)

Heap – Exemplo (4)

Heap – Exemplo (5)

Comparação entre os Métodos

São apresentados quadros comparativos do tempo gasto na ordenação de vetores com 500, 5000, 10000 e 30000 elementos, organizados de forma aleatória, em ordem crescente (1, 2, 3, 4, ..., n) e em ordem decrescente (n, n-1, n - 2, ..., 1)

Em cada tabela, o método que levou menos tempo para realizar a ordenação recebeu o valor 1 e os demais receberam valores relativos ao mais rápido (valor 1)

Comparação entre os Métodos500 5000 10000 30000

Inserção 11.3 87 161 -Shell 1.2 1.6 1.7 2Quick 1 1 1 1Seleção 16.2 124 228 -Heap 1.5 1.6 1.6 1.6

500 5000 10000 30000Inserção 1 1 1 1Shell 3.9 6.8 7.3 8.1Quick 4.1 6.3 6.8 7.1Seleção 128 1524 3066 -Heap 12.2 20.8 22.4 24.6

500 5000 10000 30000Inserção 40.3 305 575 -Shell 1.5 1.5 1.6 1.6Quick 1 1 1 1Seleção 29.3 221 417 -Heap 2.5 2.7 2.7 2.9

Ordem Aleatória Ordem Ascendente Ordem Descendente

Recomendações

Tamanho <= 50 Inserção Tamanho <= 5000 Shell Sort Até 1000 elementos o Shell é mais vantajoso Tamanho > 5000 Quick Sort

Necessita de memória adicional por ser recursivo. Evitar chamadas recursivas para pequenos intervalos. Colocar um teste antes da recursividade (se n <= 50 inserção; se n <= 1000, shell sort)

Heap Sort De 2 a 3 vezes mais lento que o quick sort. Seu tempo é sempre

n log n, não importando a ordem dos elementos. Esse método deve ser utilizado quando as aplicações não podem tolerar eventuais variações no tempo esperado para ordenação

Recommended