• Nenhum resultado encontrado

Basicamente, os tipos de algoritmos de ordenação podem ser resumidos a: Por seleção: seleciona o menor elemento, o segundo menor e assim por diante

N/A
N/A
Protected

Academic year: 2021

Share "Basicamente, os tipos de algoritmos de ordenação podem ser resumidos a: Por seleção: seleciona o menor elemento, o segundo menor e assim por diante"

Copied!
13
0
0

Texto

(1)

Ordenação de dados

Frequentemente, é necessário que os dados devam ser armazenados obedecendo uma determinada ordem. A ordenação de dados é uma atividade relevante e fundamental em processamento de dados.

Ordenação corresponde ao método de rearranjar um conjunto de objetos em uma ordem crescente ou decrescente e tem como objetivo facilitar a recuperação dos itens do conjunto

Alguns algoritmos podem explorar a ordenação dos dados para operar de maneira mais eficiente, do ponto de vista de desempenho computacional. Para obtermos os dados ordenados, temos basicamente duas alternativas: ou inserimos os elementos na estrutura de dados respeitando a ordenação (dizemos que a ordenação é garantida por

construção), ou, a partir de um conjunto de dados já criado, aplicamos um algoritmo para ordenar seus elementos.

As principais linguagens de programação atuais possuem funções para ordenação de dados. Entretando, muitas vezes é preciso implementar extensões enquanto a operação de ordenação está em curso, seja para adicionar propriedades aos dados, seja para guardar determinadas informações desse processo.

Basicamente, os tipos de algoritmos de ordenação podem ser resumidos a: • Por troca: troca os elementos ordenando-os

• Por seleção: seleciona o menor elemento, o segundo menor e assim por diante • Por inserção: reinsere os elementos na estrutura reordenando os mesmos Classificação quanto à estabilidade:

• Métodos instáveis: a ordem relativa dos itens com chaves iguais é alterada durante o processo de ordenação

• Métodos estáveis: se a ordem relativa dos itens com chaves iguais mantém-se inalterada durante o processo. Exemplo: se uma lista dos funcionários é ordenada pelo campo “Salário”, um método estável produz uma lista em que os funcionários com o mesmo salário aparecem em ordem alfabética

Alguns dos métodos de ordenação mais eficientes não são estáveis. Classificação quanto ao conjunto de registros:

• Ordenação Interna: o conjunto de registros cabe todo em na memória principal Ordenação por inserção (direta e Shell Sort)

Ordenação por troca (Bolha e QuickSort) Ordenação por seleção (Direta e HeapSort)

Ordenação por distribuição (distribuição de chaves e RadixSort) Ordenação por intercalação (MergeSort)

(2)

• Ordenação Externa: o conjunto de registros não cabe completamente em memória principal, e deve ser armazenado em disco ou fita.

Medidas de complexidade levam em conta:

• O número de comparação entre as chaves • O número de trocas entre os itens

Classificação quanto aos métodos de ordenação:

1. Métodos Simples: mais recomendados para conjuntos pequenos de dados. Usam mais comparações, mas produzem códigos menores e mais simples Ordenação por Seleção (Selection Sort)

Ordenação por Inserção (Insertion Sort) Ordenação por Seleção e Troca (Bubble Sort)

2. Métodos Eficientes ou Sofisticados: adequados para conjuntos maiores de dados. Usam menos comparações, porém produzem códigos mais complexos e com muitos detalhes.

Ordenação por Inserção através de incrementos decrescentes (ShellSort) Ordenação por Particionamento (QuickSort)

Ordenação de Árvores (HeapSort)

Ordenação por seleção

Um dos algoritmos mais simples, recomendado para conjuntos pequenos. A idéia é sempre procurar o menor elemento do vetor e inseri-lo no início do vetor. Procuramos o menor valor do vetor e colocamos ele em vetor[1]. Procuramos o menor valor do vetor excluindo o já colocado e colocamos ele em vetor[2]. E assim vamos indo até termos todo o vetor ordenado.

1. para i 1 até tamanho-1, faça 2. minimo i

3. para j i+1 até tamanho, faça 4. se vetor[j] < vetor[minimo], então 5. minimo j

6. fim-se 7. fim-para

(3)

