Upload
deivid-nunes
View
369
Download
7
Embed Size (px)
Citation preview
Ordenação (computação)
Origem: Wikipédia, a enciclopédia livre.
Ordenação é o ato de se colocar os elementos de uma sequência de informações, ou dados, em uma ordem predefinida. O
termo técnico em inglês para ordenação é sorting, cuja tradução literal é "classificação".
Dado uma seqüencia de n dados:
O problema de ordenação é uma permutação dessa seqüencia
tal que
para alguma relação de ordem.
Algumas ordens são facilmente definidas. Por exemplo, a ordem numérica, ou a ordem alfabética -- crescentes
ou decrescentes. Contudo, existem ordens, especialmente de dados compostos, que podem ser não triviais de se
estabelecer.
Um Algoritmo que ordena uma conjunto, geralmente representada num vetor, é chamadado um algoritmos de
ordenação. Entre os mais importantes, podemos citar bubble sort (ou ordenação por flutuação), heap sort (ou
ordenação por heap), insertion sort (ou ordenação por inserção), merge sort (ou ordenação por mistura) e
o quicksort.
Ordenação estável Origem: Wikipédia, a enciclopédia livre.
Um algoritmo de ordenação diz-se estável se preserva a ordem de registros de chaves iguais. Isto é, se tais registros
aparecem na sequência ordenada na mesma ordem em que estão na sequência inicial. [1]
Esta propriedade é útil apenas quando há dados associados às chaves de ordenação.
Exemplo
Por exemplo, um algoritmo estável ordenando a sequência de números (chaves) com letras associadas (registros):
3[a], 2[b], 2[c], 1[d]
obrigatoriamente retornará:
1[d], 2[b], 2[c], 3[a]
enquanto algoritmos instáveis sujeitam os elementos associados aos objetos a serem ordenados a mudanças:
1[d], 2[c], 2[b], 3[a]
Implementação
Certos algoritmos são estáveis a partir de sua concepção original, como o Counting sort ou o Merge sort. Porém. é possível
implementar estabilidade artificialmente em certos algoritmos. Por exemplo, numa comparação de dois objetos de mesmo valor
pode aplicar-se uma comparação adicional para verificar se a ordem original dos registros associados foi mantida. Neste caso,
a implementação de estabilidade requer um custo adicional de eficiência.
Algoritmos estáveis
Alguns algoritmos de ordenação estáveis:
Bubble sort
Cocktail sort
Insertion sort
Merge sort
Bucket sort
Algoritmos instáveis
Alguns algoritmos de ordenação instáveis:
Selection Sort
Quick Sort
Heap Sort
Shell Sort
Counting Sort
Algoritmo de ordenação
Origem: Wikipédia, a enciclopédia livre.
Algoritmo de ordenação em ciência da computação é um algoritmo que coloca os elementos de uma dada sequência em
uma certaordem -- em outras palavras, efetua sua ordenação completa ou parcial. As ordens mais usadas são a numérica e
a lexicográfica.
Existem várias razões para se ordenar uma sequência. Uma delas é a possibilidade se acessar seus dados de modo mais
eficiente.
Métodos de ordenação de vetores
Métodos simples
Insertion sort
Selection sort
Bubble sort
Comb sort
Métodos sofisticados
Quick sort
Merge sort
Heapsort
Shell sort
Radix sort
Gnome sort
Count sort
Bucket sort
Cocktail sort
Timsort
Métodos de pesquisa
Pesquisa binária
Busca linear
BogoBusca
Bogosort Origem: Wikipédia, a enciclopédia livre.
Bogosort (também denominado bozo sort, blort sort e vai-na sort ou Estou com sort) é um algoritmo de
ordenação extremamente ineficiente, baseado na reordenação aleatória dos elementos. Não é utilizado na prática, mas pode
ser usado no ensino de algorítmos mais eficientes. Seu nome veio do engraçado termo quantum bogodynamics e,
ultimamente, a palavra bogus.
Esse algoritmo é probabilístico por natureza. Se todos os elementos a serem ordenados são distintos, a complexidade
esperada é . O tempo exato de execução esperado depende do quantos diferentes valores de elementos
ocorrem, e quantas vezes cada um deles ocorre, mas para casos não-triviais o tempo esperado de execução é exponencial ou
super-exponencial a . Ele termina pela mesma razão do teorema do macaco infinito; existe alguma probabilidade de que
aconteça a permutação correta, dado que em um infinito número de tentativas fatalmente a encontrará.
Deve-se notar que com os algoritmos geradores de números pseudo-aleatórios, que têm um número finito de estados e não
são realmente aleatórios, o algoritmo pode nunca terminar para certos conjuntos de valores a serem ordenados.
Bogosort não é um algoritmo de ordenação estável.
Exemplo
Para se ordenar um baralho usando-se este algorítmo, seria necessário jogar as cartas ao ar, juntá-las aleatoriamente, e então
verificar se as mesmas estão ordenadas.
[editar]Algorítmo
função bogosort(array)
enquanto não está_ordenado(array)
array := permutação_aleatória(array)
[editar]Implementações
[editar]C
void bogosort(int size, int *array)
{
int i, j;
for (i = 1; i <= size; i++)
if (i == size)
return;
else if (array[i-1] > array[i])
break;
for (i = 0; i < size; i++) {
j = rand() % size;
if (array[i] != array[j])
array[i] ^= array[j] ^= array[i] ^= array[j];
}
bogosort(size, array);
}
[editar]C++
#include <algorithm>
#include <vector>
template<class T>
void bogosort(std::vector<T>& array)
{
while (! is_sorted(array))
std::random_shuffle(array.begin(), array.end());
}
template<class T>
bool is_sorted(const std::vector<T>& array)
{
for (typename std::vector<T>::size_type i = 1; i < array.size(); ++i)
if (array[i] < array[i-1]) return false;
return true;
}
[editar]Java
public static void bogoSort(int length, int range) {
int []array = randomIntArray(length,range);
while (! isSorted(array))
array = randomArray(array);
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
}
private static boolean isSorted(int [] array)
{
for (int i = 0; i < (array.length - 1); ++i) {
if (array[i] > array[i+1])
return false;
}
return true;
}
private static int [] randomArray(int [] array) {
int size = array.length;
int[] indices = new int[size];
for (int i=0; i<size; i++) {
indices[i] = i;
}
Random random = new Random();
for (int i = 0; i < size; i++) {
boolean unique = false;
int nRandom = 0;
while (!unique) {
unique = true;
nRandom = random.nextInt(size);
for (int j = 0; j < i; j++) {
if (indices[j] == nRandom) {
unique = false;
break;
}
}
}
indices[i] = nRandom;
}
int [] result = new int[size];
for (int k = 0; k < size; k++) {
result[indices[k]] = array[k];
}
return result;
}
private static int[] randomIntArray(int length, int n)
{
int[] a = new int[length];
Random generator = new Random();
for (int i = 0; i < a.length; i++)
{
a[i] = generator.nextInt(n);
}
return a;
}
Fluxograma
Introdução
O bubble sort, ou ordenação por flutuação (literalmente "por bolha"), é um algoritmo de ordenação dos mais simples. A ideia é
percorrer o vector diversas vezes, a cada passagem fazendo flutuar para o topo o maior elemento da sequência. Essa movimentação
lembra a forma como as bolhas em um tanque de água procuram seu próprio nível, e disso vem o nome do algoritmo.
No melhor caso, o algoritmo executa operações relevantes, onde n representa o número de elementos do vector. No pior caso, são
feitas operações. A complexidade desse algoritmo é de Ordem quadrática. Por isso, ele não é recomendado para programas que
precisem de velocidade e operem com quantidade elevada de dados.
[editar]Algoritmo
[editar]Pseudo-código
O algoritmo abaixo, decrito em pseudo-código, promete ordenar um vetor V[1..n] em ordem crescente.
Algoritmo Bubble(V, n)
1. k = n-1
2. para i = 1 até n faça
3. j = 1
4. enquanto j <= k faça
5. se V[j] > V[j+1] então
6. aux = V[j]
7. V[j] = V[j+1]
8. V[j+1] = aux
9. j = j+1
10. k = k-1
[editar]Demonstração de corretude
A demonstração do algoritmo se apóia nos seguintes invariantes, provados por indução matemática:
(i0): na linha 2, V[n-i+2 .. n] é crescente.
Prova: no momento da entrada do laço externo, quando i=1, o invariante vale, já que V[n+1 .. n] é vazio e, portanto, crescente.
Suponha agora que o invariante vale se trocarmos i por i-1. Queremos mostrar que ele também vale para i. Por hipótese de indução,
V[n-i+3 .. n] é crescente. Pelo invariante (i1), ao terminar o laço das linhas 4-9, teremos que V[1 .. n-i] <= V[n-i+1]. V[n-i+2] <= V[n-i+3
.. n]. Assim, V[n-i+2 .. n] é crescente.
Observe que a validade de (i0) em conjunto com a condição de parada do algoritmo (i = n+1) implicam na corretude do mesmo: V[n-
(n+1)+2 .. n] = V[1 .. n] é crescente.
(i1): na linha 4, vale que V[ j ] >= V[1 .. j-1]
Prova: o invariante vale na entrada do laço das linhas 4-9, quando j=1, pois V[1] >= V[1..0] (vazio). Suponha agora que o invariante
vale se trocarmos j por j-1. Então, V[ j-1 ] >= V[1 .. j-2] na linha 4. Ora, mas podemos ver que, ao final do laço interno, V[ j ] >= V[ j-1 ].
De fato, na linha 5, se V[ j-1 ] > V[ (j-1)+1 ] = V[ j ], trocaremos V[ j-1 ] e V[ j ] de posição, o que garante que V[ j ] >= V[ j-1 ] sob
qualquer circunstância.
Observe que, ao final do laço interno, V[n-i+1] >= V[1 .. n-i]: aplique (i1) com j = k+1, notando que k = n-i.
[editar]Análise do consumo de tempo
TODO. Alguém saberia formatar melhor esta tabela?
-------------+-------------------------------------
linha | número de execuções da linha
-------------+-------------------------------------
1 1
2 n+1
3 n
4 n
5 sum_{i=1}^{n} n-i+1 = (n^2 + n)/2 + 1
6 <= sum_{i=1}^{n} n-i = (n^2 + n)/2
7 <= sum_{i=1}^{n} n-i = (n^2 + n)/2
8 <= sum_{i=1}^{n} n-i = (n^2 + n)/2
9 sum_{i=1}^{n} n-i = (n^2 + n)/2
10 n
-------------+-------------------------------------
total <= (5/2)n^2 + (13/2)n + 3
-------------+-------------------------------------
O consumo de tempo de Bubble é \theta(n^2).
TODO: provar.
[editar]Versão alternativa
Abaixo há um algoritmo Bubble Sort onde a implementação é a mais simples possível, ou seja, é a versão original do Bubble
Sortsem o aprimoramento da variável "houve troca".
BUBBLESORT (V[], n)
houveTroca <- verdade # uma variável de controle
enquanto houveTroca for verdade faça:
houveTroca <- falso
para i de 1 até n-1 faça:
se V[i] vem depois de V[i + 1]
então troque V[i] e V[i + 1] de lugar e
houveTroca <- verdade
Para j de 1 até (i - 1) Passo 1
Se a[j - 1] > a[j] Então
aux <- a[j]
a[j] <- a[j - 1]
a[j - 1] <- aux
FimSe
Observação: Neste algoritmo tanto o melhor caso, como o pior caso tem ordem "n²", porque em ambos os casos os ciclos são
sempre realizados até ao fim, mesmo quando os elementos já estão ordenados.
[editar]Implementação
[editar]C
1. include<stdio.h>
2. include<stdlib.h>
3. include<conio.h>
4. include<stdbool.h>
int main() {
int vetor[5], i, aux;
bool parar = false;
for(i=0;i<5;++i)
{
printf("Digite o valor: ");
scanf("%d",&vetor[i]);
}
while(parar == false)
{
parar = true;
for(i=0;i<4;++i)
{
if(vetor[i]>vetor[i+1])
{
parar = false;
aux = vetor[i];
vetor[i] = vetor[i+1];
vetor[i+1] = aux;
}
}
}
for(i=0;i<5;++i)
{
printf("%d",vetor[i]);
}
getch();
return 0;
}
[editar]Java
public static void bubbleSort (int [] vetor){
boolean houveTroca = true;
while (houveTroca) {
houveTroca = false;
for (int i = 0; i < (vetor.length)-1; i++){
if (vetor[i] > vetor[i+1]){
int variavelAuxiliar = vetor[i+1];
vetor[i+1] = vetor[i];
vetor[i] = variavelAuxiliar;
houveTroca = true;
}
}
}
}
[editar]C
Usando "do while".
void swapbubble( int v[], int i)
{
int aux=0;
aux=v[i];
v[i] = v[i+1];
v[i+1] = aux;
}
void bubble(int v[], int qtd)
{
int i;
int trocou;
qtd--;
do
{
trocou = 0;
for(i = 0; i < qtd; i++)
{
if(v[i] > v[i + 1])
{
swapbubble(v, i);
trocou = 1;
}
}
}while(trocou);
}
Método de ordenação Bolha com ordenação de strings.
void bubble(int v[], int qtd)
//UTILIZA BIBLIOTECA string.h
{
int i;
int trocou;
char aux;
do
{
qtd--;
trocou = 0;
for(i = 0; i < qtd; i++)
if(strcasecmp(v[i],v[i + 1])>0)
{
/*o ideal seria fazer uma função troca aqui*/
strcpy(aux, v[i]);
strcpy(v[i], v[i + 1]);
strcpy(v[i + 1], aux);
trocou = 1;
}
}while(trocou==1);
}
[editar]C++
#include <algorithm>
using namespace std;
void bubblesort(int a[], int n)
{
for(int j=0; j<n; j++){
for(int i=0; i<n-1; i++){
if(a[i+1] < a[i])
swap(a[i+1], a[i]);
}
}
}
[editar]Fluxograma
Bucket sort
Conceito de base do bucket sort.
Bucket sort, ou bin sort, é um algoritmo de ordenação que funciona dividindo um vetor em um número finito de recipientes.
Cada recipiente é então ordenado individualmente, seja usando um algoritmo de ordenação diferente, ou usando o algoritmo
bucket sort recursivamente. O bucket sort tem complexidade linear (Θ(n)) quando o vetor a ser ordenado contém valores que
são uniformemente distribuídos.
[editar]Funcionamento
Bucket sort funciona do seguinte modo:
1. Inicialize um vetor de "baldes", inicialmente vazios.
2. Vá para o vetor original, incluindo cada elemento em um balde.
3. Ordene todos os baldes não vazios.
4. Coloque os elementos dos baldes que não estão vazios no vetor original.
[editar]Exemplo em C
//Compilado em Linux.Sujeito a mudanças caso outro sistema seja utilizado.
#include <stdio.h>
#define tam_bucket 100
#define num_bucket 10
#define max 10
typedef struct {
int topo;
int balde[tam_bucket];
}bucket;
void bucket_sort(int v[],int tam); //cabeçalho das funções
void bubble(int v[],int tam);
//int main(){}
void bucket_sort(int v[],int tam){
bucket b[num_bucket];
int i,j,k;
/* 1 */ for(i=0;i<num_bucket;i++) //inicializa todos os "topo"
b[i].topo=0;
/* 2 */ for(i=0;i<tam;i++){ //verifica em que balde o elemento deve
ficar
j=(num_bucket)-1;
while(1){
if(j<0)
break;
if(v[i]>=j*10){
b[j].balde[b[j].topo]=v[i];
(b[j].topo)++;
break;
}
j--;
}
}
/* 3 */ for(i=0;i<num_bucket;i++) //ordena os baldes
if(b[i].topo)
bubble(b[i].balde,b[i].topo);
i=0;
/* 4 */ for(j=0;j<num_bucket;j++){ //põe os elementos dos baldes de volta
no vetor
for(k=0;k<b[j].topo;k++){
v[i]=b[j].balde[k];
i++;
}
}
}
void bubble(int v[],int tam){
int i,j,temp,flag;
if(tam)
for(j=0;j<tam-1;j++){
flag=0;
for(i=0;i<tam-1;i++){
if(v[i+1]<v[i]){
temp=v[i];
v[i]=v[i+1];
v[i+1]=temp;
flag=1;
}
}
if(!flag)
break;
}
}
[editar]Explicação do código
Bucket sort - fase 1.
Bucket sort - fase 2.
Antes de mais nada, é preciso saber o que cada "#define" significa.
1. tam_bucket é o tamanho de cada balde da estrutura bucket.
2. num_bucket é o número de baldes, isto é, o tamanho do vetor de bucket
3. max é o tamanho do vetor a ser ordenado.
A estrutura bucket consiste de um vetor de inteiros (int balde[tam_bucket]) e de uma variável que serve para dizer
quantos números estão armazenados no balde.
O parâmetro "tam", tanto na função "bucket_sort" como na "bubble", é o tamanho do vetor a ser ordenado.
A explicação dos "for" agora:
1. Inicializa o "topo" de cada bucket que o vetor de bucket "b[num_bucket]" contém.
Isso é importante, pois, a princípio, os baldes estão vazios.
2. Verifica em que balde o elemento deve ficar.
Cada elemento do vetor a ser ordenado é colocado em seu lugar no vetor de bucket.Por exemplo, suponha o número
26.A variável "j" receberia (num_bucket-1), isto é,9 no exemplo acima.O "while" verifica se 26 é maior do que j*10
(90).Como isto não é válido, "j" é decrementado em 1, e o processo se repete até que j=2, já que 26>=20.Então, o
balde de posição 2 recebe 26.Caso não haja nenhum outro elemento no balde 2, isso significa que "topo" daquele
balde vale 0, portanto balde[0] recebe o 26.Caso haja, por exemplo, 3 elementos no balde, isso quer dizer que topo=2,
portanto balde[2] recebe 26.Depois disso, "topo" daquele balde é incrementado em 1 e o processo se repete para os
outros elementos do vetor que queremos ordenar.
3. Ordena cada balde.
Ordena os baldes cujos "topo" são diferentes de 0, ou seja, não estão vazios.No algoritmo acima, o bubble sort foi
utilizado, mas métodos mais eficientes podem ser utilizados.
4. Por fim, os baldes são percorridos e seus elementos são devolvidos para o vetor original.
Atente para o fato de que nosso exemplo não ordena elementos negativos.Um tratamento especial para eles
seria necessário.Além do mais, o método de separar cada elemento pode ser diferente.O utilizado foi
verificar se o elemento está entre 0 e 10, 11 e 20, e assim por diante.
_______________________________________________________________________________________
____
Aqui uma matriz linear de inteiros com n elementos,é usado para ordenar os elementos do vetor.
[editar]Exemplo em C++ com matriz
/*************************INICIO*****************************************/
//==================================================================
//
// Projeto: Bucket Sort
// Data de Criacao: 27/02/09
// Autor: Albany Timbo Mesquita
// Colaboracao:Pedro Henrique Fernandes Marques Leitao
//
//==================================================================
#include <iostream>
#define TAM 20 /*Tamanho do vetor*/
#define NUM 10000 /*base para gerador de numeros aleatorios*/
using std::cout;
using std::cin;
using std::endl;
void gerarVet(int*);
void bucketSort(int*);
void imprimaVet(int*);
int main(){
int vet[TAM],tinicio,tfim,tempo;
tinicio=time(NULL);
gerarVet(vet);
imprimaVet(vet);
bucketSort(vet);
imprimaVet(vet);
tfim=time(NULL);
tempo=difftime(tfim,tinicio);
cout<<"Tempo de execucao "<<tempo/60<<" Minutos e "<<tempo%60<<" segundos.\n";
system("pause");
return 0;
}
/***********************************************************************/
/*******************************FUNCOES*********************************/
/***********************************************************************/
void bucketSort(int *vet){
int mat[10][TAM],aux[TAM],cont=1,num,w=0,i,j;
do{
for(i=0;i<TAM;i++){aux[i] = 0;}//Zerando o vetor auxiliar.
for(i=0;i<10;i++) {//Setando a Matriz com valores -1
for(j=0;j<TAM;j++){
mat[i][j] = -1;
}
}
for (i=0;i<TAM;i++) {
num = (vet[i]/cont)%10;//verificando o valor da esquerda para direita
mat[num][aux[num]] = vet[i];//colocando o valor na sua posicao na
matriz
aux[num]++; //contador de colunas da matriz
}
for(i=0;i<10;i++) {//volta com os valores da Matriz para o vetor
for(j=0;j<TAM;j++){
if(mat[i][j] != -1){
vet[w] = mat[i][j];
w++;
}
}
}
w = 0;
cont=cont*10;
}while(aux[0] < TAM);//condicao :Enquanto vetor auxiliar < tamanho vetor
} //
/******************GERADOR DE NUMEROS ALEATORIOS**************************/
void gerarVet(int *vet){
srand(time(NULL));
for (int i=0;i<TAM;i++){
vet[i]=rand()%NUM;
}
}
/*******************FUNCAO PARA IMPRIMIR VETOR************************/
void imprimaVet(int *vet){
for (int i=0;i<TAM;i++){
cout<<vet[i]<<"|";
}
cout<<"**************************************************************\n";
}
/********************************FIM*************************************/
_______________________________________________________________________________________
______________________
[editar]Exemplo em Java com LinkedList
/*
* Autor: wilhs
* Data: 28/04/2011
* Crédito: Implementação com base neste Artigo.
*/
public static void BucketSort(int[] vetor, int maiorValor)
{
int numBaldes = maiorValor/5;
LinkedList[] B = new LinkedList[numBaldes];
for (int i = 0; i < numBaldes; i++){
B[i] = new LinkedList<Integer>();
}
//Coloca os valores no balde respectivo:
for (int i = 0; i < vetor.length; i++) {
int j = numBaldes-1;
while (true){
if(j<0){
break;
}
if(vetor[i] >= (j*5)){
B[j].add(vetor[i]);
break;
}
j--;
}
}
//Ordena e atualiza o vetor:
int indice = 0;
for (int i = 0; i < numBaldes; i++){
int[] aux = new int[B[i].size()];
//Coloca cada balde num vetor:
for (int j = 0; j < aux.length; j++){
aux[j] = (Integer)B[i].get(j);
}
insertionSort(aux); //algoritmo escolhido para ordenação.
// Devolve os valores ao vetor de entrada:
for (int j = 0; j < aux.length; j++, indice++){
vetor[indice] = aux[j];
}
}
}
Cocktail sort Origem: Wikipédia, a enciclopédia livre.
Cocktail sort, também conhecido como Shaker Sort, bubble sort bidirecional (que também pode se referir a uma variante
do selection sort), ripple sort, shuttle sort ouhappy hour sort, é uma variação do bubble sort que é tanto um algoritmo de
ordenaçãoestável quanto uma ordenação por comparação. O algoritmo difere do bubble sort pelo fato de ordenar em ambas as
direções em cada passagem através da lista. Este algoritmo de ordenação é apenas ligeiramente mais difícil de implementar
do que o bubble sort, e resolve o problema com os chamados coelhos e tartarugas no bubble sort.
[editar]Complexidade
O(n²)
[editar]Implementações
[editar]Código em C
void cocktail_sort(int list[10]) {
int length,bottom,top, swapped,i,aux;
length=10;
bottom = 0;
top = length - 1;
swapped = 0;
while(swapped == 0 && bottom < top)//Se não houver troca de posições ou o ponteiro que
{ //sobe ultrapassar o que desce, o vetor esta ordenado
swapped = 1;
//Este for é a “ida” para a direita
for(i = bottom; i < top; i = i + 1)
{
if(list[i] > list[i + 1]) //indo pra direita:testa se o próximo é maior
{ //indo pra direita:se o proximo é maior que o atual,
//troca as posições
aux=list[i];
list[i]=list[i+1];
list[i+1]=aux;
swapped = 0;
}
}//fecha for
// diminui o `top` porque o elemento com o maior valor
// já está na direita (atual posição top)
top = top - 1;
//Este for é a “ida” para a esquerda
for(i = top; i > bottom; i = i - 1)
{ if(list[i] < list[i - 1])
{
aux=list[i];
list[i]=list[i-1];
list[i-1]=aux;
swapped = 0;
}
}
//aumenta o `bottom` porque o menor valor já está
//na posição inicial (bottom)
bottom = bottom + 1;
}//fecha while
}// fim da funçao
[editar]Código em C# e Java (sintaxe idêntica)
private static void cocktail(int[] vetor)
{
int tamanho, inicio, fim, swap, aux;
tamanho = 20; // para um vetor de 20 elementos
inicio = 0;
fim = tamanho - 1;
swap = 0;
while (swap == 0 && inicio < fim)
{
swap = 1;
for (int i = inicio; i < fim; i = i + 1)
{
if (vetor[i] > vetor[i + 1])
{
aux = vetor[i];
vetor[i] = vetor[i + 1];
vetor[i + 1] = aux;
swap = 0;
}
}
fim = fim - 1;
for (int i = fim; i > inicio; i = i - 1)
{
if (vetor[i] < vetor[i - 1])
{
aux = vetor[i];
vetor[i] = vetor[i - 1];
vetor[i - 1] = aux;
swap = 0;
}
}
inicio = inicio + 1;
}
}
Comb sort Origem: Wikipédia, a enciclopédia livre.
O algoritmo Comb sort (ou Combo sort ou ainda algoritmo do pente[1]
) é umalgoritmo de ordenação relativamente simples, e
faz parte da família de algoritmos deordenação por troca. Foi desenvolvido em 1980 por Wlodzimierz Dobosiewicz. Mais tarde,
foi redescoberto e popularizado por Stephen Lacey e Richard Box em um artigo publicado na revista Byte em Abril de 1991.
O Comb sort melhora o Bubble sort, e rivaliza com algoritmos como o Quicksort. A idéia básica é eliminar as tartarugas ou
pequenos valores próximos do final da lista, já que em um bubble sort estes retardam a classificação tremendamente.
(Coelhos, grandes valores em torno do início da lista, não representam um problema no bubble sort).
O Algoritmo repetidamente reordena diferentes pares de itens, separados por um salto, que é calculado a cada passagem.
Método semelhante ao Bubble Sort, porém mais eficiente.
Na Bubble sort, quando quaisquer dois elementos são comparados, eles sempre têm um gap (distância um do outro) de 1. A
idéia básica do Comb sort é que a diferença pode ser muito mais do que um. (O Shell sort também é baseado nesta idéia, mas
é uma modificação do insertion sort em vez do bubble sort).
O gap (intervalo) começa como o comprimento da lista a ser ordenada dividida pelo fator de encolhimento (em geral 1,3; veja
abaixo), e a lista é ordenada com este valor (arredondado para um inteiro se for necessário) para o gap. Então, a diferença é
dividida pelo fator de encolhimento novamente, a lista é ordenada com este novo gap, e o processo se repete até que a
diferença seja de 1. Neste ponto, o Comb sort continua usando um espaço de 1 até que a lista esteja totalmente ordenada. A
fase final da classificação é, portanto, equivalente a um bubble sort, mas desta vez a maioria dos elementos "tartarugas" já
foram tratados, assim o bubble sort será eficiente.
[editar]Fator de encolhimento
O fator de encolhimento tem um grande efeito sobre a eficiência do Comb sort. No artigo original, os autores sugeriram 1,3
depois de tentar algumas listas aleatórias e encontrando-se, geralmente as mais eficazes. Um valor muito pequeno retarda o
algoritmo porque mais comparações devem ser feitas, ao passo que um valor muito grande não pode tratar um número
suficiente de "tartarugas" para ser prático.
O texto descreve uma melhoria no comb sort usando o valor base como
fator de encolhimento. Ele também contém uma implementação em pseudocódigo com uma tabela de gaps pré-definidos.
[editar]Variações
[editar]Combsort11
Com um fator de encolhimento de cerca de 1,3, só existem três caminhos possíveis para a lista de gaps terminar: (9, 6, 4, 3, 2,
1), (10, 7, 5, 3, 2, 1), ou (11, 8, 6, 4, 3, 2, 1). Experimentos mostram que melhorias significativas de velocidade podem ser feitas
se o gap for definido como 11, sempre que, caso contrário, tornar-se 9 ou 10. Esta variação é chamada Combsort11.
Se uma das sequências que começam com 9 ou 10, forem utilizadas, o passo final, com um intervalo de 1 tem menor
probabilidade de ordenar os dados sendo necessário então outro passo com gap de 1. Os dados são ordenados quando não
ocorrem mais trocas durante uma passagem com gap= 1.
Também é possível usar uma tabela pré-definida, para escolher quais gaps a utilizar em cada passo.
[editar]Combsort com diferentes finais
Como muitos outros algoritmos eficientes de ordenação (como o quick sort ou merge sort), o comb sort é mais eficaz em suas
passagens anteriores do que durante o passo final, quando ele se assemelha a um bubble sort. O Comb sort pode ser mais
eficaz se o método de classificação é mudado uma vez que os gaps cheguem a um número pequeno o suficiente. Por
exemplo, uma vez que a diferença chegue a um tamanho de cerca de 10 ou menor, parando o comb sort e fazendo um
simples gnome sort ou cocktail sort, ou, melhor ainda, um insertion sort, se aumentará a eficiência global da ordenação.
Outra vantagem deste método é que não há necessidade de manter o controle das operações de troca durante os passos da
classificação para saber se a ordenação deve parar ou não.
[editar]Implementações
[editar]C++
Esta é uma implementação no estilo STL. Ele irá classificar qualquer intervalo entre a primeira e a última. Isso funciona com
quaisqueriteradores posteriores, mas é mais eficaz com iteradores de acesso aleatório ou ponteiros.
template<class ForwardIterator>
void combsort ( ForwardIterator first, ForwardIterator last )
{
static const double shrink_factor = 1.247330950103979;
typedef typename std::iterator_traits<ForwardIterator>::difference_type difference_type;
difference_type gap = std::distance(first, last);
bool swaps = true;
while ( (gap > 1) || (swaps == true) ){
if (gap > 1)
gap = static_cast<difference_type>(gap/shrink_factor);
swaps = false;
ForwardIterator itLeft(first);
ForwardIterator itRight(first); std::advance(itRight, gap);
for ( ; itRight!=last; ++itLeft, ++itRight ){
if ( (*itRight) < (*itLeft) ){
std::iter_swap(itLeft, itRight);
swaps = true;
}
}
}
}
[editar]Java
public static <E extends Comparable<? super E>> void sort(E[] input) {
int gap = input.length;
boolean swapped = true;
while (gap > 1 || swapped) {
if (gap > 1)
gap = (int) (gap / 1.247330950103979);
int i = 0;
swapped = false;
while (i + gap < input.length) {
if (input[i].compareTo(input[i + gap]) > 0) {
E t = input[i];
input[i] = input[i + gap];
input[i + gap] = t;
swapped = true;
}
i++;
}
}
}
[editar]C
void combsort(int *arr, int size) {
float shrink_factor = 1.247330950103979;
int gap = size, swapped = 1, swap, i;
while ((gap > 1) || swapped) {
if (gap > 1)
gap = gap / shrink_factor;
swapped = 0;
i = 0;
while ((gap + i) < size) {
if (arr[i] - arr[i + gap] > 0) {
swap = arr[i];
arr[i] = arr[i + gap];
arr[i + gap] = swap;
swapped = 1;
}
++i;
}
}
}
Counting sort
Origem: Wikipédia, a enciclopédia livre.
Counting sort é um algoritmo de ordenação estável cuja complexidade é O(n). As chaves podem tomar valores entre 0 e M-1.
Se existirem k0 chaves com valor 0, então ocupam as primeiras k0 posições do vetor final: de 0 a k0-1.
[editar]Implementações
1. Cria cnt[M+1] e b[max N]
2. Inicializa todas as posições de cnt a 0.
3. Percorre o vector a e, para cada posição i de a faz cnt[a[i]-1]++ o que faz com que, no final, cada posição i de cnt
contem o nº de vezes que a chave i-1 aparece em a.
4. Acumula em cada elemento de cnt o elemento somado ao elemento anterior: cnt[i] indica a posição ordenada do
primeiro elemento de chave i.
5. Guarda em b os valores de a ordenados de acordo com b[cnt[a[i]++]=a[i]
6. Copia b para a.
7. Counting-Sort trabalha como uma contadora de ocorrências dentro de um programa, especificamente dentro de um
vetor. Quando determinado vetor tem números repetidos, números únicos e números que não existem um outro vetor
indica a quantidade de ocorrências.
Esta implementação tem a desvantagem de precisar de vectores auxiliares. O Counting Sort ordena exclusivamente números
inteiros pelo fato de seus valores servirem como índices no vetor de contagem.
[editar]Código em C++
template<class T>
std::vector<T> counting_sort( const std::vector<T> &op )
{
if( op.empty() )
return std::vector<T>();
T min = *std::min_element( op.begin(), op.end() );
T max = *std::max_element( op.begin(), op.end() );
std::vector<int> contagem( max - min + 1, 0 );
for( std::vector<T>::const_iterator it = op.begin(); it != op.end(); ++it );
++contagem[ *it - min ];
std::partial_sum( contagem.begin(), contagem.end(), contagem.begin() );
std::vector<T> ordenado( op.size() );
for( std::vector<T>::const_reverse_iterator it2 = op.rbegin(); it2 != op.rend(); ++it2 )
ordenado[ --contagem[ *it2 - min ] ] = *it2;
return ordenado;
}
[editar]Código em C
# include <stdio.h>
# include <string.h>
# include <stdlib.h>
# include <ctype.h>
# define MAX 100001
struct data
{
int number;
char key[100];
}DataBase[MAX], VectorSort[MAX];
int CounterNum[MAX];
int size = 0;
int main (void)
{
int i = 0;
while(scanf("%d%s",&DataBase[size].number,DataBase[size].key) >= 1)
size++;
int aux[2] = {0,0};
for(i = 0; i <= size;i++)
aux[DataBase[i].number]++;
aux[1] += aux[0];
for(i = size - 1;i >= 0;i--)
VectorSort[--aux[DataBase[i].number]] = DataBase[i];
for(i = 0; i < size;i++)
printf("Number: %d --- Key: %s\n",VectorSort[i].number,VectorSort[i].key);
return 0;
}
Gnome sort
Origem: Wikipédia, a enciclopédia livre.
Algoritmo similiar ao Insertion sort com a diferença que o Gnome sort leva um elemento para sua posição correta, com uma
seqüencia grande de trocas assim como o Bubble sort
O algoritmo percorre o vetor comparando seus elementos dois a dois, assim que ele encontra um elemento que está na
posição incorreta, ou seja, um número maior antes de um menor, ele troca a posição dos elementos, e volta com este elemento
até que encontre o seu respectivo lugar.
Características
Complexidade de tempo: Θ(n²)
[editar]Implementações
[editar]Código em C
# include <stdio.h>
# include <stdlib.h>
# include <ctype.h>
# include <string.h>
# include <stdbool.h>
# define MAX 100001
int VectorSort[MAX];
int size = 0;
void swap(int * ,int *);
void GnomeSort();
int main (void)
{
while(scanf("%d",&VectorSort[size]) >= 1)
size++;
GnomeSort();
return 0;
}
void swap(int *A, int *B)
{
int C = *A;
* A = *B;
* B = C;
}
void GnomeSort()
{
int next = 0, previous = 0;
int i = 0;
for(i = 0; i < size ; i++)
{
if(VectorSort[i] > VectorSort[i + 1])
{
previous = i;
next = i + 1;
while(VectorSort[previous] > VectorSort[next])
{
swap(&VectorSort[previous],&VectorSort[next]);
previous--;
next--;
}
}
}
for(i = 0; i < size; i++)
printf("%d\n",VectorSort[i]);
}
[editar]Código em C++ versão 1
template<class T>
void gnome_sort( std::vector<T> &lista )
{
std::vector<T>::size_type i = 1;
while( i < lista.size() )
{
if( i == 0 || lista.at( i-1 ) <= lista.at( i ) )
{
i++;
}
else
{
std::swap( lista[ i - 1 ], lista [ i ] );
--i;
}
}
}
[editar]Código em C++ versão 2
template<class T>
void gnome_sort( std::vector<T> &lista )
{
std::vector<T>::iterator elem = lista.begin()+1;
while( elem != lista.end() )
{
if( elem == lista.begin() || *(elem-1) <= *elem )
{
++elem;
}
else
{
std::iter_swap( elem-1, elem );
--elem;
}
}
}
[editar]Código em Java
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
/**
* Implementa e executa o algoritmo Gnome Sort
*
* @author Dielson Sales, Marcos Paulo J. Melo Silva
* /
public class GnomeSort<E extends Comparable<? super E>> {
/**
* Ordena uma coleção de dados comparáveis usando o Gnome Sort.
* @param vector uma lista de dados comparáveis
* @return uma lista com os dados ordenados
* /
public Collection<E> sort(Collection<E> vector) {
int i = 1;
List<E> result = new ArrayList<E>(vector);
while (i < result.size()) {
if (i == 0 || result.get(i - 1).compareTo(result.get(i))<= 0) {
i++;
} else {
E temp = result.get(i - 1);
result.set(i - 1, result.get(i));
result.set(i, temp);
i--;
}
}
return result;
}
/**
* Execução do algoritmo de ordenação Gnome Sort.
* /
public static void main(String[] args) {
GnomeSort<Integer> gnomeSort = new GnomeSort<Integer>();
final int size = 50;
final Random random = new Random();
List<Integer> list = new ArrayList<Integer>(size);
for (int i = 0; i < size; i++) {
list.add(random.nextInt());
}
// Lista com os dados já ordenados.
Set<Integer> sortedList = new HashSet<Integer>(gnomeSort.sort(list));
}
}
/**
* Exemplo de código em Java
* Autores: Marcos Paulo J. de Melo Silva e Dielson Sales de Carvalho;
* Instituição: Universidade Federal de Alagoas (UFAL);
* /
[editar]Código em Java
/*
* Autor: Felipe da Silva Travassos
* Graduando em Ciência da Computação - UFCG
*/
public static Integer[] gnomeSort(Integer[] array){
int pivout = 0;
int aux;
while(pivout<(array.length-1)){
if(array[pivout]>array[pivout+1]){
aux = array[pivout];
array[pivout] = array[pivout+1];
array[pivout+1] = aux;
if(pivout>0){
pivout-=2;
}
}
pivout++;
}
return array;
}
Heapsort Origem: Wikipédia, a enciclopédia livre.
O algoritmo heapsort é um algoritmo de ordenação generalista, e faz parte da família de algoritmos de ordenação por seleção.
Foi desenvolvido em 1964 porRobert W. Floyd e J.W.J. Williams.
[editar]Definição
Tem um desempenho em tempo de execução muito bom em conjuntos ordenados aleatoriamente, tem um uso de memória
bem comportado e o seu desempenho em pior cenário é praticamente igual ao desempenho em cenário médio. Alguns
algoritmos de ordenação rápidos têm desempenhos espectacularmente ruins no pior cenário, quer em tempo de execução,
quer no uso da memória. O Heapsort trabalha no lugar e o tempo de execução em pior cenário para ordenar n elementos é
de O (n lg n). Lê-se logaritmo (ou log) de "n" na base 2. Para valores de n, razoavelmente grande, o termo lg n é quase
constante, de modo que o tempo de ordenação é quase linear com o número de itens a ordenar.
[editar]Características
Comparações no pior caso: 2n log2n + O(n) é o mesmo que 2n lgn + O(n)
Trocas no pior caso: n log2n + O(n) é o mesmo que n lgn + O(n)
Melhor e pior caso: O(n log2n) é o mesmo que O(n lgn)
[editar]Funcionamento
O heapsort utiliza uma estrutura de dados chamada heap, para ordenar os elementos a medida que os insere na estrutura.
Assim, ao final das inserções, os elementos podem ser sucessivamente removidos da raiz da heap, na ordem desejada,
lembrando-se sempre de manter a propriedade de max-heap.
A heap pode ser representada como uma árvore (uma árvore binária com propriedades especiais[2]
) ou como um vetor. Para
uma ordenação crescente, deve ser construído uma heap mínima (o menor elemento fica na raiz). Para uma ordenação
decrescente, deve ser construído uma heap máxima (o maior elemento fica na raiz).
[editar]Implementações
[editar]Código em C
void heapsort(tipo a[], int n)
{
int i = n/2, pai, filho;
tipo t;
for (;;)
{
if (i > 0)
{
i--;
t = a[i];
}
else
{
n--;
if (n == 0)
return;
t = a[n];
a[n] = a[0];
}
pai = i;
filho = i*2 + 1;
while (filho < n)
{
if ((filho + 1 < n) && (a[filho + 1] > a[filho]))
filho++;
if (a[filho] > t)
{
a[pai] = a[filho];
pai = filho;
filho = pai*2 + 1;
}
else
break;
}
a[pai] = t;
}
}
[editar]Código em C++
template<class T>
void heap_sort( std::vector<T> &lista )
{
int tam = static_cast<int>( lista.size() ), i;
for( i = tam/2 - 1; i >= 0; --i )
{
maxHeapify(lista, i , tam );
}
std::vector<T>::reverse_iterator elem;
for( elem = lista.rbegin(); elem != lista.rend(); elem++ )
{
std::iter_swap( elem, lista.begin() );
maxHeapify( lista, 0, --tam );
}
}
template<class T>
void maxHeapify( std::vector<T> &lista, const int pos, const int n )
{
int max = 2 * pos + 1;
if( max < n )
{
if( (max+1) < n && lista.at(max) < lista.at(max+1) )
{
++max;
}
if( lista.at(max) > lista.at(pos) )
{
std::swap( lista[max], lista[pos] );
maxHeapify( lista, max, n );
}
}
}
[editar]Código em Java
public static void heapSort(int[] v)
{
buildMaxHeap(v);
int n = v.length;
for (int i = v.length - 1; i > 0; i--)
{
swap(v, i , 0);
maxHeapify(v, 0, --n);
}
}
private static void buildMaxHeap(int[] v)
{
for (int i = v.length/2 - 1; i >= 0; i--)
maxHeapify(v, i , v. length );
}
private static void maxHeapify(int[] v, int pos, int n)
{
int maxi;
int l = 2 * pos + 1;
int right = 2 * pos + 2;
if ( (l < n) && (v[l] > v[pos]) )
{
maxi = l;
}
else
{
maxi = pos;
}
if (right < n && v[right] > v[maxi])
{
maxi = right;
}
if (maxi != pos)
{
swap(v, pos, maxi);
maxHeapify(v, maxi, n);
}
}
public static void swap ( int[ ] v, int j, int aposJ )
{
int aux = v [ j ];
v [ j ] = v [ aposJ ];
v [ aposJ ] = aux;
}
[editar]Código em Java (5.0)
public static <T extends Comparable<? super T>> void heapSort(T[] v) {
buildMaxHeap(v);
int n = v.length;
for (int i = v.length - 1; i > 0; i--) {
swap(v, i, 0);
maxHeapify(v, 0, --n);
}
}
private static <T extends Comparable<? super T>> void buildMaxHeap(T v[]) {
for (int i = v.length / 2 - 1; i >= 0; i--)
maxHeapify(v, i, v.length);
}
private static <T extends Comparable<? super T>> void maxHeapify(T[] v, int pos,
int n) {
int max = 2 * pos + 1, right = max + 1;
if (max < n) {
if (right < n && v[max].compareTo(v[right]) < 0)
max = right;
if (v[max].compareTo(v[pos]) > 0) {
swap(v, max, pos);
maxHeapify(v, max, n);
}
}
}
public static void swap(Object[] v, int j, int aposJ) {
Object aux = v[j];
v[j] = v[aposJ];
v[aposJ] = aux;
}
Insertion sort Origem: Wikipédia, a enciclopédia livre.
Insertion sort, ou ordenação por inserção, é um simples algoritmo de ordenação, eficiente quando aplicado a um pequeno
número de elementos. Em termos gerais, ele percorre um vetor de elementos da esquerda para a direita e à medida que
avança vai deixando os elementos mais à esquerda ordenados. O algoritmo de inserção funciona da mesma maneira com que
muitas pessoas ordenam cartas em um jogo de baralho como o pôquer.[1]
[editar]Características
Menor número de trocas e comparações entre os algoritmos de ordenação O(n) quando o vetor está ordenado.
Pior caso O(n²)
[editar]Implementações
[editar]Java
public static void insertionSort(int[] array)
{
for (int i = 1; i < array.length; i++)
{
int a = array[i];
for (int j = i - 1; j >= 0 && array[j] > a; j--)
{
array[j + 1] = array[j];
array[j] = a;
}
}
}
[editar]C
void insertionSort(int V[], int tam)
{
int i, j, aux;
for(i = 1; i < tam; i++){
j = i;
while((V[j] < V[j - 1])&&(j!=0)) {
aux = V[j];
V[j] = V[j - 1];
V[j - 1] = aux;
j--;
}
}
}
[editar]C++
void Inserction(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;
}
}
Merge sort Origem: Wikipédia, a enciclopédia livre.
O merge sort, ou ordenação por mistura, é um exemplo de algoritmo de ordenação do tipo dividir-para-conquistar.
Sua ideia básica consiste em Dividir(o problema em vários sub-problemas e resolver esses sub-problemas através da
recursividade) e Conquistar(após todos os sub-problemas terem sido resolvidos ocorre a conquista que é a união das
resoluções dos sub-problemas).Como o algoritmo do Merge Sort usa a recursividade em alguns problemas esta técnica não é
muito eficiente devido ao alto consumo de memória e tempo de execução.
Os três passos úteis dos algoritmos dividir-para-conquistar, ou divide and conquer, que se aplicam ao merge sort são:
1. Dividir: Dividir os dados em subsequências pequenas;
2. Conquistar: Classificar as duas metades recursivamente aplicando omerge sort;
3. Combinar: Juntar as duas metades em um único conjunto já classificado.
[editar]Características
Complexidade de tempo: Θ(n log2 n)
Complexidade de espaço: Θ(n)
É possível implementar o merge sort utilizando somente um vetor auxiliar ao longo de toda a execução, tornando assim a
complexidade de espaço adicional igual a Θ(n log n).
É possível também implementar o algoritmo com espaço adicional Θ(1)
Algoritmo Criado por Von Neumann em 1945.
[editar]Desvantagens
Implementação complexa
Ideia complexa
Utiliza funções recursivas
[editar]Implementações
[editar]C
void merge(int vec[], int vecSize) {
int mid;
int i, j, k;
int* tmp;
tmp = (int*) malloc(vecSize * sizeof(int));
if (tmp == NULL) {
exit(1);
}
mid = vecSize / 2;
i = 0;
j = mid;
k = 0;
while (i < mid && j < vecSize) {
if (vec[i] < vec[j]) {
tmp[k] = vec[i];
++i;
}
else {
tmp[k] = vec[j];
++j;
}
++k;
}
if (i == mid) {
while (j < vecSize) {
tmp[k] = vec[j];
++j;
++k;
}
}
else {
while (i < mid) {
tmp[k] = vec[i];
++i;
++k;
}
}
for (i = 0; i < vecSize; ++i) {
vec[i] = tmp[i];
}
free(tmp);
}
void mergeSort(int vec[], int vecSize) {
int mid;
if (vecSize > 1) {
mid = vecSize / 2;
mergeSort(vec, mid);
mergeSort(vec + mid, vecSize - mid);
merge(vec, vecSize);
}
}
[editar]Código em C++
#include <algorithm>
#include <iostream>
#include <vector>
std::vector<int> merge_sort(const std::vector<int> &data)
{
if (data.size() <= 1) {
return data;
}
int middle = data.size() / 2;
std::vector<int> left(data.begin(), data.begin()+middle);
std::vector<int> right(data.begin()+middle, data.end());
left = merge_sort(left);
right = merge_sort(right);
std::vector<int> result(data.size());
std::merge(left.begin(), left.end(),
right.begin(), right.end(),
result.begin());
return result;
}
Quicksort
Origem: Wikipédia, a enciclopédia livre.
O algoritmo Quicksort é um método de ordenação muito rápido e eficiente, inventado por C.A.R. Hoare em 1960[1]
, quando
visitou a Universidade de Moscovocomo estudante. Naquela época, Hoare trabalhou em um projeto de tradução de
máquina para o National Physical Laboratory. Ele criou o 'Quicksort ao tentar traduzir um dicionário de inglês para russo,
ordenando as palavras, tendo como objetivo reduzir o problema original em subproblemas que possam ser resolvidos mais facil
e rapidamente. Foi publicado em 1962 após uma série de refinamentos.[2]
O Quicksort é um algoritmo de ordenação por comparação não-estável.
O Quicksort adota a estratégia de divisão e conquista. A estratégia consiste em rearranjar as chaves de modo que as chaves
"menores" precedam as chaves "maiores". Em seguida o Quicksort ordena as duas sublistas de chaves menores e maiores
recursivamente até que a lista completa se encontre ordenada. [3]
Os passos são:
1. Escolha um elemento da lista, denominado pivô;
2. Rearranje a lista de forma que todos os elementos anteriores ao pivô sejam menores que ele, e todos os elementos
posteriores ao pivô sejam maiores que ele. Ao fim do processo o pivô estará em sua posição final e haverá duas
sublistas não ordenadas. Essa operação é denominada partição;
3. Recursivamente ordene a sublista dos elementos menores e a sublista dos elementos maiores;
A base da recursão são as listas de tamanho zero ou um, que estão sempre ordenadas. O processo é finito, pois a cada
iteração pelo menos um elemento é posto em sua posição final e não será mais manipulado na iteração seguinte.
[editar]Complexidade
Complexidade de tempo: θ(n lg2 n) no melhor caso e caso médio e θ(n2) no pior caso;
Complexidade de espaço: θ(lg2 n) no melhor caso e no caso médio e θ(lg2 n) no pior caso. R. Sedgewick desenvolveu uma
versão do Quicksort com partição recursão de cauda que tem complexidade θ(n2) no pior caso.
[editar]Implementações
[editar]C++
#include <algorithm>
#include <iterator>
#include <functional>
using namespace std;
template <typename T>
void sort(T begin, T end) {
if (begin != end) {
T middle = partition (begin, end, bind2nd(less<iterator_traits<T>::value_type>(),
*begin));
sort (begin, middle);
sort (max(begin + 1, middle), end);
}
}
[editar]C
void swap(int* a, int* b) {
int tmp;
tmp = *a;
*a = *b;
*b = tmp;
}
int partition(int vec[], int left, int right) {
int i, j;
i = left;
for (j = left + 1; j <= right; ++j) {
if (vec[j] < vec[left]) {
++i;
swap(&vec[i], &vec[j]);
}
}
swap(&vec[left], &vec[i]);
return i;
}
void quickSort(int vec[], int left, int right) {
int r;
if (right > left) {
r = partition(vec, left, right);
quickSort(vec, left, r - 1);
quickSort(vec, r + 1, right);
}
}
Implementação quicksort testado com ate 1000000 de elementos para dados crescente, decrescente e aleatório
void swap(int *a, int i, int j) {
int t = a[i];
a[i] = a[j];
a[j] = t;
}
int partition(int *a, int left,int right,int pivot)
{
int pos, i;
swap(a, pivot, right);
pos = left;
for(i = left; i < right; i++)
{
if (a[i] < a[right])
{
swap(a, i, pos);
pos++;
}
}
swap(a, right, pos);
return pos;
}
void quick(int *a, int left, int right)
{
if (left < right)
{
int pivot = (left+right)/2;
int pos = partition(a,left,right,pivot);
quick(a,left,pos-1);
quick(a,pos+1,right);
}
}
Implementaçao usando 'fat pivot':
void sort(int array[], int begin, int end) {
int pivot = array[begin];
int i = begin + 1, j = end, k = end;
int t;
while (i < j) {
if (array[i] < pivot) i++;
else if (array[i] > pivot) {
j--; k--;
t = array[i];
array[i] = array[j];
array[j] = array[k];
array[k] = t; }
else {
j--;
swap(array[i], array[j]);
} }
i--;
swap(array[begin], array[i]);
if (i - begin > 1)
sort(array, begin, i);
if (end - k > 1)
sort(array, k, end);
}
Lembrando que quando você for chamar a função recursiva terá que chamar a mesma da seguinte forma
ordenar_quicksort_nome(0,n-1). O 0(zero) serve para o início receber a posição zero do vetor e o fim será o tamanho do vetor -
1.
void ordenar_quicksort_nome(int ini, int fim)
{
int i = ini, f = fim;
char pivo[50];
strcpy(pivo,vetor[(ini+fim)/2]);
if (i<=f)
{
while (strcmpi(vetor[i],pivo)<0) i++;
while (strcmpi(vetor[f],pivo)>0) f--;
if (i<=f)
{
strcpy (aux_char,vetor[i]);
strcpy (vetor[i],vetor[f]);
strcpy (vetor[f],aux_char);
i++; f--;
}
}
if (f>ini) ordenar_quicksort_nome(ini,f);
if (i<fim) ordenar_quicksort_nome(i,fim);
}
[editar]JAVA
public static void quick_sort(int []v,int ini, int fim) {
int meio;
if (ini < fim) {
meio = partition(v, ini, fim);
quick_sort(v, ini, meio);
quick_sort(v, meio + 1, fim);
}
}
public static int partition(int []v, int ini, int fim) {
int pivo, topo, i;
pivo = v[ini];
topo = ini;
for (i = ini + 1; i <= fim; i++) {
if (v[i] < pivo) {
v[topo] = v[i];
v[i] = v[topo + 1];
topo++;
}
}
v[topo] = pivo;
return topo;
}
[editar]JAVA
public static void quickSort(int[] v, int inicio, int fim){
if(inicio<fim){
int pivo=inicio, i=fim, vPivo=v[pivo];
while(pivo<i){
if(vPivo>v[i]){
v[pivo]=v[i];
pivo=i;
i=inicio+1;
while(pivo>i){
if(vPivo<v[i]){
v[pivo]=v[i];
pivo=i;
i=fim;
break;
}else
i++;
}
} else
i--;
}
v[pivo]=vPivo;
quicksort(v, inicio, pivo-1);
quicksort(v, pivo+1, fim);
}
}
Comparação com outros algoritmos de ordenação
Quicksort é uma versão optimizada de uma árvore binária ordenada. Em vez de introduzir itens sequencialmente numa árvore
explicita, o Quicksort organiza-os correntemente na árvore onde está implícito, fazendo-o com chamadas recursivas à mesma.
O algoritmo faz exactamente as mesmas comparações, mas com uma ordem diferente.
O algoritmo que mais se familiariza com o Quicksort é o Heapsort. Para o pior caso neste algoritmo temos .
Mas, o Heapsort em média trata-se de uma algoritmo mais lento que o Quicksort, embora tenha sido muito debatido essa
afirmação. No Quicksort permanece o caso do pior caso, à excepção quando se trata de usar a variante Intro sort, que muda
para Heapsort quando um pior caso é detectado. Caso se saiba à partida que será necessário o uso do heapsort é
aconselhável usá-lo directamente, do que usar o introsort e depois chamar o heapsort, torna mais rápido o algoritmo.
O Quicksort também compete com o Mergesort, outro algoritmo de ordenação recursiva, tendo este o benefício de ter como
pior caso . Mergesort, ao contrário do Quicksort e do Heapsort, é estável e pode facilmente ser adptado para
operar em listas encadeadas e em listas bastantes grandes alojadas num tipo de acesso lento a média como um Network-
Attached Storage ou num disco. Embora o Quicksort possa ser operado em listas encadeadas, por vezes escolhendo um mau
pivô sem acesso aleatório. A maior desvantagem do Mergesort é que quando opera em arrays, requer de espaço para
o melhor caso, considerando que o Quicksort com um particionamento espacial e com recursão utiliza apenas de
espaço.
Bucket sort com dois buckets é muito parecido ao Quicksort (quase idêntico), o pivô neste caso é garantidamente o valor do
meio do vector.
Selection sort
Origem: Wikipédia, a enciclopédia livre.
O selection sort (do inglês, ordenação por seleção) é um algoritmo de ordenação baseado em se passar sempre o menor
valor do vetor para a primeira posição (ou o maior dependendo da ordem requerida), depois o de segundo menor valor para a
segunda posição, e assim é feito sucessivamente com os (n-1) elementos restantes, até os últimos dois elementos.
== Complexidade == Muito Complexo
O algoritmo possui complexidade enquanto que, por exemplo, os algoritmos Heapsort e Mergesort possuem
complexidades .
[editar]Implementações
[editar]C
void selection_sort(int num[], int tam)
{
int i, j, min;
for (i = 0; i < (tam-1); i++)
{
min = i;
for (j = (i+1); j < tam; j++) {
if(num[j] < num[min]) {
min = j;
}
}
if (i != min) {
int swap = num[i];
num[i] = num[min];
num[min] = swap;
}
}
}
Código da ordenação SelectionSort com strings
void ordenar_selecao_nome() {
int i,j,n;
for(i=0; i<n-1; i++) {
for(j=i+1; j<n; j++) {
if(strcmp(vetor[i], vetor[j])>0) {
strcpy(aux_char, vetor[i]);
strcpy(vetor[i], vetor[j]);
strcpy(vetor[j], aux_char);
}
}
}
[editar]Código em C++
template<class T>
void selection_sort( std::vector<T> &lista )
{
for( std::vector<T>::iterator it = lista.begin(); it != lista.end()-1; ++it )
{
std::iter_swap( it, std::min_element( it, lista.end() ) );
}
}
[editar]Código em Java
public static void SelectionSort(int[] v) {
int index_min;
int aux;
for (int i = 0; i < v.length; i++) {
index_min = i;
for (int j = i + 1; j < v.length; j++) {
if (v[j] < v[index_min]) {
index_min = j;
}
}
if (index_min != i) {
aux = v[index_min];
v[index_min] = v[i];
v[i] = aux;
}
}
}
Shell sort Origem: Wikipédia, a enciclopédia livre.
Criado por Donald Shell em 1959,[1]
publicado pela Universidade de Cincinnati, Shell sort é o mais
eficiente algoritmo de classificação dentre os de complexidade quadrática. É um refinamento do método de inserção direta.[2]
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.[3]
Basicamente o
algoritmo passa várias vezes pela lista dividindo o grupo maior em menores. Nos grupos menores é aplicado o método
[editar]Implementações do algoritmo
[editar]Código em Java
public static void shellSort(Integer[] nums) {
int n = nums.length;
int h = n / 2;
int c, j;
while (h > 0) {
for (int i = h; i < n; i++) {
c = nums[i];
j = i;
while (j >= h && nums[j - h] > c) {
nums[j] = nums[j - h];
j = j - h;
}
nums[j] = c;
}
h = h / 2;
}
}
[editar]Código em C++
void ShellSort( apvector <int> &num) {
int i, temp, flag = 1, numLength = num.length( );
int d = numLength;
while( flag || (d > 1)) { // boolean flag (true when not equal to 0)
flag = 0; // reset flag to 0 to check for future swaps
d = (d+1) / 2;
for (i = 0; i < (numLength - d); i++) {
if (num[i + d] > num[i]) {
temp = num[i + d]; // swap positions i+d and i
num[i + d] = num[i];
num[i] = temp;
flag = 1; // tells swap has occurred
}
}
}
return;
}
[editar]Código em C
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);
}
[editar]Exemplo de execução
Execução:
Dado o vetor de entrada: 12, 43, 1, 6, 56, 23, 52, 9
12, 43, 1, 6, 56, 23, 52, 9
12, 43, 1, 6, 56, 23, 52, 9
1, 43, 12, 6, 56, 23, 52, 9
1, 6, 12, 23, 56, 43, 52, 9
1, 6, 12, 23, 52, 43, 56, 9
1, 6, 12, 23, 52, 9, 56, 43
1, 6, 12, 9, 52, 23, 56, 43
1, 6, 9, 12, 52, 23, 56, 43
1, 6, 9, 12, 23, 52, 56, 43
1, 6, 9, 12, 23, 52, 43, 56
1, 6, 9, 12, 23, 43, 52, 56
Em negrito estão os números trocados na atual iteração.
Após as seguintes trocas acima, obtemos o vetor ordenado: 1, 6, 9, 12, 23, 43, 52, 56.
[editar]Conclusão
A ordenação Shell utiliza a quebra sucessiva da sequência a ser ordenada e implementa a ordenação por inserção na
sequência obtida. Por ser um método de complexidade O(n^2 ) não é aconselhável a sua implementação para sequências
grandes, mas possui uma boa eficiência para as pequenas e medianas.