Quicksort

O algoritmo Quicksort é um método de ordenação muito rápido e eficiente, inventado por C.A.R. Hoare em 1960, quando visitou a Universidade de Moscou como estudante. Foi publicado em 1962 após uma série de refinamentos.

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

O algoritmo

O Quicksort adota a estratégia de divisão e conquista. Os passos são:

  • Escolha um elemento da lista, denominado pivô;
  • Rearranje a lista de forma que todos os elementos anteriores ao pivô sejam menores ou iguais a ele, e todos os elementos posteriores ao pivô sejam maiores ou iguais a ele. Ao fim do processo o pivô estará em sua posição final;
  • Essa operação é denominada partição;
  • Recursivamente ordene a sub-lista dos elementos menores e a sub-lista 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.

Complexidade

  • Complexidade de tempo: ?(n lg2 n) no melhor caso e no caso médio e ?(n2) no pior caso;
  • Complexidade de espaço: ?(lg2 n) no melhor caso e no caso médio e ?(n) no pior caso.

Implementações

Pseudocódigo


proc quicksort (x:vet[n] int; ini:int; fim:int; n:int)
var
   int: i,j,y,aux;

início
   i <- ini;
   j <- fim;
   y <- x[(ini + fim) div 2];
   repete
       enquanto (x[i] < y) faça
          i <- i + 1;
       fim-enquanto;
       enquanto (x[j] > y) faça
          j <- j - 1;
       fim-enquanto;
       se (i <= j) então
          aux <- x[i];
          x[i] <- x[j];
          x[j] <- aux;
          i <- i + 1;
          j <- j - 1;
       fim-se;
    até_que (i >= j);
    se (j > ini) então
        exec quicksort (x, ini, j, n);
    fim-se;
    se (i < fim) então
        exec quicksort (x, i, fim, n);
    fim-se;
fim.

Delphi


procedure QuickSort(var A: array of Integer);

 procedure QuickSort(var A: array of Integer; iLo,
 iHi: Integer);
 var
   Lo, Hi, Mid, T: Integer;
 begin
   Lo := iLo;
   Hi := iHi;
   Mid := A[(Lo + Hi) div 2];
   repeat
     while A[Lo] < Mid do Inc(Lo);
     while A[Hi] > Mid do Dec(Hi);
     if Lo <= Hi then
     begin
       T := A[Lo];
       A[Lo] := A[Hi];
       A[Hi] := T;
       Inc(Lo);
       Dec(Hi);
     end;
   until Lo > Hi;
   if Hi > iLo then QuickSort(A, iLo, Hi);
   if Lo < iHi then QuickSort(A, Lo, iHi);
 end;

begin
 QuickSort(A, Low(A), High(A));
end;

{Chamando em um evento de onClick}
procedure TForm1.Button1Click(Sender: TObject);
var
 arr: array[0..100] of integer;
 I: Integer;
begin
 for I:=Low(arr) to High(arr) do
   arr[I]:=Random(High(Integer));

 Quick_Sort(arr);
end;

Visual Basic


Sub QuickSort(ByRef vetor() As Integer, ByVal 
inicio As Integer, 
ByVal final As Integer, ByRef iteracoes As Long)
    Dim pivo As Integer
    Dim i As Integer
    Dim j As Integer
    iteracoes = iteracoes + 1
    If final > inicio Then
        i = inicio
        j = final
        pivo = vetor(Fix((inicio + final) / 2))
        While i <= j
            While vetor(i) < pivo
                i = i + 1
            Wend
            While pivo < vetor(j)
                j = j - 1
            Wend
            If i <= j Then
                Call Troca(vetor(i), vetor(j))
                i = i + 1
                j = j + 1
            End If
        Wend
        Call QuickSort(vetor, inicio, j, iteracoes)
        Call QuickSort(vetor, i, final, iteracoes)
    End If
        
End Sub

Sub Troca(ByRef val1 As Integer, ByRef val2 As Integer)
    Dim aux As Integer
    aux = val1
    val1 = val2
    val2 = aux
End Sub

Python


def quicksort(lista):
     if lista == []:
        return lista
     else:
         pivo = lista[0]
         maiores = []
         menores = []
         for x in lista[1:]:
             if x < pivo:
                 menores.append(x)
             else:
                 maiores.append(x)
         return quicksort(menores) + [pivo] +
 quicksort(maiores)


