Você está na página 1de 86

Captulo 2 - Algoritmos elementares de ordenao

ISEL/LEIC - 2007/2008 2 ano, 1 Semestre

* Estes acetatos foram parcialmente adaptados dos acetatos de AED da LEEC do Instituto Superior Tcnico Prof. Rui Gustavo Crespo Nuno Leite AED: Algoritmos e Estruturas de Dados Semestre de Inverno 2007/08 http://www.deetc.isel.ipl.pt/programacao/aed/

Algoritmos elementares de ordenao


Comearemos o nosso estudo com algoritmos elementares de ordenao: Selection sort, Insertion sort, Bubble sort e Shell sort Porqu estudar algoritmos elementares de ordenao? Razes de ordem prtica

Fceis de codificar e por vezes suficientes Rpidos/Eficientes para problemas de dimenso mdia e por vezes os melhores em certas circunstncias Bom exemplo para aprender terminologia, compreender contexto dos problemas e bom princpio para desenvolvimento de algoritmos mais sofisticados Alguns so fceis de generalizar para mtodos mais eficientes

Razes pedaggicas

Importante para compreenso das regras de "funcionamento"

LEIC AED Inverno 2007/08

Algoritmos de ordenao

Contexto e regras bsicas (1)


Objectivo

estudar mtodos de ordenao de ficheiros de dados em que cada elemento (item) caracterizado por uma chave (key) chaves so usadas para controlar a ordenao objectivo rearranjar os dados de forma a que as chaves estejam ordenadas de forma pr-definida (numrica ou alfabtica, por exemplo) caractersticas especficas de cada item ou chave podem ser diferentes mas conceito abstracto o mais importante utilizaremos operaes abstractas nos dados: comparao, troca

Metodologia

LEIC AED Inverno 2007/08

Algoritmos de ordenao

Contexto e regras bsicas (2)


Metodologia

comearemos por estudar ordenao em arrays consideraremos primeiro ordenao de sequncias de inteiros apresentaremos posteriormente uma implementao genrica

Tempo de execuo usualmente proporcional ao nmero de comparaes nmero de movimentaes/trocas (ou ambos)

LEIC AED Inverno 2007/08

Algoritmos de ordenao

Programa de teste de algoritmos de ordenao


