Ordenação
Prof. Leandro C. Fernandes
Estruturas de Dados
Introdução
Definição (Dic. Aurélio):
– Pôr em ordem; arrumar,
– Organização dos elementos de um conjunto de acordo com uma relação de ordem com a qual se atribui, em geral, a todo elemento, um antecedente e um sucessor.
Importância da ordenação ou classificação de dados em atividades rotineiras:
– Livros numa biblioteca
– Agenda e catálogos telefônicos
– Dicionários
– Arquivos com cadastro de funcionários, ...
Princípios da Ordenação
Considerando 3 elementos a, b, c e < com o significado de precedência, temos:
1) Princípio da triconomia
a < b, a=b, b < a 2) Princípio da transitividade
Se a < b e b < c então a < c
Ordenação
Computadores gastam mais tempo ordenando do que fazendo qualquer outra coisa.
A ordenação aparece em muitos problemas na prática e, portanto, servem de base para a
construção de muitos algoritmos.
Entendendo a ordenação, tem-se conhecimento para resolver outros problemas.
– Muitas das idéias usadas no projeto de algoritmos
aparecem no contexto de ordenação, tais como divisão e conquista, estruturas de dados e algoritmos
randomizados.
– É um dos problema mais estudado em CC.
Compromisso
“A complexidade da ordenação da estrutura de dados não deve exceder a complexidade da
computação a ser feita na estrutura sem o processo de ordenação”
Ex: Deseja-se realizar uma única pesquisa num vetor
– busca seqüencial ⇒ O(n)
– ordenação ⇒ O(n log n)
● Não vale a pena ordenar!
Aplicações da Ordenação
Busca
– Uma busca binária em um dicionário com os dados ordenados leva tempo O(log n).
● Provavelmente esta seja a mais simples e importante aplicação da ordenação.
Par mais próximo
– Dado um conjunto de n números, como encontrar o par de números cuja diferença entre eles seja a menor
possível?
● Com os números ordenados a solução é simples.
● Solução em tempo O(n log n).
Aplicações da Ordenação
Unicidade de elementos
– Dado um conjunto de n elementos, existem elementos duplicados?
● Novamente, a melhor solução possível usa a ordenação.
● É um caso particular do problema do par mais próximo em que a diferença entre vizinhos é zero.
Distribuição de freqüência
– Dado um conjunto de n elementos, qual
elemento ocorre o maior número de vezes?
Aplicações da Ordenação
Seleção
– Qual o k-ésimo maior elemento no conjunto?
● Com os dados ordenados, esta informação é determinada em tempo constante.
● Em particular, a mediana (o n/2-ésimo elemento).
Casco convexo
– Dado um conjunto de n pontos no plano cartesiano, qual o polígono convexo de menor área que contém todos estes pontos?
● Os pontos são ordenadas pelas abscissas dos pontos.
● A partir do ponto de menor abscissa, o casco é construído inserindo-se os pontos.
Problema do Casco Convexo
Tipos de Ordenação
Ordenação interna:
– A classificação é feita na estrutura como um todo, geralmente num conjunto pequeno de dados.
– O processo é realizado inteiramente (ou quase) na memória principal.
Ordenação externa:
– A classificação é feita sobre parte de uma grande estrutura.
– É impossível colocar toda a estrutura na memória principal.
– Há necessidade de contar com auxílio de memórias de armazenamento de massa.
Assumindo que ...
Os dados estão mantidos em um vetor (Ordenação Interna)
Um elemento do vetor é:
– um objeto que possui um atributo chave que deve ser mantido ordenado
Um método troca(x,y) realiza a troca dos elementos presentes nas posições x e y do vetor
Para fins de exemplo, números inteiros serão utilizados como elementos
Métodos de Ordenação
Ordenação por troca
– BubbleSort (método da bolha)
– QuickSort (método da troca e partição)
Ordenação por inserção
– InsertionSort (método da inserção direta)
– ShellSort (método de incrementos decrescentes)
Ordenação por seleção
– SelectionSort (método da seleção direta)
– HeapSort (método da seleção em árvore)
Outros métodos
– MergeSort (método da intercalação)
– BucketSort (método da distribuição de chave)
Métodos de Ordenação
Ordenação por troca
– BubbleSort (método da bolha)
– QuickSort (método da troca e partição)
Ordenação por inserção
– InsertionSort (método da inserção direta)
– ShellSort (método de incrementos decrescentes)
Ordenação por seleção
– SelectionSort (método da seleção direta)
– HeapSort (método da seleção em árvore)
Outros métodos
– MergeSort (método da intercalação)
– BucketSort (método da distribuição de chave)
Ordenação por troca
BubbleSort é um método simples de troca
– É um algoritmo fácil, mas muito lento.
– ordena através de sucessivas trocas entre pares de elementos do vetor
Características
– realiza varreduras no vetor, trocando pares adjacentes de elementos sempre que o próximo elemento for menor
que o anterior
– após uma varredura, o maior elemento está corretamente posicionado no vetor e não precisa mais ser comparado
Algoritmo BubbleSort
Em cada passo, cada elemento é comparado com o próximo;
Se o elemento estiver fora de ordem, a troca é realizada;
Realizam-se tantos passos quantos forem necessários até que não ocorram mais
trocas.
Xsortlab.jar
Implementação: BubbleSort
public static void sort(int[] dados) { int n = dados.length;
for(int i = 0; i < n-1; i++)
for(int j = i+1; j <= n-1; j++) if (dados[i] < dados[j]) {
int temp = dados[i];
dados[i] = dados[j];
dados[j] = temp;
} }
Análise de Desempenho
Caso mais favorável é aquele no qual as chaves já se encontram na ordem desejada.
– Na primeira e única varredura o algoritmo faz n - 1 comparações.
Caso mais desfavorável é aquele no qual as chaves estão em ordem inversa da desejada.
– O total de comparações será a soma da progressão
aritmética cujo primeiro termo é 1 e o último n - 1. Isto é, (n2 - n) / 2 comparações.
A estimativa do número médio de comparações é (n2 + n - 2) / 4
Ordenação por Troca
QuickSort é um método de troca elaborado.
– Proposto por Hoare em 1962.
– É um dos mais rápidos métodos de ordenação.
Características:
– Adota o princípio “dividir para conquistar”.
– É mais rápido classificar dois vetores com n/2 elementos do que n elementos.
Algoritmo QuickSort
Um elemento do vetor, geralmente o primeiro ou do meio, é escolhido de forma arbitrária. O elemento é colocado numa variável auxiliar.
O vetor é varrido a partir da esquerda até que se encontre um elemento maior ou igual à variável auxiliar.
O vetor é varrido a partir da direita até que encontre um elemento menor ou igual à variável auxiliar.
É efetuada a troca dos elementos.
O processo é repetido até que os ponteiros se cruzem em algum ponto do vetor.
Xsortlab.jar
Implementação: QuickSort
public static void sort(int[] dados, int left, int right){
int i = left; int j = right;
int x = dados[(left+right)/2]; //Elemento "pivot"
do {
while ((dados[i] < x) && (i < right)) i++;
while ((dados[j] > x) && (j > left)) j--;
if (i <= j) {
swap(dados,i,j); i++; j--;
}
} while (i <= j);
if (left < j) sort(dados,left,j);
if (i < right) sort(dados,i,right);
}
Análise de Desempenho
Em comparação com os demais métodos é o que apresenta, em média, menor tempo de classificação.
Apesar de efetuar uma quantidade de iterações na ordem de n log2 n, é mais rápido por apresentar menor número de operação elementares por iteração.
Métodos de Ordenação
Ordenação por troca
– BubbleSort (método da bolha)
– QuickSort (método da troca e partição)
Ordenação por inserção
– InsertionSort (método da inserção direta)
– ShellSort (método de incrementos decrescentes)
Ordenação por seleção
– SelectionSort (método da seleção direta)
– HeapSort (método da seleção em árvore)
Outros métodos
– MergeSort (método da intercalação)
– BucketSort (método da distribuição de chave)
Ordenação por Inserção
InsertionSort é um método simples de inserção
Características:
– considera dois segmentos (sub-vetores) dentro do próprio vetor: ordenado (aumenta) e
não-ordenado (diminui)
– ordena através da inserção de um elemento por vez (primeiro elemento) do segmento
não-ordenado no segmento ordenado, na sua posição correta
Algoritmo InsertionSort
O primeiro elemento do vetor é considerado ordenado e os seguintes desordenados;
Busca-se os elementos do bloco dos desordenados e compara-se com os do bloco de desordenados.
Faz-se a inserção na posição correta.
Repete-se o processo até que os elementos do bloco de desordenados tenham passado para o bloco de ordenados.
Xsortlab.jar
Implementação: InsertionSort
public static void sort(int[] dados) {
for(int i = 1; i < dados.length; i++) { int pos = i;
int temp = dados[i];
while((pos > 0) && (temp < dados[pos-1])){
dados[pos] = dados[pos-1];
pos--;
}
dados[pos] = temp;
} }
Ordenação por Inserção
ShellSort ou Incrementos Decrescentes: é uma extensão do algoritmo de inserção direta
– Diferencia-se por dividir o vetor usado no processo de classificação em vários segmentos (blocos).
Características:
– Algoritmo proposto por Ronald L. Shell (1959)
– O vetor é dividido em i segmentos, de tal forma que cada segmento possua n/i chaves que é classificado
separadamente.
Algoritmo ShellSort
Considerando o vetor V[1..n], o mesmo é dividido em i segmentos;
A cada passo, o valor de i é diminuído pela metade do valor anterior dando origem a novos segmentos (a metade do número anterior).
É aplicado método da ordenação por inserção direta em cada passo e em cada segmento originado.
O processo é repetido até que i = 1. Quando aplicada a ordenação com i =1, o vetor estará classificado.
Funcionamento do ShellSort
Funcionamento do ShellSort
Funcionamento do ShellSort
Implementação: ShellSort
public static void sort(int[] dados) { int gap = 1;
do
gap = 3*gap + 1;
while (gap < dados.length);
do {
gap = gap / 3;
for(int i = gap; i < dados.length; i++) { int value = dados[i];
int j = i - gap;
while ((j >= 0) && (value < dados[j])) { dados [j + gap] = dados[j];
j -= gap;
}
dados [j + gap] = value;
}
} while(gap > 1);
}
Análise de Desempenho
É complexa. Alguns problemas matemáticos relacionados não foram resolvidos, como por
exemplo, determinar o efeito da ordenação de um passo produz nos passos subseqüentes.
Ainda não se conhece exatamente a melhor
seqüência de incrementos para produzir melhores resultados.
É recomendável que o valor inicial do incremento seja um valor que divida o vetor de chaves no maior número possível de segmentos de mais de um
elemento.
Análise de Desempenho
O desempenho do método é quadrático, isto é, o
desempenho esperado na classificação de cada um dos segmentos é de (n/i)2, onde n/i é o número de chaves em i segmentos.
O desempenho da classificação dos i segmentos é em torno de i * (n/i)2, ou seja, n2/i.
É recomendável que o valor inicial do incremento seja um valor que divida o vetor de chaves no maior número possível de segmentos de mais de um
elemento.
Métodos de Ordenação
Ordenação por troca
– BubbleSort (método da bolha)
– QuickSort (método da troca e partição)
Ordenação por inserção
– InsertionSort (método da inserção direta)
– ShellSort (método de incrementos decrescentes)
Ordenação por seleção
– SelectionSort (método da seleção direta)
– HeapSort (método da seleção em árvore)
Outros métodos
– MergeSort (método da intercalação)
– BucketSort (método da distribuição de chave)
Ordenação por Seleção
SelectionSort é um método simples de seleção
Característica:
– ordena através de sucessivas seleções do elemento de menor valor em um segmento
não-ordenado e seu posicionamento no final de um segmento ordenado
– realiza uma busca seqüencial pelo menor valor no segmento não-ordenado a cada iteração
Algoritmo SelectionSort
Procurar o menor elemento do vetor
Trocar com o elemento armazenado na primeira posição do vetor
Reduz o tamanho do vetor em uma unidade, delimitando seu limite inferior em +1
Repetir o passos anteriores até que o vetor alcance tamanho igual a um.
Xsortlab.jar
Implementação: SelectionSort
public static void sort(int[] dados) {
for(int i = 0; i < dados.length-1; i++) { int posMenor = i;
for(int j = i+1; j < dados.length; j++) if (dados[j] < dados[posMenor])
posMenor = j;
if (posMenor != i) { int temp = dados[i];
dados[i] = dados[posMenor];
dados[posMenor] = temp;
} }
}
Análise de Desempenho
Caso mais favorável é aquele no qual as chaves já se encontram na ordem desejada.
– Na primeira e única varredura o algoritmo faz n - 1 comparações.
Caso mais desfavorável é aquele no qual as chaves estão em ordem inversa da desejada.
– O total de comparações será a soma da progressão
aritmética cujo primeiro termo é 1 e o último n - 1. Isto é, (n2 - n) / 2 comparações.
A estimativa do número médio de comparações é (n2 + n - 2) / 4
Métodos de Ordenação
Ordenação por troca
– BubbleSort (método da bolha)
– QuickSort (método da troca e partição)
Ordenação por inserção
– InsertionSort (método da inserção direta)
– ShellSort (método de incrementos decrescentes)
Ordenação por seleção
– SelectionSort (método da seleção direta)
– HeapSort (método da seleção em árvore)
Outros métodos
– MergeSort (método da intercalação)
– BucketSort (método da distribuição de chave)
MergeSort
MergeSort é um algoritmo intercalação
– Fundamenta-se na ordenação por mistura de seqüências já ordenadas.
Características:
– Adota o princípio “dividir para conquistar”.
– Sua idéia básica é que é muito fácil criar uma seqüência ordenada a partir de duas outras também ordenadas.
– Para isso, ele divide a sequência original em pares de dados, ordena-as; depois as agrupa em sequências de quatro elementos, e assim por diante, até ter toda a sequência dividida em apenas duas partes.
Algortimo MergeSort
Dividir os dados em subseqüências pequenas;
Classificar as duas metades recursivamente aplicando o MergeSort;
Juntar as duas metades em um único conjunto já classificado.
Implementação: MergeSort
void MergeSort(int *A, int e, int d){
int q;
if (e < d) {
q = floor((e+d)/2);
MergeSort(A,e,q);
MergeSort(A,q+1,d);
Merge(A,e,q,d);
} }
Links
Mais sobre o assunto:
– http://www.ime.usp.br/~pf/algoritmos/aulas/ordena.html
– http://www.ime.usp.br/~pf/algoritmos/aulas/mrgsrt.html
– http://www.ime.usp.br/~pf/algoritmos/aulas/hpsrt.html
– http://www.ime.usp.br/~pf/algoritmos/aulas/quick.html
Não deixe de visitar:
– http://www.cs.ubc.ca/spider/harrison/Java/sorting-demo.html
– http://math.hws.edu/TMCM/java/xSortLab/
– http://www.cs.oswego.edu/~mohammad/classes/csc241/samples/
sort/Sort2-E.html