Classificação Ordenação de Dados
-
Upload
harper-johnston -
Category
Documents
-
view
39 -
download
0
description
Transcript of Classificação Ordenação de Dados
ClassificaçãoOrdenação de Dados
Marco Antonio Montebello Jú[email protected]
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 campos
1 3 xxx xxx xxx
2 7 yyy yyy yyy
3 5 zzz zzz zzz
4 1 kkk kkk kkk
5 4 ttt ttt ttt
6 2 uuu uuu uuu
Reg Chave Outros campos
1 1 kkk kkk kkk
2 2 uuu uuu uuu
3 3 xxx xxx xxx
4 4 ttt ttt ttt
5 5 zzz zzz zzz
6 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 campos
1 3 xxx xxx xxx
2 7 yyy yyy yyy
3 5 zzz zzz zzz
4 1 kkk kkk kkk
5 4 ttt ttt ttt
6 2 uuu uuu uuu
Índice da tabela
1 4
2 6
3 1
4 5
5 3
6 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 5
2 7 yyy yyy yyy yyy yyy yyy -
3 5 zzz zzz zzz zzz zzz zzz 2
4 1 kkk kkk kkk kkk kkk kkk 6
5 4 ttt ttt ttt ttt ttt ttt 3
6 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ão
ConstTAM = 10
Tiposv = 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 12
15 19 50 27 20 41 40 45 25 13 35 10
1 2 3 4 5 6 7 8 9 10 11 12
15 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 12
15 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 12
15 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 12
15 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 12
10 13 15 19 20 25 27 35 40 41 45 50
Algoritmo do Método Shell
Const 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: inteiro
i = esqj = dirx = v[(i + j) DIV 2]Repita //Faça
Enquanto x > v[i] Façai = i + 1
Fim-EnquantoEnquanto x < v[i] Faça
j = j - 1Fim-EnquantoSe i <= j Então
aux = v[i]v[i] = v[j]v[j] = auxi = i + 1j = j - 1
Fim-SeAté Que i > j //Enquanto i < jSe esq < j Então
QuickSort (esq, j)Fim-SeSe dir > i Então
QuickSort (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 = 8
10 25 19 18 35 17 15 13 TAM = 7
10 13 19 18 35 17 15 25 TAM = 6
10 13 15 18 35 17 19 25 TAM = 5
10 13 15 17 35 18 19 25 TAM = 4
10 13 15 17 18 35 19 25 TAM = 3
10 13 15 17 18 19 35 25 TAM = 2
10 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ça
Leia (vet[i])Fim-ParaPara i = 1 até TAM - 1 Faça
pos_menor = iPara j = i + 1 até TAM Faça
Se vet[j] < vet[pos_menor] Entãopos_menor = j
Fim-SeFim-Paratemp = vet[i]vet[i] = vet[pos_menor]vet[pos_menor] = temp
Fim-ParaFim.
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étodos
500 5000 10000 30000
Inserção 11.3 87 161 -
Shell 1.2 1.6 1.7 2
Quick 1 1 1 1
Seleção 16.2 124 228 -
Heap 1.5 1.6 1.6 1.6
500 5000 10000 30000
Inserção 1 1 1 1
Shell 3.9 6.8 7.3 8.1
Quick 4.1 6.3 6.8 7.1
Seleção 128 1524 3066 -
Heap 12.2 20.8 22.4 24.6
500 5000 10000 30000
Inserção 40.3 305 575 -
Shell 1.5 1.5 1.6 1.6
Quick 1 1 1 1
Seleçã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 <= 5000Shell 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