public class IntArraySort { private static boolean less(int x, int y) { return x < y; } private static void exch(int[] a, int i, int j) { int aux = a[i]; a[i] = a[j]; a[j] = aux; } private static void lessExch(int[] a, int i, int j) { if (less(a[i], a[j])) exch (a, i, j); } // Selection Sort private static void selectionSort(int[] a, int l, int r) { ... } // Insertion Sort private static void insertionSort(int[] a, int l, int r) { ... } // Bubble Sort private static void bubbleSort(int[] a, int l, int r) { ... } ...
LEIC AED Inverno 2007/08 Algoritmos de ordenao 5

Programa de teste de algoritmos de ordenao


... public static void sort(int[] a, int l, int r) { selectionSort(a, l, r); } public static void main(String[] args) { int n = 50; int a[] = new int[n]; for (int i = 0; i < n; ++i) { // random gera nmeros no intervalo [0.0; 1.0[ a[i] = (int) (Math.random()*100); } sort(a, 0, n-1); // Ordenar array for (int i = 0; i < n; ++i) // Imprimir array System.out.print(a[i] + " "); } } // classe IntArraySort
LEIC AED Inverno 2007/08 Algoritmos de ordenao 6

Nomenclatura (1)

Tipos de Algoritmos de Ordenao


no adaptativos: sequncia de operaes independente da ordenao original dos dados


interessantes para implementao em hardware

adaptativos: sequncia de operaes dependente do resultado de comparaes (operao "less")


a maioria dos que estudaremos

Parmetro de interesse o desempenho, i.e. tempo de execuo


algoritmos bsicos: N2 para ordenar N itens


mas por vezes os melhores para N pequeno p.ex., Quicksort, Mergesort, Heapsort

algoritmos avanados: N log N para ordenar N itens


LEIC AED Inverno 2007/08

Algoritmos de ordenao

Nomenclatura (2)

Olharemos tambm para os recursos de memria necessrios


ordenao "in-place" ou utilizando memria adicional

Definio: um algoritmo de ordenao dito estvel se preserva a ordem relativa dos itens com chaves repetidas

ex: ordenar lista de alunos por ano de graduao quando esta j est ordenada alfabeticamente por nome

usualmente possvel estabilizar um algoritmo alterando a sua chave (tem custo adicional) algoritmos bsicos so quase todos estveis, mas poucos algoritmos avanados so estveis

LEIC AED Inverno 2007/08

Algoritmos de ordenao

Exemplo: Algoritmo estvel vs no estvel


Ordenado pela 1 chave (nome) Aps ordenao pela segunda chave (nmero) algoritmo no estvel Aps ordenao pela segunda chave (nmero) algoritmo estvel

Afonso Beatriz Bruno Joo Jos Mariana Mrio Matilde Slvia Tnia

1 2 4 2 4 2 3 3 1 4

Afonso Slvia Mariana Joo Beatriz Matilde Mrio Tnia Bruno Jos

1 1 2 2 2 3 3 4 4 4

Afonso Slvia Beatriz Joo Mariana Mrio Matilde Bruno Jos Tnia

1 1 2 2 2 3 3 4 4 4
9

LEIC AED Inverno 2007/08

Algoritmos de ordenao

Nomenclatura (3)

Definio: um algoritmo de ordenao dito interno, se o conjunto de todos os dados a ordenar couber na memria; caso contrrio dito externo

ex: ordenar dados lidos de disco ordenao externa ordenao interna pode aceder a qualquer dado facilmente ordenao externa tem de aceder a dados de forma sequencial (ou em blocos)

Distino muito importante:


Vamos estudar fundamentalmente ordenao interna

LEIC AED Inverno 2007/08

Algoritmos de ordenao

10

Nomenclatura (4)

Definio: um algoritmo de ordenao dito directo se os dados so acedidos directamente nas operaes de comparao e troca; caso contrrio dito indirecto Exemplo de algoritmo indirecto:

se a chave for pequena e cada dado for "grande


(por exemplo o nome completo de um aluno, mais morada, nmero de BI, etc.) nestes casos no convm estar a trocar os elementos dispendioso basta trocar a informao correspondente aos seus ndices array de ndices/ponteiros em que o primeiro indica o menor elemento, etc.

LEIC AED Inverno 2007/08

Algoritmos de ordenao

11

Exemplo: Ordenao indirecta


Em Java, a ordenao de elementos de tipo bsico feita de forma directa, e a ordenao de objectos realizada de forma indirecta, dado que estes so manipulados por referncia A figura ao lado ilustra o contedo dum array a ser ordenado, contendo referncias para objectos com chaves E X A M P L E, nesta ordem. Aps a ordenao das referncias, o array passa a referir os objectos na ordem A E E L M P X

LEIC AED Inverno 2007/08

Algoritmos de ordenao

12

Ordenao por seleco - Selection Sort


Algoritmo:

procurar menor elemento e trocar com o elemento situado na 1. posio procurar 2. menor elemento e trocar com o elemento situado na 2. posio proceder assim at ordenao estar completa a sombreado, indicam-se os elementos j ordenados

LEIC AED Inverno 2007/08

Algoritmos de ordenao

13

Implementao
private static void selectionSort(int[] a, int l, int r) { int min; for (int i = l; i < r; ++i) { min = i; for (int j = i+1; j <= r; ++j) if (less(a[j], a[min])) min = j; exch(a, i, min); } }

LEIC AED Inverno 2007/08

Algoritmos de ordenao

14

Selection Sort - Anlise


Ciclo interno apenas faz comparaes


troca de elementos feita fora do ciclo interno cada troca coloca um elemento na sua posio final

Nmero de trocas N-1 (porque no N?)

tempo de execuo dominado pelo nmero de comparaes!

Propriedade: Selection sort usa aproximadamente N trocas e N2/2 comparaes Demonstrao: para cada item i de 1 a N-1 h uma troca e N-i comparaes (ver sombreados no exemplo) Logo h N-1 trocas e (N-1) + (N-2) + ... + 2 + 1 = N(N-1)/2 comparaes

LEIC AED Inverno 2007/08

Algoritmos de ordenao

15

Selection Sort - Anlise


Factos: desempenho independente da ordenao inicial dos dados; a nica coisa que depende desta ordenao o nmero de vezes que min actualizado

quadrtico no pior caso (dados ordenados de forma inversa) N log N em mdia (dados ordenados aleatoriamente)

Algoritmo no adaptativo

Ordenar um ficheiro j ordenado demora tanto tempo como ordenar um ficheiro ordenado aleatoriamente!

LEIC AED Inverno 2007/08

Algoritmos de ordenao

16

Ordenao Sntese da Aula 1


Introduo ao problema da ordenao de dados


Simplicidade do problema facilita a compreenso de conceitos chave em algoritmos Problema de grande aplicao operaes elementares relevantes

Definio das regras base e interface de utilizao


Definies e propriedades gerais Ordenao por Seleco Selection sort


Descrio Exemplo de aplicao Anlise de eficincia

LEIC AED Inverno 2007/08

Algoritmos de ordenao

17

Ordenao por insero - Insertion Sort


Ideia: considerar os elementos um a um e inseri-los no seu lugar entre os elementos j tratados (mantendo essa ordenao)

ex: ordenar cartas de jogar

insero implica arranjar novo espao ou seja mover um nmero elevado de elementos uma posio para a direita inserir os elementos um a um comeando pelo da 1 posio

LEIC AED Inverno 2007/08

Algoritmos de ordenao

18

Insertion Sort - Funcionamento


Durante a primeira passagem de Insertion sort, o S na segunda posio maior que A, no sendo necessrio mover-se. Na segunda passagem, quando encontrado o O na terceira posio, este trocado com o S colocando A O S em ordem, e assim por diante. Elementos no sombreados e no assinalados com um crculo, so aqueles que so movidos uma posio para a direita
Algoritmos de ordenao 19

LEIC AED Inverno 2007/08

Implementao

private static void insertionSort1(int[] a, int l, int r) { for (int i = l+1; i <= r; ++i) { for (int j = i; j > l; --j) lessExch(a, j, j-1); } }

LEIC AED Inverno 2007/08

Algoritmos de ordenao

20

Insertion Sort - Comentrios


Elementos esquerda do ndice corrente esto ordenados mas no necessariamente na sua posio final

podem ainda ter de ser deslocados para a direita para dar lugar a elementos menores encontrados posteriormente

Implementao da ordenao por insero na pg. anterior ineficiente


cdigo simples, claro, mas pouco eficiente; pode ser melhorado ilustra bom raciocnio:

encontrar soluo simples estudar o seu funcionamento melhorar desempenho atravs de pequenas transformaes

LEIC AED Inverno 2007/08

Algoritmos de ordenao

21

Insertion Sort - Melhorar desempenho


Demasiadas operaes de comparao/troca (lessExch)


podemos parar se encontramos uma chave que no maior que a do item a ser inserido (array est ordenado esquerda)

podemos sair do ciclo interno se less(a[j-1], a[j]) verdadeira

modificao torna o algoritmo adaptativo aumenta desempenho aproximadamente por um factor de 2 mudar para um ciclo while remover instrues irrelevantes

Passa a haver duas condies para sair do ciclo


lessExch no o melhor processo de mover vrios dados uma posio para a direita

LEIC AED Inverno 2007/08

Algoritmos de ordenao

22

Insertion Sort - Verso adaptativa


private static void insertionSort2(int[] a, int l, int r) { for (int i = l+1; i <= r; ++i) { int v = a[i]; int j = i; while (j >= l+1 && less(v, a[j-1])) { a[j] = a[j-1]; --j; } a[j] = v; } }

LEIC AED Inverno 2007/08

Algoritmos de ordenao

23

Insertion Sort - Anlise


Propriedade: Insertion sort usa aproximadamente N2/4 comparaes e N2/4 pseudo-trocas (translaes ou movimentos) no caso mdio e o dobro destes valores no pior caso Demonstrao: Fcil de ver graficamente; elementos abaixo da diagonal so contabilizados (todos no pior caso)

Para dados aleatrios expectvel que cada elemento seja colocado aproximadamente a meio para trs pelo que apenas metade dos elementos abaixo da diagonal devem ser contabilizados

Factos: Quando a sequncia a ordenar se encontra parcialmente ordenada, o Insertion sort tem um desempenho aproximadamente linear.

LEIC AED Inverno 2007/08

Algoritmos de ordenao

24

Bubble Sort

Talvez o algoritmo mais utilizado e o que muitas pessoas aprendem primeiro Ideia: fazer mltiplas passagens pelos dados trocando de cada vez dois elementos adjacentes que estejam fora de ordem, at no haver mais trocas

supostamente muito fcil de implementar usualmente mais lento que os dois mtodos elementares estudados

LEIC AED Inverno 2007/08

Algoritmos de ordenao

25

Implementao

private static void bubbleSort(int[] a, int l, int r) { for (int i = l; i < r; ++i) { for (int j = r; j > i; --j) { lessExch(a, j, j-1); } } }

LEIC AED Inverno 2007/08

Algoritmos de ordenao

26

Bubble Sort - Comentrios (1)


Movendo da direita para a esquerda no ficheiro de dados


quando o elemento mais pequeno encontrado na primeira passagem


sucessivamente trocado com todos sua esquerda acaba por ficar na primeira posio

na segunda passagem o 2. elemento mais pequeno colocado na sua posio e por diante N passagens pelos dados so suficientes! tem mais trabalho para colocar cada elemento na sua posio final

semelhante ao mtodo de seleco


todas as trocas sucessivas at chegar posio certa

LEIC AED Inverno 2007/08

Algoritmos de ordenao

27

Bubble Sort - Comentrios (2)


Algoritmo pode ser melhorado, tal como o algoritmo de insero


cdigo muito semelhante mas no igual


ciclo interno de Insertion Sort percorre a parte esquerda (ordenada) do array ciclo interno de Bubble Sort percorre a parte direita (no ordenada) do array se o array estiver ordenado, pra

no final de cada passagem podemos testar se houve mudanas


LEIC AED Inverno 2007/08

Algoritmos de ordenao

28

Bubble Sort - Anlise


Propriedade: Bubble sort usa aproximadamente N2/2 comparaes e N2/2 trocas no pior caso; N2/4 trocas no caso mdio Demonstrao: A i-sima passagem de Bubble Sort requer N-i operaes de comparao/troca, logo a demonstrao semelhante a Selection sort Factos: Algoritmo pode depender criticamente dos dados se for modificado para terminar quando no houver mais trocas

se o ficheiro estiver ordenado, apenas um passo necessrio se estiver em ordenao inversa ento na i-sima passagem so precisas N-i comparaes e trocas caso mdio semelhante (anlise mais complexa)

LEIC AED Inverno 2007/08

Algoritmos de ordenao

29

Comparao dos algoritmos elementares de ordenao (1)

Tempos de execuo quadrticos

Selection Comparaes Trocas N2/2 N

Insertion N2/4 N2/4

Bubble N2/2 N2/2

LEIC AED Inverno 2007/08

Algoritmos de ordenao

30

Comparao dos algoritmos elementares de ordenao (2)


Ficheiros com elementos grandes e pequenas chaves


Selection Sort linear no nmero de dados


N dados com tamanho M (palavras/words)


considerando dados manipulados por valor tem-se: comparao -1 unidade;

troca - M unidades N2/2 comparaes e NM custo de trocas termo NM domina custo proporcional ao tempo necessrio para mover os dados

Ficheiros quase ordenados


Insertion sort e Bubble sort so quase lineares os melhores algoritmos de ordenao podem ser quadrticos neste caso!

LEIC AED Inverno 2007/08

Algoritmos de ordenao

31

Comparao dos algoritmos elementares de ordenao (3)


int items N 1000 2000 4000 Legenda: S I* I B Selection sort Insertion sort, exchange-based Insertion sort Bubble sort S I* I 14 54 8 54 218 33 212 848 129 Integer keys B S I B 54 100 55 130 221 436 229 569 871 1757 986 2314 String keys S I B 129 65 170 563 295 725 2389 1328 3210

LEIC AED Inverno 2007/08

Algoritmos de ordenao

32

Ordenao Sntese da Aula 2


Ordenao por insero Insertion sort


Verso elementar Verso adaptativa Exemplo de aplicao Anlise de Eficincia Descrio do algoritmo e anlise funcionamento Exemplo de aplicao Anlise de eficincia Em nmero de comparaes e trocas Na evoluo da tabela durante a execuo

Bubble sort Breve referncia


Comparao dos trs primeiros algoritmos elementares


LEIC AED Inverno 2007/08

Algoritmos de ordenao

33

Shell sort (1)


Shell sort (proposto por Donald Shell em 1959) um algoritmo que requer no pior caso menos de O(n2) comparaes e trocas

embora seja simples perceber intuitivamente o seu funcionamento, extremamente difcil analisar o seu desempenho
estimam-se desempenhos de ordem entre O(n3/2) e O(n log2n) (melhor alcanado actualmente), dependendo dos detalhes de implementao

Shell sort uma generalizao de Insertion sort que tem em conta duas observaes:

Insertion sort eficiente se a entrada estiver ordenada ou quase ordenada Insertion sort ineficiente, em mdia, porque apenas move os elementos de uma posio de cada vez

LEIC AED Inverno 2007/08

Algoritmos de ordenao

34

Shell sort (2)


Insertion sort:

se o menor item est no final da tabela, sero precisos N passos para o colocar na posio correcta acelerar o algoritmo permitindo trocas entre elementos que esto afastados como?

Shell sort:

O Shell sort compara os elementos separados de uma distncia (gap) de vrias posies (p.ex. gap=5)

so realizadas mltiplas passagens com passos sucessivamente menores, terminando com gap=1, que no mais do que realizar Insertion sort mas nesta altura, os dados j esto praticamente ordenados

Insertion sort eficiente!

LEIC AED Inverno 2007/08

Algoritmos de ordenao

35

Shell sort Exemplo (1)


Suponha que se pretende ordenar o array


66, 95, 93, 82, 54, 40, 35, 19, 75, 24, 32, 43, 16, 68

Ordenar os elementos separados de uma distncia h o mesmo que particionar o array em linhas de h colunas e aplicar Insertion sort ao longo das colunas Execuo de Shell sort com h=5:

Sequncia original h=5 66 40 32 95 35 43 93 19 16 82 75 68 54 24

Sequncia ordenada por colunas usando Insertion sort 32 40 66


Algoritmos de ordenao

35 43 95

16 19 93

68 75 82

24 54

LEIC AED Inverno 2007/08

36

Shell sort Exemplo (2)


Execuo de Shell sort com h=3:

Sequncia original h=3 32 68 43 54 93 35 24 19 66 82 16 40 75 95

Sequncia ordenada por colunas usando Insertion sort 32 43 54 68 93 19 24 35 66 82 16 40 75 95

LEIC AED Inverno 2007/08

Algoritmos de ordenao

37

Shell sort Exemplo (3)


Execuo de Shell sort com h=1 (Insertion sort):

Sequncia original (coluna nica) h=1 32 19 16 43 24 40 54 35 75 68 66 95 93 82

Sequncia ordenada usando Insertion sort 16 19 24 32 35 40 43 54 66 68 75 82 93 95


38

LEIC AED Inverno 2007/08

Algoritmos de ordenao

Shell sort Exemplo (4)


Em termos de implementao, a ordenao das colunas com Insertion sort no realizada sequencialmente, ordenar 1 col., 2 col. , mas sim de forma entrelaada como ilustrado neste exemplo.

k= l+h+k

0 40 66 32

1 35 95 43

2 19 93 16

3 75 82 68

4 24 54

Sequncia original h=5

k=
66 40 32 95 35 43 93 19 16 82 75 68 54 24

5 32

6 35 43 95

7 16 19 93

8 68 75 82
39

24 54

l+h+k
Algoritmos de ordenao

40 66

LEIC AED Inverno 2007/08

Shell sort Implementao para o exemplo dado


private static void shellSortTest(int[] a, int l, int r) { int incs[] = { 5, 3, 1 }; for (int k = 0; k < incs.length; ++k) { int h = incs[k]; // Insertion sort com passo (gap) h for (int i = l+h; i <= r; ++i) { int v = a[i], j = i; while (j >= l+h && less(v, a[j-h])) { a[j] = a[j-h]; j -= h; } a[j] = v; } } }
LEIC AED Inverno 2007/08 Algoritmos de ordenao 40

Sequncia de Ordenao (1)


Difcil de escolher

propriedades de muitas sequncias foram j estudadas possvel provar que umas so melhores que outras

ex: 1, 4, 13, 40, 121, 364, 1093, 3280, ... (Knuth, h=3*hant+1) 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, ... (Shell, h=2i ) -> O(n2)

melhor que

Porqu?

mas pior (20%) que 1, 8, 23, 77, 281, 1073, 4193, (Sedgewick, 4i + 1 + 3(2i) + 1 )

na prtica utilizam-se sequncias que decrescem geometricamente para que o nmero de incrementos seja logartmico

LEIC AED Inverno 2007/08

Algoritmos de ordenao

41

Sequncia de Ordenao (2)


a sequncia ptima no foi ainda descoberta (se que existe) anlise do algoritmo desconhecida

ningum encontrou a frmula que define a complexidade complexidade depende da sequncia

LEIC AED Inverno 2007/08

Algoritmos de ordenao

42

Shell sort Implementao genrica


private static void shellSort(int[] a, int l, int r) { int h, length = r-l+1; for (h = 1; h < length; h = 3*h+1); // empty body for (h /= 3; h > 0; h /= 3) { // Insertion sort com passo (gap) h for (int i = l+h; i <= r; ++i) { int v = a[i], j = i; while (j >= l+h && less(v, a[j-h])) { a[j] = a[j-h]; j -= h; } a[j] = v; } } }
LEIC AED Inverno 2007/08 Algoritmos de ordenao 43

Anlise de Shell sort


Propriedades:

o resultado de h-ordenar um ficheiro que est k-ordenado um ficheiro que est simultaneamente h- e k-ordenado

Propriedade muito importante: indica a ordenao actual no estraga a ordenao realizada anteriormente

Shell sort faz menos do que O(N3/2) comparaes para os incrementos (Knuth) 1, 4, 13, 40, 121, 364, 1093, ... Shell sort faz menos do que O(N4/3) comparaes para os incrementos (Sedgewick) 1, 8, 23, 77, 281, 1073, 4193, 16577, ...

Nota: sequncias at agora usam incrementos que so primos entre si

Shell sort faz menos do que O(N lg2 N) comparaes para os incrementos (Pratt) 1, 2, 3, 4, 6, 8, 9, 12, 16, ..., 2p3q, ...

LEIC AED Inverno 2007/08

Algoritmos de ordenao

44

Vantagens de Shell sort


rpido/eficiente pouco cdigo melhor mtodo para ficheiros pequenos e mdios aceitvel para elevados volumes de dados Muito utilizado na prtica, embora difcil de compreender!

LEIC AED Inverno 2007/08

Algoritmos de ordenao

45

Implementao genrica de algoritmos de ordenao (1)


public class StaticGenericArraySort { private static boolean less(Object x, Object y, Comparator cmp) { if (cmp == null) return ((Comparable)x).compareTo(y) < 0; else return cmp.compare(x, y) < 0; } private static void exch(Object[] a, int i, int j) { Object aux = a[i]; a[i] = a[j]; a[j] = aux; } private static void lessExch(Object[] a, int i, int j, Comparator cmp) { if (less(a[i], a[j], cmp)) exch (a, i, j); } private static void selectionSort(Object[] a, int l, int r, Comparator cmp) { for (int i = l; i < r; ++i) { int min = i; for (int j = i+1; j <= r; ++j) if (less(a[j], a[min], cmp)) min = j; exch(a, i, min); } }
LEIC AED Inverno 2007/08 Algoritmos de ordenao 46

Implementao genrica de algoritmos de ordenao (2)


// Mtodos pblicos public static void sort(Object[] a, int l, int r, Comparator cmp) { selectionSort(a, l, r, cmp); } public static void main(String[] args) { Student[] students = {new Student("Nuno", 30), new Student("Luis", 10), new Student("Afonso", 40), new Student("Ana", 20) }; // Ordem natural, neste caso por nome de forma ascendente // (definido pelo mtodo compareTo) sort(students, 0, students.length-1, null); // ordenao por nome de forma descendente sort(students, 0, students.length-1, Student.BY_NAME); // ordenao por nmero de forma ascendente sort(students, 0, students.length-1, Student.BY_NUMBER); } }
LEIC AED Inverno 2007/08 Algoritmos de ordenao 47

Ordenar por diferentes critrios


class Student implements Comparable<Student> { private String name; private int number; private static class ByName implements Comparator<Student> { public int compare(Student a, Student b) { return -a.name.compareTo(b.name); } // ordem inversa } private static class ByNumber implements Comparator<Student> { public int compare(Student a, Student b) { return a.number - b.number; } } public static final Comparator<Student> BY_NAME = new ByName(); public static final Comparator<Student> BY_NUMBER = new ByNumber(); public int compareTo(Student s) { return this.name.compareTo(s.name); } }
LEIC AED Inverno 2007/08 Algoritmos de ordenao 48

Ordenao Sntese da Aula 3


Shell sort

Apresentado como uma variante de acelerao do Insertion sort Descrio Implementao


Sequncias de ordenao

Exemplo de aplicao Discusso da eficincia do algoritmo


Condicionada pela sequncia de ordenao utilizada

Vantagens relativamente a outros algoritmos Ordenao por diferentes critrios

Implementao genrica de algoritmos de ordenao


LEIC AED Inverno 2007/08

Algoritmos de ordenao

49

Captulo 2 - Algoritmos avanados de ordenao - Quicksort e Mergesort

ISEL/LEIC - 2007/2008 2 ano, 1 Semestre

* Estes acetatos foram parcialmente adaptados dos acetatos de AED da LEEC do Instituto Superior Tcnico Prof. Rui Gustavo Crespo Nuno Leite AED: Algoritmos e Estruturas de Dados Semestre de Inverno 2007/08 http://www.deetc.isel.ipl.pt/programacao/aed/

Algoritmos avanados - Quicksort


Provavelmente o algoritmo mais usado


inventado em 1960 por Charles Hoare muito estudado e analisado


desempenho bem conhecido complexidade N log2 N, em mdia, para ordenar N objectos ciclo interno muito simples e conciso

popular devido facilidade de implementao e eficincia


LEIC AED Inverno 2007/08

Algoritmos de ordenao

51

Quicksort

Quicksort realiza 39% mais comparaes do que o Mergesort Contudo, mais rpido que o Mergesort na prtica devido ao menor custo de outras instrues de alta frequncia Mas:

no estvel quadrtico (N2) no pior caso! frgil: qualquer pequeno erro de implementao pode no ser detectado mas levar a ineficincia

LEIC AED Inverno 2007/08

Algoritmos de ordenao

52

Quicksort

Algoritmo do tipo dividir para conquistar Algoritmo Quicksort:


(Opcional): Baralhar (Shuffle) o array Particionar (Partition) o array da seguinte forma:


elemento a[i] fica na sua posio final para um determinado i no existem elementos maiores do que a[i] esquerda de i no existem elementos menores do que a[i] direita de i

Ordenar cada partio recorrentemente

LEIC AED Inverno 2007/08

Algoritmos de ordenao

53

Quicksort - Partio

LEIC AED Inverno 2007/08

Algoritmos de ordenao

54

Quicksort - Exemplo

LEIC AED Inverno 2007/08

Algoritmos de ordenao

55

Estratgia para a partio


Escolher a[r] para ser o elemento de partio


o que colocado na posio final

Percorrer o array a partir da esquerda at encontrar um elemento maior que ou igual ao elemento de partio (a[r]) Percorrer o array a partir da direita at encontrar um elemento menor que ou igual ao elemento de partio (a[r])

estes dois elementos esto deslocados; trocamos as suas posies!

Procedimento continua at nenhum elemento esquerda de a[r] ser maior que ele, e nenhum elemento direita de a[r] ser menor que ele

termina quando os ndices se cruzam completa-se trocando a[r] com o elemento referenciado pelo ndice i (que varre da esquerda para a direita)

LEIC AED Inverno 2007/08

Algoritmos de ordenao

56

Quicksort - Implementao
public class IntArraySort { public static void quicksort(int[] a, int l, int r) { shuffle(a, l, r); // Opcional qsort(a, 0, a.length - 1); } private static void qsort(int[] a, int l, int r) { if (r <= l) return; int m = partition(a, l, r); qsort(a, l, m-1); qsort(a, m+1, r); }

LEIC AED Inverno 2007/08

Algoritmos de ordenao

57

Quicksort - Implementao
private static int partition(int[] a, int l, int r) { int i = l-1, j = r; int v = a[r]; for (;;) {
// Encontra ndice de elemento >= pivot esquerda

while (less(a[++i], v)) ;


// Encontra ndice elemento<=pivot direita

while (less(v, a[--j])) if (j == l) break; if (i >= j) break; exch(a, i, j); } exch(a, i, r); // Troca com pivot de partio return i; // Retorna ndice do pivot }
LEIC AED Inverno 2007/08 Algoritmos de ordenao 58

Quicksort - Partio

Eficincia do processo de ordenao depende de quo bem a partio divide os dados


depende por seu turno do elemento de partio


ser tanto mais equilibrada quanto mais perto este elemento estiver do meio da tabela na sua posio final

Processo de partio no estvel


qualquer chave pode ser movida para trs de vrias outras chaves iguais a si (que ainda no foram examinadas)

no conhecida nenhuma forma simples de implementar uma verso estvel de Quicksort baseada em arrays

LEIC AED Inverno 2007/08

Algoritmos de ordenao

59

Quicksort Caractersticas de desempenho


Se no se usar o shuffling, o Quicksort pode ser muito ineficiente em casos patolgicos Propriedade: Quicksort usa cerca de N2/2 comparaes no pior caso

No pior caso, o nmero de comparaes usadas por Quicksort satisfaz a recorrncia de dividir para conquistar

C(n) = C(n-1) + O(n)


1 termo cobre o custo de ordenar um sub-ficheiro (partio degenerada) 2 termo refere-se a examinar cada elemento C(n) = O(n2)

LEIC AED Inverno 2007/08

Algoritmos de ordenao

60

Quicksort Anlise do pior caso


Se o ficheiro j estiver ordenado, todas as parties degeneram e o programa chama-se a si prprio N vezes; o nmero de comparaes de N + (N-1) + (N-2) + + 2 + 1 = (N + 1)N / 2 (mesma situao se o ficheiro estiver ordenado por ordem inversa) No apenas o tempo necessrio para a execuo do algoritmo cresce quadraticamente como o espao necessrio para o processo recorrente de cerca de N o que inaceitvel para ficheiros grandes

LEIC AED Inverno 2007/08

Algoritmos de ordenao

61

Quicksort Caractersticas de desempenho


Melhor caso: quando cada partio divide o ficheiro de entrada exactamente em metade

nmero de comparaes usadas por Quicksort satisfaz a recorrncia de dividir para conquistar

C(n) = 2C(n/2) + O(n)


1 termo cobre o custo de ordenar os dois sub-ficheiros 2 termo refere-se a examinar cada elemento

soluo C(n) = O(n log2 n) (vimos numa aula anterior) Espao usado nas chamadas recorrentes log2(n)

Demonstrao...

LEIC AED Inverno 2007/08

Algoritmos de ordenao

62

Quicksort Caractersticas de desempenho


Propriedade: Quicksort usa cerca de O(2N log2 N) comparaes em mdia Demonstrao: A frmula de recorrncia exacta para o nmero de comparaes utilizado por Quicksort para ordenar N nmeros distintos aleatoriamente posicionados

1 n C(n) = n + 1 + (C(k 1) + C(n k)) n k =1


n 2, C(0) = C(1) = 0

termo n+1 cobre o custo de comparar o elemento de partio com os restantes (2 comparaes extra: ponteiros cruzam-se) resto vem do facto de que cada elemento tem probabilidade 1/n de ser o elemento de partio aps o que ficamos com dois sub-arrays de tamanhos k-1 e n-k

LEIC AED Inverno 2007/08

Algoritmos de ordenao

63

Quicksort Caractersticas de desempenho


Demonstrao (cont.)

1 n C(n) = n + 1 + (C(k 1) + C(n k)) n k =1

2 n = n + 1 + C(k 1) n k =1

Multiplicar ambos os lados da equao por n e subtrair a mesma frmula por n-1

nC(n) - (n -1)C(n -1) = n(n + 1) - (n -1)n + 2C(n -1)


Simplificar para:

nC(n) = (n + 1)C(n 1) + 2n
LEIC AED Inverno 2007/08 Algoritmos de ordenao 64

Quicksort Caractersticas de desempenho


Dividir ambos os lados da equao por n(n-1) de forma a obter a soma:


C(n) C(n -1) 2 = + n +1 n n +1 C(n - 2) 2 2 = + + n -1 n n +1 C(n - 3) 2 2 2 = + + + n-2 n -1 n n + 1 = M
C(2) n 2 = + k +1 3 k =3

Aproximar a resposta exacta por um integral: n n C(n) 2 = 2 k k = 2 ln n k 1 = n + 1 k =1 Finalmente, obtm-se a soluo:

C(n) = 2(n + 1) ln n 1.39n log 2 n.


65

LEIC AED Inverno 2007/08

Algoritmos de ordenao

Quicksort Caractersticas de desempenho


Anlise assume que os dados esto aleatoriamente ordenados e tm chaves diferentes


pode ser lento em situaes em que as chaves no so distintas ou que os dados no esto aleatoriamente ordenados (como vimos) para reduzir a probabilidade que estes casos sucedam! necessrio em ficheiros de grandes dimenses ou se o algoritmo for usado como funo genrica numa biblioteca

Algoritmo pode ser melhorado


LEIC AED Inverno 2007/08

Algoritmos de ordenao

66

Ordenao Sntese da Aula 4


Algoritmo Quicksort

Ideia chave + Motivao


Algoritmo que recorre diviso em instncias menores divide and conquer

Cdigo Exemplo de aplicao Descrio detalhada do mecanismo de partio Anlise de eficincia


Pior caso Melhor caso Caso mdio

LEIC AED Inverno 2007/08

Algoritmos de ordenao

67

Quicksort Questes mais relevantes


Possvel reduo de desempenho devido ao uso de recorrncia Tempo de execuo dependente dos dados de entrada Tempo de execuo quadrtico no pior caso

um problema um problema srio (para ficheiros de grandes dimenses) recorrncia implica chamada a funo e logo a carregar dados na pilha/stack do computador no pior caso todas as parties degeneram e h O(N) nveis de recorrncia (em vez de O(log2(N)) no melhor caso)

Espao/memria necessrio no pior caso linear


Problema do espao est associado ao uso de recorrncia:


pilha cresce at ordem N

LEIC AED Inverno 2007/08

Algoritmos de ordenao

68

Quicksort - Espao necessrio (1)


Para resolver este problema usamos uma pilha (stack) explcita


pilha contm trabalho a ser processado, na forma de sub-arrays a ordenar quando precisamos de um sub-array para processar tiramo-lo da pilha (i.e. fazemos um pop() do stack) por cada partio criamos dois sub-arrays e metemos ambos na pilha (i.e. fazemos dois push() para o stack) substitui a pilha do computador que usada na implementao recorrente

LEIC AED Inverno 2007/08

Algoritmos de ordenao

69

Quicksort - Espao necessrio (2)


Conduz a uma verso no recorrente de Quicksort


verifica os tamanhos dos dois subarrays e pe o maior deles primeiro na pilha (e o menor depois; logo o menor retirado e tratado primeiro) ordem de processamento dos subarrays no afecta a correcta operao da funo ou o tempo de processamento mas afecta o tamanho da pilha garante que dimenso mxima do stack O(log2 N)

No pior caso espao extra para a ordenao logartmico em N


LEIC AED Inverno 2007/08

Algoritmos de ordenao

70

Quicksort - Verso no-recursiva (1)


static void nonRecursiveQuicksort(int[] a, int l, int r) { shuffle(a, l, r); // Shuffle IntStack s = new IntStackArray(50); s.push(l); s.push(r); while (!s.isEmpty()) { r = s.pop(); l = s.pop(); if (r <= l) continue; int i = partition(a, l, r); if (i-l > r-i) { s.push(l); s.push(i-1); } s.push(i+1); s.push(r); if (r-i >= i-l) { s.push(l); s.push(i-1); } } }

LEIC AED Inverno 2007/08

Algoritmos de ordenao

71

Quicksort - Verso no-recursiva (2)


Poltica de colocar o maior dos subarrays primeiro na pilha


garante que cada entrada na pilha no maior do que metade da que estiver antes dela na pilha pilha apenas ocupa log2 N no pior caso

que ocorre agora quando a partio ocorre sempre no meio da tabela em ficheiros aleatrios o tamanho mximo da pilha bastante menor

Propriedade: se o menor dos dois subarrays ordenado primeiro a pilha nunca necessita mais do que log2 N entradas quando Quicksort usado para ordenar N elementos

LEIC AED Inverno 2007/08

Algoritmos de ordenao

72

Quicksort - Verso no-recursiva (3)


Demonstrao: no pior caso o tamanho da pilha inferior a T(n) em que T(n) satisfaz a recorrncia

T(n) = Tn/2 + 1

com T(0) = T(1) = 0

que foi j estudada anteriormente

LEIC AED Inverno 2007/08

Algoritmos de ordenao

73

Quicksort - Melhoramentos (1)


Algoritmo pode ainda ser melhorado com alteraes triviais


porqu colocar ambos os subarrays na pilha se um deles de imediato retirado? Teste para r <= l feito assim que os subarrays saem da pilha

seria melhor nunca os l ter colocado!

ordenao de ficheiros/subarrays de pequenas dimenses pode ser efectuada de forma mais eficiente como escolher correctamente o elemento de partio? Como melhorar o desempenho se os dados tiverem um grande nmero de chaves repetidas?

LEIC AED Inverno 2007/08

Algoritmos de ordenao

74

Quicksort - Melhoramentos (2)


Pequenos ficheiros/sub-arrays

At mesmo o QuickSort apresenta um overhead excessivo quando usado com ficheiros de pequena dimenso

conveniente utilizar o melhor mtodo possvel quando encontra tais ficheiros

forma bvia de obter este comportamento mudar o teste no incio da funo recorrente para uma chamada a Insertion sort if (r-l <= M) insertionSort(a, l, r)

em que M um parmetro a definir na implementao

LEIC AED Inverno 2007/08

Algoritmos de ordenao

75

Quicksort - Melhoramentos (3)


Pequenos ficheiros/subarrays

outra soluo a de simplesmente ignorar ficheiros pequenos (tamanho menor que M) durante a partio: if (r-l <= M) return;

neste caso no final teremos um ficheiro que est praticamente todo ordenado

Boa soluo neste caso usar insertion sort


algoritmo hbrido: bom mtodo em geral!

LEIC AED Inverno 2007/08

Algoritmos de ordenao

76

Quicksort - Melhoramentos (4)


1 Mtodo:

Utilizar um elemento de partio que com alta probabilidade divida o ficheiro pela metade

pode usar-se um elemento aleatoriamente escolhido evita o pior caso (i.e. pior caso tem baixa probabilidade de acontecer) um exemplo de um algoritmo probabilstico um que usa aleatoriedade para obter bom desempenho com alta probabilidade independentemente dos dados de entrada pode ser demasiado pesado incluir gerador aleatrio no algoritmo; existem outros mtodos igualmente simples

LEIC AED Inverno 2007/08

Algoritmos de ordenao

77

Quicksort - Melhoramentos (5)


2 Mtodo:

pode escolher-se alguns (ex: trs) elementos do ficheiro e usar a mediana dos trs como elemento de partio

escolhendo os trs elementos da esquerda, meio e direita da tabela podemos incorporar sentinelas na ordenao ordenamos os trs elementos, depois trocamos o do meio com a[r-1] e executamos o algoritmo de partio em a[l+1] a[r-1] median - of - three

Este melhoramento chama-se o mtodo da mediana de trs


LEIC AED Inverno 2007/08

Algoritmos de ordenao

78

Mediana de trs - Implementao


private final static int M = 10; static void quickSort(int[] a, int l, int r) { if (r-l <= M) return; exch(a, (l+r)/2, r-1); lessExch(a, r-1, l); lessExch(a, r, l); lessExch(a, r, r-1); int i = partition(a, l+1, r-1); quicksort(a, l, i-1); quicksort(a, i+1, r); } static void hybridSort(int a[], int l, int r) { quicksort(a, l, r); insertionSort(a, l, r); }

LEIC AED Inverno 2007/08

Algoritmos de ordenao

79

Quicksort - Melhoramentos (6)


Mtodo da mediana de trs melhora Quicksort por duas razes


o pior caso mais improvvel de acontecer na prtica


dois dos trs elementos teriam de ser dos maiores ou menores do ficheiro e isto teria de acontecer constantemente a todos os nveis de partio embora apenas por cerca de 5%

reduz o tempo mdio de execuo do algoritmo


junto com o mtodo de tratar de pequenos ficheiros pode resultar em ganhos de 20 a 25%

possvel pensar em outros melhoramentos mas o acrscimo de eficincia marginal (ex: porque no fazer a mediana de cinco?)

LEIC AED Inverno 2007/08

Algoritmos de ordenao

80

Quicksort - Chaves duplicadas (1)


Ficheiros com um grande nmero de chaves duplicadas so frequentes na prtica


ex: ordenar populao por idade; remover duplicados de uma lista desempenho de Quicksort pode ser substancialmente melhorado

se todas as chaves forem iguais Quicksort mesmo assim faz O(N log2 N) comparaes

LEIC AED Inverno 2007/08

Algoritmos de ordenao

81

Quicksort - Chaves duplicadas (2)


Uma possibilidade dividir o ficheiro em trs partes


cada uma para chaves menores, iguais e maiores que o elemento de partio no trivial de implementar, sobretudo se se impuser que a ordenao dever ser feita com apenas uma passagem pelos dados

Soluo simples para este problema fazer uma partio em trs partes

manter chaves iguais ao elemento de partio que so encontradas no sub-ficheiro da esquerda do lado esquerdo do ficheiro manter chaves iguais ao elemento de partio que so encontradas no sub-ficheiro da direita do lado direito do ficheiro

LEIC AED Inverno 2007/08

Algoritmos de ordenao

82

Quicksort - Chaves duplicadas (3)


Quando os ponteiros/ndices de pesquisa se cruzam sabemos onde esto os elementos iguais ao de partio e fcil coloc-los em posio

no faz exactamente tudo num s passo mas quase... trabalho extra para chaves duplicadas proporcional ao nmero de chaves duplicadas: funciona bem se no houver chaves duplicadas linear quando h um nmero constante de chaves!!
Algoritmos de ordenao 83

LEIC AED Inverno 2007/08

Quicksort - Partio em trs


static void quicksort(int a[], int l, int r) { if (r <= l) return; int v = a[r], i = l, j = r-1, p = l-1, q = r, k; for (;;) { while (less(a[i], v)) ++i; while (j >= l && less(v, a[j])) ++j; if (i >= j) break; exch(a, i, j); if (equal(a[i], v)) { p++; exch(a, p, i); } if (equal(v, a[j])) { q--; exch(a, q, j); } } exch(a, i, r); j = i-1; i = i+1; for (k = l ; k <= p; k++,j--) exch(a, k, j); for (k = r-1; k >= q; k--,i++) exch(a, k, i); quicksort(a, l, j); quicksort(a, i, r); }
LEIC AED Inverno 2007/08 Algoritmos de ordenao 84

Juno versus partio


Quicksort baseado na operao de seleco do elemento de partio (pivot)


a partio divide um ficheiro em duas partes quando as duas metades do ficheiro esto ordenadas, o ficheiro est ordenado dividir o ficheiro em duas partes para serem ordenados e depois combinar as partes de forma a que o ficheiro total fique ordenado

Operao complementar de juno (merge)


Mergesort

Mergesort tem uma propriedade muito interessante:


ordenao de um ficheiro de N elementos feito em tempo proporcional a N log N, independentemente dos dados!

Outros algoritmos, p.ex. HeapSort, tambm tm desempenho desta ordem

LEIC AED Inverno 2007/08

Algoritmos de ordenao

85

Ordenao Sntese da Aula 5


Anlise do algoritmo Quicksort


Discusso relativa memria utilizada na verso recorrente Alternativa de implementao por pilha e suas vantagens na perspectiva da memria utilizada Cdigo para Quicksort em verso no recorrente Mecanismos de partio alternativos

Melhoramentos na verso no recorrente


Aleatrios Mediana de trs Ideia base Cdigo

Estratgia de melhoramento em presena de chaves duplicadas


LEIC AED Inverno 2007/08

Algoritmos de ordenao

86