9. vetor[i] vetor[minimo] 10. vetor[minimo] temp

1. fim-para

Partindo sempre a partir do último elemento reordenado (a partir do i), o programa procura o menor elemento no vetor e o substitue pelo elemento i atual.

O programa recebe o seguinte vetor.

v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 5 3 7 8 2 5

Aí ele começa com .

v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 5 3 7 8 2 5

Ele marca o próprio índice i como a variável minimo, que é sempre o menor elemento do vetor. Então, ele faz um para de até o comprimento do vetor, com o objetivo de descobrir qual o menor elemento.

... , portanto . v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 5 3 7 8 2 5

... , portanto não mexemos em nada. ... , portanto não mexemos em nada.

... , portanto .

(4)

1] 2] 3] 4] 5] 6] 5 3 7 8 2 5

... , portanto não mexemos em nada. Agora substituímos o v[minimo] pelo v[i], formando com isto o novo vetor:

v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 2 3 7 8 5 5

E assim vamos fazendo com os outros elementos até que todo o vetor esteja ordenado. Resumo do algoritmo:

• Seleciona o elemento de menor valor e o troca pelo primeiro. Faz-se o mesmo com os elementos restantes.

• executa-se o processo tantas vezes quanto o número de elementos no array menos um

• varre o array a partir dos elementos ainda não ordenados

Implementação void selecao(int a[]) { int r = TAM -1; int i, j, t;

for (i = 0; i < r; i++) { int min = i;

for (j = i+1; j <= r; j++) if (a[j] < a[min]) min = j; t = a[i]; a[i] = a[min]; a[min] = t; }

}

Ordenação por inserção

Também conhecida como Insertion Sort, é um dos métodos mais simples para ordenar um array. Um exemplo típico ocorre num jogo de cartas. Para classificar as cartas em uma mão, uma carta é retirada, muda-se as cartas restantes e em seguida a carta retirada é inserida no no local correto. Este processo é repetido até que todas as cartas estejam na seqüência correta.

(5)

Essa opção é boa quando temos uma entrada pequena de dados. Para entradas grandes pode se consumir muito tempo de processamento.

1. para j 2 até comprimento do vetor, faça 2. elemento vetor[j]

3. i j - 1

4. enquanto i > 0 e vetor[i] > elemento, faça 5. vetor[i + 1] vetor[i]

6. i i - 1 7. fim-enquanto

8. vetor[i + 1] elemento 1. fim-para

Vamos iniciar com o seguinte vetor v.

v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 5 3 7 8 2 5

Aí o código me manda começar com e iterar até o comprimento do vetor (6). A primeira ordem que ele me dá é para armazenar o elemento ( ) na variável elemento. Para facilitar toda a explicação eu vou sempre pintar de cinza o onde eu estou (no caso, o segundo elemento do vetor, 3) e de preto o vetor ainda não ordenado (elementos ). v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 5 3 7 8 2 5

Então ele me diz que . Portanto, . E agora ele me faz um enquanto (que poderia ser substituído por para) onde meu i deverá ir diminuindo. Vamos entrar no loop... Bom, meu é maior que 0. é maior que o ? Sim, então vamos entrar no corpo do enquanto... Aqui ele me manda fazer um , que nesse caso é fazer um .

(6)

1] 2] 3] 4] 5] 6] 5 5 7 8 2 5

E agora subtrae de i um valor. Portanto, . Ele retorna ao enquanto, mas agora não satisfazemos a condição , por isso saímos do enquanto. Então ele pede para

( ). Portanto, o vetor fica assim:

v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 3 5 7 8 2 5 E incrementamos o j, agora . v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 3 5 7 8 2 5

... E ? Não! Portanto, não entramos no enquanto. (nenhuma mudança)

E lá vamos para e continuando até que vamos ter o vetor ordenado:

v[ 1] v[ 2] v[ 3] v[ 4] v[ 5] v[ 6] 2 3 5 5 7 8 Resumo do processo:

• reinsere os elementos no array reordenando o mesmo • ordena os dois primeiros elementos

• do terceiro elemento em diante, os valores são inseridos em relação aos elementos já ordenados

Em termos gerais, o algoritmo percorre um vetor de elementos da esquerda para a direita e à medida que avança vai deixando os elementos mais à esquerda ordenados.