Assembly x86-gas-Linux



/*void quicksort_as (int *x, int n);*/
.globl quicksort_as
quicksort_as:
        pushl %ebp
        movl %esp, %ebp
        /* 8(%ebp)= ponteiro do arranjo */
        /* 12(%ebp)= num de elementos */
        movl 12(%ebp), %eax
        dec %eax
        movl $4, %ebx
        mul %ebx
        pushl %eax
        pushl $0
        pushl 8(%ebp)
        call quicksort_as_
        leave
        ret
quicksort_as_:
        pushl %ebp
        movl %esp, %ebp
        /* 8(%ebp)= ponteiro do arranjo */
        /* 12(%ebp)= esq */
        /* 16(%ebp)= dir */
        movl 12(%ebp), %ecx
        movl %ecx, %edx
        movl 8(%ebp), %eax
        addl %ecx, %eax
        movl 16(%ebp), %ecx
        movl 8(%ebp), %ebx
        addl %ecx, %ebx
        /* agora %eax aponta p/ x[esq] e %ebx x[dir]*/
        addl %edx, %ecx  /*%ecx eh esq + dir*/
        pushl %eax
        movl %ecx, %eax
        movl $2, %ecx
        cltd
        idivl %ecx  /* div %eax por 2=%ecx*/
        movl $4, %ecx
        cltd
        idivl %ecx
        mul  %ecx
        movl 8(%ebp), %ecx
        addl %eax, %ecx
        movl (%ecx), %ecx
        popl %eax
        /*%ecx = compare(cmp)*/ 
quicksort_imj:
        cmp %eax, %ebx
        jle quicksort_fim
quicksort_inci:
        cmp (%eax), %ecx
        jle quicksort_incj
        addl $4, %eax
        jmp quicksort_inci
quicksort_incj:
        cmp (%ebx), %ecx
        jge quicksort_troca
        subl $4, %ebx
        jmp quicksort_incj
quicksort_troca:
        cmp %eax, %ebx
        jl quicksort_fim
        movl (%ebx), %edx
        pushl (%eax)
        movl %edx, (%eax)
        popl (%ebx)
        addl $4, %eax
        subl $4, %ebx
        jmp quicksort_imj
quicksort_fim:
        /*salvando registradores na pilha
 p/ fazer chamada de função*/
        pushl %eax
        pushl %ebx
        /*passando parametros p/ chamada recursiva*/
        subl 8(%ebp), %eax
        cmp %eax, 16(%ebp)
        jle quicksort_2a_rec
        pushl 16(%ebp)
        pushl %eax
        pushl 8(%ebp)
        call quicksort_as_
        addl $12, %esp
quicksort_2a_rec:
        /*recuperando registradores apos chamada de funcao*/
        popl %ebx
        popl %eax
        subl 8(%ebp), %ebx
        cmp %ebx, 12(%ebp)
        jge quicksort_final
        /*passando parametros p/ chamada recursiva*/
        pushl %ebx
        pushl 12(%ebp)
        pushl 8(%ebp)
        call quicksort_as_
quicksort_final:
        leave
        ret

Haskell


 sort :: (Ord a)   => [a] -> [a]
  
  sort []           = []
  sort (pivot:rest) = (sort [y | y <- rest, y < pivot])
                       ++ [pivot] ++ 
                      (sort [y | y <- rest, y >=pivot])


Lisp


(defun partition (fun array)
  (list (remove-if-not fun array)
 (remove-if fun array)))
 
(defun sort (array)
  (if (null array) nil
    (let ((part (partition (lambda (x) (< x (car array)))
 (cdr array))))
      (append (sort (car part)) (cons (car array)
	  (sort (cadr part)))))))


Ruby


def sort( array )
   return array if array.size <= 1
   pivot = array[0]
   return sort( array.select { |y| y < pivot } )
          + array.select { |y| y == pivot } + 
          sort( array.select { |y| y > pivot } )
end

Groovy


def sort(list) {
    if (list.isEmpty()) return list
    anItem = list[0]
    def smallerItems = list.findAll{it < anItem}
    def equalItems = list.findAll{it == anItem}
    def largerItems = list.findAll{it > anItem}
    sort(smallerItems) + equalItems + sort(largerItems)
}

