Você está na página 1de 54

Algoritmos e Estruturas de Dados

LEEC
Algoritmos de Ordenação – Parte I
Porquê estudar algoritmos elementares
(de ordenação)

 Razões de ordem prática


 Fáceis de codificar e por vezes suficientes
 Rápidos/Eficientes para problemas de dimensão média e por vezes os
melhores em certas circunstâncias
 Razões pedagógicas
 Bom exemplo para aprender terminologia, compreender contexto dos
problemas e bom princípios para desenvolvimento de algoritmos mais
sofisticados
 Alguns são fáceis de generalizar para métodos mais eficientes ou para
melhorar o desempenho de outros algoritmos
 Importante para compreensão das regras de "funcionamento"

2 AED (IST/DEEC)
Contexto e regras básicas [1]
 Objectivo
 Estudar métodos de ordenação de ficheiros de dados em que cada
elemento (item) é caracterizado por uma chave ("key")
 Chaves são usadas para controlar a ordenação
 objectivo é rearranjar os dados de forma a que as chaves estejam
ordenadas de forma pré-definida (numérica ou alfabética, por exemplo)
 Opções em termos de implementação
 macros ou subrotinas/funções?
 compromisso entre desempenho, generalidade e simplicidade
 utilizaremos uma mistura de ambos

3 AED (IST/DEEC)
Contexto e regras básicas [2]
 Metodologia
 características específicas de cada item ou chave podem ser diferentes
mas conceito abstracto é o mais importante
 começaremos por estudar ordenação em tabelas
 utilizaremos operações abstractas nos dados: comparação, troca
 alterar items para outro tipo (ex: vírgula flutuante) é simples

typedef int Item;


#define key(A) (A)
#define less(A, B) (key(A) < key(B))
#define exch(A, B) {Item t = A; A = B; B = t; }
#define compexch(A, B) if (less(B,A)) exch(A, B)

 Tempo de execução usualmente proporcional ao número de


comparações número de movimentações/trocas (ou ambos)

4 AED (IST/DEEC)
Nomenclatura [1]
 Tipos de Algoritmos de Ordenação
 não adaptativos: sequência de operações independente da ordenação
original dos dados
 interessantes para implementação em hardware
 adaptativos: sequência de operações dependente do resultado de
comparações (operação "less")
 a maioria dos que estudaremos
 Parâmetro de interesse é o desempenho, i.e. tempo de
execução
 algoritmos básicos: 𝑁2 para ordenar 𝑁 items
 mas por vezes os melhores para 𝑁 pequeno
 algoritmos avançados: 𝑁 log 𝑁 para ordenar 𝑁 items
 Olharemos também para os recursos de memória necessários
 ordenação "in-place" ou utilizando memória adicional

5 AED (IST/DEEC)
Nomenclatura [2]
 Definição – um algoritmo de ordenação é dito estável se
preserva a ordem relativa dos items com chaves repetidas
 exemplo: ordenar lista de alunos por ano de graduação quando esta já
está ordenada alfabeticamente por nome
 é usualmente possível estabilizar um algoritmo alterando a sua chave
(tem custo adicional)
 algoritmos básicos são quase todos estáveis, mas poucos algoritmos
avançados são estáveis

6 AED (IST/DEEC)
Nomenclatura [3]
 Definição – um algoritmo de ordenação é dito interno, se o
conjunto de todos os dados a ordenar couber na memória;
caso contrário é dito externo
ex: ordenar dados lidos de tape ou disco é ordenação externa
 Distinção muito importante:
 ordenação interna pode aceder a qualquer dado facilmente
 ordenação externa tem de aceder a dados de forma sequencial (ou em
blocos)
 Vamos estudar fundamentalmente ordenação interna

7 AED (IST/DEEC)
Nomenclatura [4]
 Definição – um algoritmo de ordenação é dito directo se os
dados são acedidos directamente nas operações de
comparação e troca; caso contrário é 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, número de BI,
etc)
 nestes casos não convém estar a trocar os elementos
 é dispendioso
 basta trocar a informação correspondente aos seus índices
 tabela de índices/ponteiros em que o primeiro indica o menor elemento, etc

8 AED (IST/DEEC)
Contexto de utilização
 Mesmo programa, diferentes drivers para diferentes algoritmos
#include <stdio.h>
#include <stdlib.h>