(7)

elementos acima são deslocada para baixo até encontrar o local correto para inserir o 3. Esse processo se repete na b com o próximo número. Finalmente, na c, completa-se o ciclo através da inserção de 2 na posição correta.

Assumindo que existem n elementos na matriz, é preciso percorrer através de n - 1 entradas. Para cada entrada, talvez seja necessário examinar e mudar até n - 1 entradas de outros, resultando em um algoritmo O(n2). Na ordenação por inserção não há memória extra necessária.

Características:

O tipo de inserção é do tipo estável de ordenação interna.

Menor número de trocas e comparações entre os algoritmos de ordenação quando o vetor está ordenado.

Implementação

void insercao(int n, int vetor[]){ int j,i,key;

for(j = 1; j < n; j++){ key = vetor[j]; i = j - 1;

while(i >= 0 && vetor[i] > key){ vetor[i + 1] = vetor[i]; i = i - 1; } vetor[i + 1] = key; } }

BubbleSort

O Bubblesort, ou ordenação em bolha, é um dos mais populares dos algoritmos para ordenação por causa da fácil memorização de funcionamento e como é fácil a sua

implementação. O algoritmo recebeu este nome pela imagem usada para descrevê-lo: os elementos maiores são mais leves, e sobem como bolhas até suas posições corretas. Consiste basicamente em intercalar elementos, por isso se enquadra na categoria de ordenação por intercalação. Com uma estrutura de dados desordenada inicia-se o algoritmo pelo primeiro elemento, depois faz-se a comparação dele com todos os que

(8)

estão depois dele na estrutura desordenada. Quando dois elementos estão fora de ordem, há uma inversão e esses dois elementos são trocados de posição, ficando em ordem correta. Assim, o primeiro elemento é comparado com o segundo. Se uma inversão for encontrada, a troca é feita. Em seguida, independente se houve ou não troca após a primeira comparação, o segundo elemento é comparado com o terceiro, e, caso uma inversão seja encontrada, a troca é feita. O processo continua até que o penúltimo elemento seja comparado com o último.