ML


fun filter nil elem cmp = nil
  | filter (x::xl) elem cmp  =
      if (cmp(x, elem))
        then x :: filter xl elem cmp
        else filter xl elem cmp;

fun quicksort nil = nil
  | quicksort (pivot::xl) =
      let
        val small = filter xl pivot (op <);
        val medium = pivot :: filter xl pivot (op =);
        val large = filter xl pivot (op >);
      in
        (quicksort small) @ medium @ (quicksort large)
      end;

PHP


 $j){
        if ($vet[$i] > $vet[$j]){
            troca($vet[$i], $vet[$j]);
            $dir = - $dir;
        }
        if ($dir == 1) {
            $j--; 
        }else{
            $i++;
        }   
        return $i;
    }
}
//ordena
function quicksort($vet=array(), $ini, $fim){
    if ($ini < $fim){
        $k = divide($vet, $ini, $fim);
        quicksort($vet, $ini, $k-1);
        quicksort($vet, $k+1, $fim);
    }
}
quicksort($vet,0,count($vet));
?>

C++


#include 
#include 
#include 
using namespace std;

template 
void sort(T begin, T end) {
    if (begin != end) {
        T middle = partition 
(begin, end, bind2nd(less::value_type>(), *begin));
        sort (begin, middle);
        sort (max(begin + 1, middle), end);
    }
}

C


void sort(int array[], int begin, int end) {
   if (end - begin > 0) {
      int pivot = array[begin];
      int l = begin + 1;
      int r = end;
      while(l < r) {
         if (array[l] <= pivot) {
            l++;
         } else {
            swap(array[l], array[r]); 
            r--;
         }
      }
      if (array[l] > pivot) {
         l--;
      }
      swap(array[begin], array[l]);
      sort(array, begin, l-1);
      sort(array, r, end);
   }
}

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

Java


import java.util.Comparator;
import java.util.Random;

public class Quicksort {
    public static final Random RND = new Random();      
    private static void swap(Object[] array,
 int i, int j) {
        Object tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }
    private int partition(Object[] array, int begin,
 int end, Comparator cmp) {
        int index = begin + RND.nextInt
(end - begin + 1);
        Object pivot = array[index];
        swap(array, index, end);                
        for (int i = index = begin; i < end; ++ i) {
            if (cmp.compare(array[i+1], pivot) <= 0)
 {
                swap(array, index++, i);
        }   }
        swap(array, index, end);        
        return (index);
    }
    private void qsort(Object[] array, int begin, 
	int end, Comparator cmp) {
        if (end > begin) {
            int index = partition(array,
 begin, end, cmp);
            qsort(array, begin, index, cmp);
            qsort(array, index,  end,  cmp);
    }   }
    public void sort(Object[] array, Comparator cmp)
 {
        qsort(array, 0, array.length - 1, cmp);
    }
}


 Exemplo em J2SE 5.0 com método para teste.


import java.util.Arrays;
import java.util.Random;
 
public class QuickSort> {
    public static final Random RND = new Random();
 
    private void swap(E[] array, int i, int j) {
        E tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }
 
    private int partition(E[] array, 
int begin, int end) {
        int index = begin + RND.nextInt
(end - begin + 1);
        E pivot = array[index];
        swap(array, index, end);
        for (int i = index = begin; i < end; ++i) {
            if (array[i].compareTo(pivot) <= 0) {
                swap(array, index++, i);
            }
        }
        swap(array, index, end);
        return (index);
    }
 
    private void qsort(E[] array, 
int begin, int end) {
        if (end > begin) {
            int index = partition
(array, begin, end);
            qsort(array, begin, index - 1);
            qsort(array, index + 1, end);
        }
    }
 
    public void sort(E[] array) {
        qsort(array, 0, array.length - 1);
    }
 