main (int argc, char *argv[]){


int i=0, N = atoi (argv[1]), sw = atoi (argv[2]);
int *a = malloc (N * sizeof(int));

if (sw)
for (i = 0; i < N; i++)
a[i] = 1000 * (1.0 * rand() / RAND_MAX);
else
while (scanf(“%d”, &a[i]) == 1 && i<N) i++;
sort (a, 0, N-1);
for (i = 0; i < N; i++) printf(“%3d”, a[i]);
printf(“\n”);
}

 Para cada algoritmo, “sort” tem nome apropriado

9 AED (IST/DEEC)
Ordenação por selecção - Selection Sort
 Um dos mais simples
 Algoritmo
 procurar menor elemento e trocar com o elemento na 1a posição
 procurar 2o menor elemento e trocar com o elemento na 2a posição
 proceder assim até ordenação estar completa

...
void selection (Item a[], int l, int r)
{
int i, j;
Ciclo
for (i = l; i < r; i++) { Ciclo interior
int min = i; exterior
for (j = i+1; j <= r; j++)
if (less(a[j], a[min])) min = j;
exch(a[i], a[min])
}
}

10 AED (IST/DEEC)
Selection Sort - Exemplo de Aplicação
A S O R T I N G E X A M P L E
A S O R T I N G E X A M P L E
A A O R T I N G E X S M P L E
A A E R T I N G O X S M P L E
A A E E T I N C
G O X S M P L R
A A E E G I N T O X S M P L R
A A E E G I N T O X S M P L R
A A E E G I L T O X S M P N R
A A E E G I L M O X S T P N R
A A E E G I L M N X S T P O R
A A E E G I L M N O S T P X R
A A E E G I L M N O P T S X R
A A E E G I L M N O P R S X T
A A E E G I L M N O P R S X T
A A E E G I L M N O P R S T X
A A E E G I L M N O P R S T X

27 AED (IST/DEEC)
Selection Sort - Análise
 Ciclo interno apenas faz comparações
 troca de elementos é feita fora do ciclo interno
 cada troca coloca um elemento na sua posição final
 número de trocas é 𝑁 − 1 (porque não 𝑁?)
 tempo de execução dominado pelo número de comparações!
 Propriedade – Selection sort usa aproximadamente 𝑁2/2
comparações e 𝑁 trocas
 Demonstração – para cada item 𝑖 de 1 a 𝑁 − 1 há uma troca e
𝑁 − 𝑖 comparações (ver zona não sombreada no exemplo)
 Logo há 𝑁 − 1 trocas e (𝑁 − 1) + (𝑁 − 2) + ⋯ + 2 + 1 = 𝑁(𝑁 − 1)/2 comparações
 Factos – desempenho é independente da ordenação inicial dos
dados;
 a única coisa que depende desta ordenação é o número de vezes que min
é actualizado (quadrático no pior caso, 𝑁 log 𝑁 em média)

28 AED (IST/DEEC)
Ordenação por inserção - Insertion Sort
 Ideia: considerar os elementos um a um e inseri-los no seu lugar
entre os elementos já tratados (mantendo essa ordenação)
 ex: ordenar cartas de jogar
 inserção implica arranjar novo espaço ou seja mover um número
elevado de elementos uma posição para a direita
 inserir os elementos um a um começando pelo da 1a posição
#define less(A, B) (key(A) < key(B)) ...
#define exch(A, B) {Item t = A; A = B; B = t; }
#define compexch(A, B) if (less(B,A)) exch(A, B)
Ciclo
void insertion(Item a[], int l, int r) interior
{ Ciclo
int i, j; exterior

for (i = l+1; i <= r; i++)


for (j = i; j > l; j--)
compexch (a[j-1], a[j]);
}

29 AED (IST/DEEC)
Insertion Sort - Comentários
 Elementos à esquerda do índice corrente, 𝒊, estão ordenados
mas não necessariamente na sua posição final
 podem ainda ter de ser deslocados para a direita para dar lugar a
elementos menores encontrados posteriormente
 Implementação da ordenação por inserção no acetato anterior
é ineficiente
 código é simples, claro mas pouco eficiente; pode ser melhorado
 ilustra bom raciocínio:
 encontrar solução simples
 estudar o seu funcionamento
 melhorar desempenho através de pequenas transformações