1. proc bubbleSort(int[] arr) { 2. int tamanho <- tam(arr); 3. int i, aux;

4. para i de 1 incr 1 até tamanho-1 faça 5. para j de tamanho-1 incr -1 até j≥i faça 6. se arr[j-1] > arr[j] então

7. aux <- arr[j-1]; 8. arr[j-1] <- arr[j]; 9. arr[j] <- aux; Implementação

void bolha (int v[]) { int n = TAM; int i,j;

for (i=n-1; i>=1; i--) { int troca = 0; for (j=0; j<i; j++) { if (v[j]>v[j+1]) { int temp = v[j]; v[j] = v[j+1]; v[j+1] = temp; troca = 1; } } if (troca == 0) return; } }

MergeSort

É um algoritmo que segue uma técnica de dividir para conquistar na base de sua idéia principal. O algoritmo Mergesort possibilita a ordenação de dados quebrando o problema-chave em pedaços menores,organizando trechos de dados separados para em seguida, juntar os resultados formando um vetor ordenado.

(9)

A lógica básica é a seguinte: ordenar uma estrutura significa ordenar várias subestruturas internas já ordenadas, caso essas estruturas não estejam ordenadas, basta ordená-las pelo mesmo método (ordenar suas subestruturas internas). Por exemplo: ordenar 6, 3, 4, 8, 1, 2, 3, 5. O algoritmo irá dividir em pares ordenados: {3,6}, {4,8}, {1,2}, {3,5}, depois ir fazendo o merge desses dados, ou seja, juntando-os em dois pares ordenados: {3,4,6,8}, {1,2,3,5}, depois juntar novamente: 1,2,3,3,4,5,6,8. No final do algoritmo a seqüência inicial está ordenada a partir de divisões. Por sua base bem estruturada esse algoritmo tem tempo médio bem rápido.

Resumo do funcionamento: • Dividir para conquistar

• Divide-se o array ao meio e aplica o algoritmo às duas metades separadamente • ao chegar na situação em que o array são dois elementos, ordena os mesmos • algoritmo recursivo

Um dos principais problemas com o MergeSort é que ele faz uso de um array auxiliar. Vantagens:

É eficiente para ordenação externa Fácil implementação

Recomendado para aplicações com restrição de tempo Desvantagens:

Utiliza memória auxiliar Alto consumode memória Complexidade do algoritmo

Melhor caso: nunca é necessário trocar após as comparações Caso médio: há necessidade de trocas após as comparações

Pior caso: sempre é necessário efetuar a troca após as comparações

A complexidade do merge sort é a mesma para o pior, médio e melhor caso.

Independente da situação dos dados no vetor, o algoritmo irá sempre dividir e intercalar os dados

Implementação

void merge(int* input, int p, int r) {

int mid = floor((p + r) / 2); int i1 = 0;

int i2 = p; int i3 = mid + 1; // Temp array int temp[r-p+1];

// Merge in sorted form the 2 arrays while ( i2 <= mid && i3 <= r )

if ( input[i2] < input[i3] ) temp[i1++] = input[i2++]; else

(10)

// Merge the remaining elements in left array while ( i2 <= mid )

temp[i1++] = input[i2++];

// Merge the remaining elements in right array while ( i3 <= r )

temp[i1++] = input[i3++];

// Move from temp array to master array for ( int i = p; i <= r; i++ )

input[i] = temp[i-p]; }

void merge_sort(int* input, int p, int r) {

if ( p < r ) {

int mid = floor((p + r) / 2); merge_sort(input, p, mid); merge_sort(input, mid + 1, r); merge(input, p, r); } }

Quicksort

É considerado como o mais rápido entre os principais métodos de ordenação. A idéia por trás do algoritmo é escolher um valor "médio" (o valor do meio, também chamado pivô, que pode não corresponder exatamente ao valor do meio do vetor, depois de este estar ordenado) do vetor, passar todos os valores maiores do que ele para a frente e todos os menores para trás.

A grande vantagem desse algoritmo é que ele pode ser muito eficiente. O melhor caso ocorre quando o elemento pivô representa o valor mediano do conjunto dos elementos do vetor. Se isto acontece, após o posicionamento do pivô em sua posição, restará dois sub-vetores para serem ordenados, ambos com o número de elementos reduzido a metade, em relação ao vetor original.

Ficamos então com o vetor dividido em duas partes, uma tem todos os valores menores que o valor escolhido, a outra tem todos os valores maiores que o valor escolhido.

Aplicamos agora o algoritmo a cada uma das partes. O processo é repetido até atingirmos partes de tamanho um.

Resumo de funcionamento: • Similar ao mergesort:

• Seleciona-se um valor base para dividir o array em duas partes, uma menor que o valor escolhido e outra maior

• Aplica-se o algoritmo recursivamente para cada uma das partes Implementação

(11)

O Quicksort é um algoritmo de ordenação não-estável. Implementação

int Partition(int low, int high, int arr[]) {

int i, high_vac, low_vac, pivot; pivot = arr[low]; while(high>low) { high_vac = arr[high]; while(pivot<high_vac) { if(high <= low) break; high--; high_vac = arr[high]; } arr[low] = high_vac; low_vac = arr[low]; while(pivot > low_vac) { if(high <= low) break; low++; low_vac = arr[low]; } arr[high] = low_vac; } arr[low] = pivot; return low; }

void Quick_sort(int low, int high, int arr[]) {

int Piv_index; if(low < high) {

Piv_index=Partition(low, high, arr); Quick_sort(low,Piv_index - 1, arr); Quick_sort(Piv_index + 1, high, arr); }

}

ShellSort

Shell Sort é uma ordenação interna e não estável. É mais eficiente que a ordenação por inserção. O algoritmo difere do método de inserção direta pelo fato de no lugar de considerar o array a ser ordenado como um único segmento, ele considera vários segmentos sendo aplicado o método de inserção direta em cada um deles.

(12)

eficiência para as pequenas e medianas.

Abaixo um exemplo de Shell Sort é ilustrado. Começamos por fazer

uma espécie de inserção usando um espaçamento

de duas. No primeiro quadro examinarmos os números 3,5 e

1. Extraindo 1, mudamos 3 para baixo um slot. Em

seguida, examinamos os números 5, 2 e 4. Extraímos 2, transferir 5

para baixo e insirimos 2. Depois da ordenação com um espaçamento

de dois, uma passagem final é feita com um espaçamento de uma

posição.

Implementação

void shellSort(int * vet, int size) { int i , j , value; int gap = 1; do { gap = 3*gap+1; } while(gap < size); do { gap /= 3;

for(i = gap; i < size; i++) { value =vet[i]; j = i - gap;

while (j >= 0 && value < vet[j]) { vet [j + gap] =vet[j];

j -= gap; }

vet [j + gap] = value; }

} while ( gap > 1); }

(13)

Algoritmo Heapsort

Esse algoritmo tem tempo de execução de um algoritmo de ordenação por

intercalação, e faz as suas operações localmente, sempre apenas um

número constante de elementos é armazenados fora da estrutura de dados,

como é feito o algoritmo por inserção. Mas o que ele tem de interessante é a

forma que ele arranja os dados para depois ordená-los, ele utiliza uma

estrutura chamada de heap ou monte, que é uma arvore binária que é

extremamente importante para vários conceitos e problemas

computacionais, pois depois de ordenados os dados, podemos, por exemplo,

saber em que nível da árvore se encontra determinado item, operações

sobre arvores binárias são conceitos muito importantes para outras

estruturas como grafos.

Referências

CELES FILHO, Waldemar; Cerqueira, Renato; Rangel, José Lucas. Introdução a estrutura de dados: com técnicas de programação em C. Rio de Janeiro : Elsevier, 2004 − 7a. Impressão.

DROZDEK, Adam; tradução Luiz Sérgio de Castro Paiva. Estrutura de dados e algoritmos em C++. São Paulo: Cengage Learning, 2010.

MANZANO, José Augusto N. G.; Oliveira, Jayr Figueiredo de. Algoritmos: lógica para desenvolvimento de programação de computadores. São Paulo : Érica, 2010.

SAVITCH, Walter. C++ absoluto. São Paulo: Addison Wesley, 2004.

SILVA FILHO, Antônio Mendes da. Introdução à programação orientada a objetos com C++. Rio de Janeiro : Elsevier, 2010.

SZWARCFITER, L. J.e MARKENZON, L. Estrutura de Dados e Seus Algoritmos. Rio de Janeiro: LTC - Livros Técnicos e Científicos, 1994. 2. edição revista.

TENENBAUM, Aaron M.; LANGSAM, Yedidyah; AUGENSTEIN, Moshe J.; tradução Teresa Cristina Félix de Souza. Estruturas de dados usando C. São Paulo : MAKRON Books, 1995. Cap 6.

VELOSO, P; SANTOS, C; AZEREDO, P e FURTADO, A. Estrutura de Dados. Rio de Janeiro: Campus, 2000.

WIRTH, N. Algoritmos e Estrutura de Dados. Rio de Janeiro: LTC - Livros Técnicos e Científicos, 1999. 2. edição revista. Cap. 2.

Referências

Documentos relacionados

Este EPEI não é muito flexível pois os clientes de cada referência produzida durante o mês terão de esperar até ao início do mês seguinte para receber a sua encomenda do

No entanto, maiores lucros com publicidade e um crescimento no uso da plataforma em smartphones e tablets não serão suficientes para o mercado se a maior rede social do mundo

Realizar a manipulação, o armazenamento e o processamento dessa massa enorme de dados utilizando os bancos de dados relacionais se mostrou ineficiente, pois o

Starting out from my reflection on the words cor, preto, negro and branco (colour, black, negro, white), highlighting their basic meanings and some of their

Essa tolerância pode ser explicada de duas maneiras: a primeira sena uma característica intrínseca das populações de Phytophthora associadas aos citros no Estado de São Paulo, e a

The Anti-de Sitter/Conformal field theory (AdS/CFT) correspondence is a relation between a conformal field theory (CFT) in a d dimensional flat spacetime and a gravity theory in d +

Este trabalho tem como objetivo o estudo numérico/paramétrico do comportamento e capacidade resistente de ligações do tipo “T” compostas por perfis tubulares de paredes

É possível perceber como a interação entre as ciências, incluindo a História da Arte e sua filosofia, situou este pertencimento a uma humanidade plena como principal interface