    // Example uses
    public static void main(String[] args) {
        Integer[] l1 = 
{ 5, 1024, 1, 88, 0, 1024 };
        System.out.println("l1  
start:" + Arrays.toString(l1));
        QuickSort 
qs = new QuickSort();
        qs.sort(l1);
        System.out.println
("l1 sorted:" + Arrays.toString(l1));
 
        String[] l2 = 
{ "gamma", "beta", "alpha", "zoolander" };
        System.out.println
("l2  start:" + Arrays.toString(l2));
        QuickSort
 qs2 = new QuickSort();
        qs2.sort(l2);
        System.out.println
("l2 sorted:" + Arrays.toString(l2));
    }
}

C#



static class QuickSort 
{
   public static void Ordenar(int[] vetor) {
      Ordenar(vetor, 0, vetor.Length - 1);
   }

   private static void Ordenar(int[]
 vetor, int inicio, int fim) {
      if (inicio < fim) {
         int posicaoPivo = Separar(vetor, inicio, fim);
         Ordenar(vetor, inicio, posicaoPivo - 1);
         Ordenar(vetor, posicaoPivo + 1, fim); 
      }
   }

   private static int Separar(int[] 
vetor, int inicio, int fim) {
      int pivo = vetor[inicio];
      int i = inicio + 1, f = fim;
      while (i <= f) {
         if (vetor[i] <= pivo) 
            i++;
         else if (pivo < vetor[f])
            f--;
         else {
            int troca = vetor[i];
            vetor[i] = vetor[f];
            vetor[f] = troca;
            i++;
            f--;
         }
      }
      vetor[inicio] = vetor[f];
      vetor[f] = pivo;
      return f;
   }
}

Assembly x86


qsort:  @ Takes three parameters:
       @ a: Pointer to base of array a to
 be sorted (arrives in r0)
       @   left: First of the range of indexes
 to sort (arrives in r1)
       @   right: One past last of range 
of indexes to sort (arrives in r2)
       @ This function destroys: 
r1, r2, r3, r4, r5, r7
       stmfd   sp!, {r4, r6, lr}
  @ Save r4 and r6 for caller
       mov     r6, r2    @ r6 <- right
 qsort_tailcall_entry:
       sub     r7, r6, r1 @ If right 
- left <= 1 (already sorted),
       cmp     r7, #1
       ldmlefd sp!, {r1, r6, pc}
 @ Return, moving r4->r1, restoring r6
       ldr     r7, [r0, r1, asl #2] 
 @ r7 <- a[left], gets pivot element
       add     r2, r1, #1   
         @ l <- left + 1
       mov     r4, r6     
           @ r <- right
 partition_loop:
       ldr     r3, [r0, r2, asl #2]  @ r3 <- a[l]
       cmp     r3, r7 @ If a[l] <= pivot_element,
       addle   r2, r2, #1     
       @ ... increment l, and
       ble     partition_test @ 
... continue to next iteration.
       sub     r4, r4, #1       
     @ Otherwise, decrement r,
       ldr     r5, [r0, r4, asl #2]
  @ ... and swap a[l] and a[r].
       str     r5, [r0, r2, asl #2]
       str     r3, [r0, r4, asl #2]
 partition_test:
       cmp     r2, r4  @ If l < r,
       blt     partition_loop @
 ... continue iterating.
 partition_finish:
       sub     r2, r2, #1   
         @ Decrement l
       ldr     r3, [r0, r2, asl #2] 
 @ Swap a[l] and pivot
       str     r3, [r0, r1, asl #2]
       str     r7, [r0, r2, asl #2]
       bl      qsort  
  @ Call self recursively on left part,
                      
  @  with args a (r0), left (r1), r (r2),
                    
    @  also preserves r6 and
                     
   @  moves r4 (l) to 2nd arg register (r1)
       b    qsort_tailcall_entry 
 @ Tail-call self on right part,
                     
   @  with args a (r0), l (r1), right (r6)


[Topo]

 


Associação SoftwareLivre

A Associação SoftwareLivre.org (ASL) é uma associação civil sem fins-lucrativos, com sede em Porto Alegre/RS que reúne empresários, profissionais liberais, estudantes e servidores públicos, estabelecendo relações com os mais diversos setores da sociedade como o poder público, universidades, empresas, grupos de usuários, hackers e ONGs. A ASL tem por principal objetivo tornar o software livre amplamente incluído na sociedade, propiciando espaço de discussão, apoio, fomento e organização de iniciativas nas mais diversas áreas relacionadas. - Site oficial da associação