30 AED (IST/DEEC)
Insertion Sort - Melhorar desempenho
 Demasiadas operações de comparação/troca (compexch)
 podemos parar se encontramos uma chave que não é maior que a do
item a ser inserido (tabela está ordenada à esquerda)
 podemos sair do ciclo interno se less(a[j-1], a[j]) é verdadeira
 modificação torna o algoritmo adaptativo
 aumenta desempenho aproximadamente por um factor de 2
 Passa a haver duas condições para sair do ciclo
 mudar para um ciclo while
 remover instruções irrelevantes
 compexch não é o melhor processo de mover vários dados uma posição
para a direita

31 AED (IST/DEEC)
Insertion Sort - Versão adaptativa

void insertion(Item a[], int l, int r)


{
int i, j;

for (i = l+1; i <= r; i++)


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

32 AED (IST/DEEC)
Insertion Sort - Exemplo de Aplicação
A S O R T I N G E X A M P L E
A S O R T I N G E X A M P L E
A O S R T I N G E X A M P L E
A O R S T I N G E X A M P L E
A O R S T I N G E X A M P L E
A I O R S T N G E X A M P L E
A I N O R S T G E X A M P L E
A G I N O R S T E X A M P L E
A E G I N O R S T X A M P L E
A E G I N O R S T X A M P L E
A A E G I N O R S T X M P L E
A A E G I M N O R S T X P L E
A A E G I M N O P R S T X L E
A A E G I L M N O P R S T X E
A A E E G I L M N O P R S T X
A A E E G I L M N O P R S T X

49 AED (IST/DEEC)
Insertion Sort - Análise
 Propriedade – Insertion sort usa aproximadamente 𝑁2/4
comparações e 𝑁2/4 pseudo-trocas (translações ou
movimentos) no caso médio e o dobro destes valores no pior
caso
 Demonstração – Fácil de ver graficamente; elementos abaixo
da diagonal são contabilizados (todos no pior caso)
Para dados aleatórios é expectável que cada elemento seja
colocado aproximadamente a meio para trás pelo que apenas
metade dos elementos abaixo da diagonal devem ser
contabilizados
 Factos – em certos casos Insertion sort pode ter bom
desempenho (a ver...)

50 AED (IST/DEEC)
Bubble Sort
 Talvez o algoritmo mais utilizado e o que muitas pessoas
aprendem
 Ideia – fazer múltiplas passagens pelos dados trocando de cada
vez dois elementos adjacentes que estejam fora de ordem, até
não haver mais trocas
 supostamente muito fácil de implementar
 usualmente mais lento que os dois métodos elementares estudados

void bubble(Item a[], int l, int r) ...


{
int i, j;
for (i = l; i < r; i++) Ciclo
for (j = r; j > i; j--) interior
Ciclo
compexch(a[j-1], a[j]);
}
exterior

51 AED (IST/DEEC)
Bubble Sort - Exemplo de Aplicação
(Ciclo interior)
A S O R T I N G E X A M P L E
A S O R T I N G E X A M P E L
A S O R T I N G E X A M E P L
A S O R T I N G E X A E M P L
A S O R T I N G E X A E M P L
A S O R T I N G E A X E M P L
A S O R T I N G A E X E M P L
A S O R T I N A G E X E M P L
A S O R T I A N G E X E M P L
A S O R T A I N G E X E M P L
A S O R A T I N G E X E M P L
A S O A R T I N G E X E M P L
A S A O R T I N G E X E M P L
A A S O R T I N G E X E M P L
A A S O R T I N G E X E M P L

67 AED (IST/DEEC)
Bubble Sort - Exemplo de Aplicação
(Ciclo exterior)
A S O R T I N G E X A M P L E
A A S O R T I N G E X E M P L
A A E S O R T I N G E X L M P
A A E E S O R T I N G L X M P
A A E E G S O R T I N L M X P
A A E E G I S O R T L N M P X
A A E E G I L S O R T M N P X
A A E E G I L M S O R T N P X
A A E E G I L M N S O R T P X
A A E E G I L M N O S P R T X
A A E E G I L M N O P S R T X
A A E E G I L M N O P R S T X
A A E E G I L M N O P R S T X
A A E E G I L M N O P R S T X
A A E E G I L M N O P R S T X
A A E E G I L M N O P R S T X

83 AED (IST/DEEC)
Bubble Sort - Comentários [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 posição
 na segunda passagem o 2o elemento mais pequeno é colocado na sua
posição e por diante
 N passagens pelos dados são suficientes!
 É semelhante ao método de selecção
 tem mais trabalho para colocar cada elemento na sua posição final
 todas as trocas sucessivas até chegar à posição certa

84 AED (IST/DEEC)
Bubble Sort - Comentários [2]
 Algoritmo pode ser melhorado, tal como o algoritmo de
inserção
 código é muito semelhantes mas não igual
 ciclo interno de Insertion Sort percorre a parte esquerda(ordenada) da tabela
 ciclo interno de Bubble Sort percorre a parte direita(não ordenada) da tabela
 no final de cada passagem podemos testar se houve mudanças

85 AED (IST/DEEC)
Bubble Sort - Análise
 Propriedade – Bubble sort usa aproximadamente 𝑁2/2
comparações e 𝑁2/2 trocas no caso médio e no pior caso
 Demonstração – A 𝑖-ésima passagem de Bubble Sort requer
𝑁 − 𝑖 operações de comparação/troca, logo a demonstração é
semelhante a Selection sort
 Factos – Algoritmo pode depender criticamente dos dados se
for modificado para terminar quando não houver mais trocas
 se o ficheiro estiver ordenado, apenas um passo é necessário
 se estiver em ordenação inversa então na 𝑖-ésima passagem são precisas
𝑁 − 1 comparações e trocas
 caso médio é semelhante (análise mais complexa)

86 AED (IST/DEEC)
Comparação dos algoritmos
elementares de ordenação [1]
 Tempos de execução quadráticos

Selection Insertion Bubble


Comparações 𝑁2/2 𝑁2/4 𝑁2/2
Trocas 𝑁 𝑁2/4 𝑁2/2

87 AED (IST/DEEC)
Comparação dos algoritmos
elementares de ordenação [2]
 Ficheiros com elementos grandes e pequenas chaves
 Selection Sort é linear no número de dados
 𝑁 dados com tamanho 𝑀 (palavras/words)
 comparação - 1 unidade; troca - 𝑀 unidades
 𝑁2/2 comparações e 𝑁𝑀 custo de trocas
 termo 𝑁𝑀 domina
 custo proporcional ao tempo necessário para mover os dados
 Ficheiros quase ordenados
 Insertion sort e Bubble sort são quase lineares
 os melhores algoritmos de ordenação podem ser quadráticos neste
caso!

88 AED (IST/DEEC)
Comparação dos algoritmos
elementares de ordenação [3]

89 AED (IST/DEEC)
Ordenação – Síntese da Aula 1
 Introdução ao problema da ordenação de dados
 Definição das regras base e interface de utilização
 Macros e operações elementares relevantes
 Ordenação por Selecção – “Select sort”
 Descrição, exemplo de aplicação e análise de eficiência
 Ordenação por inserção – “Insertion sort”
 Versão elementar e versão adaptativa
 Exemplo de aplicação e análise de Eficiência
 “Bubble sort” – Breve referência
 Descrição do algoritmo e análise de funcionamento
 Exemplo de aplicação e análise de eficiência
 Comparação dos três algoritmos elementares
 Em número de comparações e trocas
 Na evolução da tabela durante a execução – exemplo gráfico

90 AED (IST/DEEC)
Shellsort - Melhorar a eficiência [1]
 Insertion sort é lento porque apenas envolve trocas entre items
adjacentes
 Se o menor item está no final da tabela, serão precisos 𝑁 passos para o
colocar na posição correcta
 Talvez se pudesse acelerar o algoritmo permitindo trocas
entre elementos que estão afastados
 Como?
 Que tal fazer trocas entre elementos que estejam a uma distância fixa
(maior que uma posição) entre si?
 Shellsort

91 AED (IST/DEEC)
Shellsort - Melhorar a eficiência [2]
 Ideia – rearranjar os dados de forma a que tenham a
propriedade tal que olhando para cada ℎ-ésimo elemento
estão ordenados
 dados dizem-se ℎ-ordenados
 é equivalente a ℎ sequências ordenadas entreligadas (entrelaçadas)
 Usando valores de ℎ grandes é possível mover elementos na
tabela grandes “distâncias”, o que torna mais fácil ℎ-ordenar
mais tarde com valores mais baixos de ℎ
 usando este procedimento para qualquer sequência de 𝒉's que termine
em 1 produzir-se-á um ficheiro ordenado
 cada passo torna o próximo mais simples

92 AED (IST/DEEC)
Shellsort - Melhorar a eficiência [3]
 Outra forma de ver o algoritmo
 A tabela é dividida em partições, cada uma contendo os objectos de
índice %ℎ
 Exemplo – para uma tabela de 16 posições e ℎ = 4
 índices resto 0, 𝑖%4 = 0, são: 0, 4, 8, 12
 índices resto 1, 𝑖%4 = 1, são: 1, 5, 9, 13
 índices resto 2, 𝑖%4 = 2, são: 2, 6, 10, 14
 índices resto 3, 𝑖%4 = 3, são: 3, 7, 11, 15

 dentro de cada partição é feita uma ordenação por inserção


 Exemplo permite visualizar bem o algoritmo...

93 AED (IST/DEEC)
ℎ-Ordenação - Exemplo: ℎ = 4
A S O R T I N G E X A M P L E
A S O R E I N G T X A M P L E 𝒊%𝟒 = 𝟎
𝟎, 𝟒, 𝟖, 𝟏𝟐
A S O R E I N G P X A M T L E

A I O R E S N G P X A M T L E
A I O R E S N G P X A M T L E 𝒊%𝟒 = 𝟏
𝟏, 𝟓, 𝟗, 𝟏𝟑
A I O R E L N G P S A M T X E

A I N R E L O G P S A M T X E
𝒊%𝟒 = 𝟐
A I A R E L N G P S O M T X E
𝟐, 𝟔, 𝟏𝟎, 𝟏𝟒
A I A R E L E G P S N M T X O

A I A G E L E R P S N M T X O 𝒊%𝟒 = 𝟑
A I A G E L E M P S N R T X O 𝟑, 𝟕, 𝟏𝟏

A I A G E L E M P S N R T X O

106 AED (IST/DEEC)


Implementação de Shellsort [1]
 Possível fazer melhor: sub-ficheiros são independentes
 quando ℎ-ordenamos os dados inserimos qualquer elemento entre os
do seu (ℎ) sub-ficheiro movendo elementos maiores para a direita
 basta usar código de insertion com incrementos/decrementos
de ℎ em vez de 1
 implementação de Shellsort usa um passo de Insertion sort pelo ficheiro
para cada incremento
 Tabela não fica completamente ordenada depois da 1a
ordenação das várias partições
 é necessário repetir com uma série de partições
 isto é, não basta escolher/usar um só ℎ!

107 AED (IST/DEEC)


Shellsort - Exemplo de aplicação [1]
As partições estão entrelaçadas

A S O R T I N G E X A M P L E
A I O R T S N G E X A M P L E
A I N R T S O G E X A M P L E
A I N G T S O R E X A M P L E
A I N G E S O R T X A M P L E
A I N G E S O R T X A M P L E
A I A G E S N R T X O M P L E
A I A G E S N M T X O R P L E
A I A G E S N M P X O R T L E
A I A G E L N M P S O R T X E
A I A G E L E M P S N R T X O

108 AED (IST/DEEC)


Implementação de Shellsort [2]
 Solução óbvia – para cada valor de ℎ usar Insertion Sort de
forma independente em cada um dos ℎ sub-ficheiros
int h = 4;
for (i = l+h; i <= r; i++)
{
Item v = a[i];
j = i;
while (j-h >= l && less(v, a[j-h]))
{
a[j] = a[j-h];
j -= h;
}
a[j] = v;
}

 Então, teremos que definir uma sequência para os valores de ℎ


a utilizar

109 AED (IST/DEEC)


Sequência de Ordenação
 Difícil de escolher
 Propriedades de muitas sequências foram já estudadas
 Possível provar que umas são melhores que outras
 exemplo: 1, 4, 13, 40, 121, 364, 1093, 3280, ... (Knuth, 3 ∗ ℎ𝑎𝑛𝑡 + 1) melhor que 1,
2, 4, 8, 16, 32, 64, 128, 256, 512, ... (Shell, 2𝑖 )
 Porquê?
mas pior (20%) que 1, 8, 23, 77, 281, 1073, 4193, … (4𝑖+1 + 3 ∗ 2𝑖 + 1)
 Na prática utilizam-se sequências que decrescem geometricamente para
que o número de incrementos seja logarítmico
 A sequência óptima não foi ainda descoberta (se é que existe)
 Análise do algoritmo é desconhecida
 ninguém encontrou a fórmula que define a complexidade
 complexidade depende da sequência

110 AED (IST/DEEC)


Implementação de Shellsort [3]
void shellsort(Item a[], int l, int r)
{
int i, j, k;
int incs[16] = {1391376, 463792, 198768, 86961, 33936,
13776, 4592, 1968, 861, 336, 112, 48,
21, 7, 3, 1};
for ( k = 0; k < 16; k++) {
int h = incs[k];

for (i = l+h; i <= r; i++) {


Item v = a[i];
j = i;
while (j-h >= l && less(v, a[j-h])) {
exch(a[j], a[j-h]); /* a[j] = a[j-h]; */
j -= h;
}
a[j] = v;
}
}
}

111 AED (IST/DEEC)


Shellsort - Exemplo de aplicação [2]
𝒉 = 𝟏𝟑
A S O R T I N G E X A M P L E
A S O R T I N G E X A M P L E 𝒉 = 𝟏
A E A G E I N M P L O R T X S
A E O R T I N G E X A M P L S
A A E G E I N M P L O R T X S
A A E G E I N M P L O R T X S

𝒉 = 𝟒 A A E E G I N M P L O R T X S

A E O R T I N G E X A M P L S A A E E G I N M P L O R T X S

A E O R T I N G E X A M P L S A A E E G I N M P L O R T X S

A E N R T I O G E X A M P L S A A E E G I M N P L O R T X S

A E N G T I O R E X A M P L S A A E E G I M N P L O R T X S

A E N G E I O R T X A M P L S A A E E G I L M N P O R T X S

A E N G E I O R T X A M P L S A A E E G I L M N O P R T X S

A E A G E I N R T X O M P L S A A E E G I L M N O P R T X S

A E A G E I N M T X O R P L S A A E E G I L M N O P R T X S

A E A G E I N M P X O R T L S A A E E G I L M N O P R T X S

A E A G E I N M P L O R T X S A A E E G I L M N O P R S T X

A E A G E I N M P L O R T X S A A E E G I L M N O P R S T X

112 AED (IST/DEEC)


Análise de Shellsort
 Propriedades
 O resultado de ℎ-ordenar um ficheiro que está 𝑘-ordenado é um ficheiro que
está simultaneamente ℎ- e 𝑘-ordenado

 Shellsort faz menos do que 𝒪(𝑁 2 ) comparações para os incrementos 1, 4, 13,
40, 121, 364, 1093, ...
4
 Shellsort faz menos do que 𝒪(𝑁 Τ3 ) comparações para os incrementos 1, 8, 23,
77, 281, 1073, 4193, 16577, ...
 Nota: sequências até agora usam incrementos que são primos entre si
 Shellsort faz menos do que 𝒪(𝑁log 2 𝑁) comparações para os incrementos 1, 2, 3,
4, 6, 9, 8, 12, 18, 27, 16, 24, 36, 54, 81
 Shellsort é um exemplo de um algoritmo simples cuja análise é
complicada
 sequência óptima, e análise completa não são conhecidos!
 Alguém consegue encontrar uma sequência que bata1, 2, 7, 21, 48, 112, 336, ...??

113 AED (IST/DEEC)


Shellsort - Exemplo Gráfico e Vantagens
 Graficamente parece que um elástico, preso nos cantos, puxa
os pontos para a diagonal

 Vantagens do Shellsort
 Rápido/eficiente
 Pouco código
 Melhor método para ficheiros pequenos e médios
 Aceitável para elevados volumes de dados
 Muito utilizado na prática, embora dificil de compreender!
114 AED (IST/DEEC)
Ordenação de outros tipos de dados [1]
 Algoritmos estudados são independentes do tipo de dados
 necessário o interface apropriado e a implementação correspondente
#include <stdlib.h>

main (int argc, char *argv[])


{
int N = atoi (argv[1]), sw = atoi (argv[2]);
int *a = malloc (N * sizeof(int));

if (sw) for (i = 0; i < N; i++)


randinit(a, N); a[i] = 1000 * (1.0*rand()/RAND_MAX);
else
scaninit(a, &N);
while (scanf(“%d”, &a[N]) == 1) N++;
sort (a, 0, N-1);
show (a, 0, N-1);
} for (i = 0; i < N; i++)
printf(“%3d”, a[i]);
printf(“\n”);

115 AED (IST/DEEC)


Ordenação de outros tipos de dados [2]
 Algoritmos estudados são independentes do tipo de dados
 necessário o interface apropriado e a implementação correspondente
#include <stdlib.h>
#include “Item.h”
#include “Array.h”

main (int argc, char *argv[])


{
int N = atoi (argv[1]), sw = atoi (argv[2]);
Item *a = malloc (N * sizeof(Item));

if (sw)
randinit(a, N);
else
scaninit(a, &N);
sort (a, 0, N-1);
show (a, 0, N-1);
}

116 AED (IST/DEEC)


Ordenação de outros tipos de dados [3]
 Definição do interface
 O tipo apropriado e as funções para sua manipulação

typedef double Item;


#define key(A) (A)
#define less(A, B) (key(A) < key(B))
#define exch(A, B) {Item t = A; A = B; B = t; }

Item.h
#define compexch(A, B) if (less(B,A)) exch(A, B)

Item ITEMrand(void);
Interface para
int ITEMscan(Item *);
void ITEMshow(Item); tipo Item

void randinit (Item [], int);

Array.h
void scaninit (Item [], int *);
void show (Item [], int, int); Interface para
void sort (Item [], int, int); tipo tabela de Items

117 AED (IST/DEEC)


Ordenação de outros tipos de dados [4]
 Implementação do interface
 Implementação das funções que operam sobre os dados
#include <stdio.h>
#include <stdlib.h>
#include “Item.h” Implementação para tipo
Item (double)
double ITEMrand(void){
return 1.0 * rand() / RAND_MAX;
}

int ITEMscan(double *x){


return scanf(“%lf”, x);
}

void ITEMshow(double x){


printf(“%7.5lf “, x);
}

118 AED (IST/DEEC)


Ordenação de outros tipos de dados [5]
 Implementação do interface
 Implementação das funções que operam sobre os dados
#include <stdio.h>
#include <stdlib.h>
#include “Item.h” Implementação para
#include “Array.h” tipo tabela de Items
void randinit(Item a[], int N){
int i;
for (i = 0; i < N; i++) a[i] = ITEMrand();
}

void scaninit(Item a[], int *N){


int i =0;;
for (i = 0; i < *N; i++)
if (ITEMscan(&a[i]) == EOF) break;
*N = i;
}

void show(Item a[], int l, int r){


int i;
for (i = l; i <= r; i++) ITEMshow(a[i]);
printf(“\n”);
}
119 AED (IST/DEEC)
Ordenação de outros tipos de dados [6]
 Para qualquer tipo de dados
 Apenas alterar o interface
 Reescrever as funções que operam sobre os objectos
 rand
 show
 exch
 etc.
 Algoritmos e rotinas de ordenação (sorting) não necessitam de qualquer
alteração

120 AED (IST/DEEC)


Ordenação por índices [1]
 Suponha-se que os objectos a ordenar são strings (vectores de
caracteres):
 funções que operam sobre os dados precisam de ter em conta a questão
da alocação de memória para strings
 quem deve ser responsável pela gestão desta memória?
 e se os objectos são "grandes"? Comparar e mover os objectos pode
ser dispendioso!
 imagine que cada objecto é o nome completo de um aluno (ou que é toda a
sua informação: nome, morada, etc)
 mesmo que haja uma boa abstracção para operar sobre os objectos
ainda há a questão do custo
 Porquê movê-los?
 porque não alterar apenas referência para a sua posição relativa?

121 AED (IST/DEEC)


Ordenação por índices [2]
 Solução 1:
 dados numa tabela 𝑑𝑎𝑡𝑎[0], … , 𝑑𝑎𝑡𝑎[𝑁 − 1]
 usar uma segunda tabela, 𝑎[. ], apenas de índices
 inicializado de forma a que 𝑎[𝑖] = 𝑖, 𝑖 = 0, … , 𝑁 − 1
 objectivo é rearranjar a tabela de índices de forma a que 𝑎[0] aponte
para o objecto com a menor chave, etc
 objectos são apenas acedidos para comparação
 Rotinas de ordenação apenas acedem aos dados através de
funções de interface: less, exch, etc
 apenas estas têm de ser reescritas

122 AED (IST/DEEC)


Ordenação por índices - Exemplo
 Suponha os seguintes dados:
 𝑑𝑎𝑡𝑎 = [“rui”, “carlos”, “luis”]
 usamos uma tabela, de índices 𝑎 = [0, 1, 2]
 1o passo: comparar 𝑑𝑎𝑡𝑎[𝑎[1]] com 𝑑𝑎𝑡𝑎[𝑎[0]]: “carlos” < “rui”
pelo que há troca de 𝑎[1] com 𝑎[0]: 𝑎 = [ 1, 0, 2 ]
 2o passo: comparar 𝑑𝑎𝑡𝑎[𝑎[2]] com 𝑑𝑎𝑡𝑎[𝑎[1]]: “rui” < “luis”
pelo que há troca de 𝑎[2] com 𝑎[1]: 𝑎 = [ 1, 2, 0 ]
 3o passo: comparar 𝑑𝑎𝑡𝑎[𝑎[1]] com 𝑑𝑎𝑡𝑎[𝑎[0]]: “carlos” < “luis”
pelo que não há troca
 Os valores ordenados são portanto 𝑑𝑎𝑡𝑎[𝑎[0]], 𝑑𝑎𝑡𝑎[𝑎[1]] e
𝑑𝑎𝑡𝑎[𝑎[2]]
ou seja, “carlos” < “luis” < “rui”
(de forma encapotada usámos uma “espécie” de Insertion sort)

123 AED (IST/DEEC)


Ordenação por ponteiros
 Outra solução é a tabela de índices conter de facto ponteiros
para os dados
 Mais geral pois os ponteiros podem apontar para qualquer lado
 items não precisam de ser membros de uma tabela
 nem de ter todos o mesmo tamanho
 Depois da ordenação, acesso sequencial à tabela de ponteiros devolve os
elementos ordenados
 Um exemplo é a função qsort, do C, que implementa o
algoritmo quicksort (estudaremos adiante)
void qsort(void *array, size_t nItems, size_t sizeItem,
int(*compar)(const void *, const void *));

124 AED (IST/DEEC)


Ordenação por ponteiros ou índices
 Não-intrusiva em relação aos dados
 pode ser efectuada se os dados forem apenas de leitura
 Possível efectuar ordenação em chaves múltiplas
 exemplo: listagens de alunos, com nome, número e nota
 Evita o custo de mover/trocar os items
 pode ser elevado se estes forem grandes quantidades de informação
 mais eficiente em problemas com dados grandes e chaves pequenas
 E se for preciso retornar os dados ordenados?
 ordenar por índice/ponteiro
 fazer permutações in-situ (como?)

125 AED (IST/DEEC)


Ordenação de listas ligadas
 Semelhante a ordenação de tabelas
 funções de interface diferentes
 necessário trabalhar com ponteiros e não apenas com índices
 Trocas podem não ser possíveis
 elementos podem ser acedidos por outras estruturas de dados
 trocam-se apenas os ponteiros
 inserções são na verdade mais simples
 não é preciso mover elementos para a direita, apenas ajustar dois ponteiros
 Algoritmos básicos
 alterações simples

126 AED (IST/DEEC)


Exercício - usar Selection Sort para ordenar uma
lista ligada
 Estruturas de Dados:
 lista de entrada
 lista de saída: dados colocados na sua posição final
 ponteiros adicionais
 Ideia básica
 procurar maior elemento na lista
 manter ponteiro para o anterior
 retirá-lo da lista de entrada
 introduzi-lo no início da lista de saída
 Implemente como exemplo!

127 AED (IST/DEEC)


Ordenação – Síntese da Aula 2
 “Shellsort”
 Variante de aceleração do “Insertion sort”
 Descrição e implementação: sequências de ordenação
 Exemplo de aplicação e discussão da eficiência do algoritmo
 Exemplo de execução e análise comparativa
 Ordenação de outros tipos de dados
 Implementações estudadas até aqui assumiam ordenação de inteiros
 Definição da interface apropriada
 Protótipos de funções elementares e definição dos dados
 Para evitar mover grandes quantidades de dados
 Ordenação por índices
 Ordenação por ponteiros
 Ordenação em listas ligadas
 Referência às alterações a introduzir nos algoritmos analisados
 Ao nível dos dados de entrada
 Ao nível da interface

128 AED (IST/DEEC)

Você também pode gostar