Ordenação por Mesclagem (Merge Sort)
O algoritmo de ordenação por mesclagem é uma aplicação clássica da estratégia divide-and-conquer. Sua estrutura recursiva particiona repetidamente o conjunto de dados até alcançar escalares individuais, para então recombiná-los progressivamante em estruturas ordenadas. Esse fluxo garante consistência temporal previsível, independentemente da configuração inicial dos elementos.
Mecanismo de Fusão
Durante a junção de dois subintervalos previamente ordenados, posicionam-se indicadores no início de cada segmento. O menor valor é transferido para um buffer temporário e seu respectivo ponteiro avança. O ciclo se repete até que um dos lados seja consumido totalmente, momento em que os remanescentes são copiados integralmente. Ao retornar das chamadas recursivas, o arranjo original é sobrescrito pelos dados consolidados.
Implementação em C++
#include <vector>
void merge(std::vector<int>& auxiliary, std::vector<int>& target, int lower, int upper) {
int pivot = lower + (upper - lower) / 2;
int leftPtr = lower, rightPtr = pivot + 1, copyIdx = lower;
while (leftPtr <= pivot && rightPtr <= upper) {
if (target[leftPtr] <= target[rightPtr]) {
auxiliary[copyIdx++] = target[leftPtr++];
} else {
auxiliary[copyIdx++] = target[rightPtr++];
}
}
while (leftPtr <= pivot) auxiliary[copyIdx++] = target[leftPtr++];
while (rightPtr <= upper) auxiliary[copyIdx++] = target[rightPtr++];
for (int i = lower; i <= upper; ++i) {
target[i] = auxiliary[i];
}
}
void executeMergeSort(std::vector<int>& auxiliary, std::vector<int>& target, int lower, int upper) {
if (lower >= upper) return;
int pivot = lower + (upper - lower) / 2;
executeMergeSort(auxiliary, target, lower, pivot);
executeMergeSort(auxiliary, target, pivot + 1, upper);
merge(auxiliary, target, lower, upper);
}
Detecção de Pares Invertidos
Um par invertido surge quando um elemento posicionado antes de outro apresenta valor superior (i < j entretanto arr[i] > arr[j]). Utilizar verificações duplas resulta em complexidade quadrática, tornando a abordagem inviável para conjuntos extensos. O Merge Sort pode ser estendido para rastrear essas ocorrências naturalmente durante a etapa de fusão.
Quando o indicador do lado direito avança por conter um valor inferior ao corrente do lado esquerdo, conclui-se que esse valor direito é menor que todos os elementos ainda não processados na metade esquerda. A contagem aumenta exatamente em pivot - leftPtr + 1, agregando múltiplas inversões em uma única operação constante.
Código Aprimorado para Acumulação de Inversões
#include <vector>
void countInversions(std::vector<int>& auxiliary, std::vector<int>& data, int lower, int upper, long long& inversionCounter) {
if (lower >= upper) return;
int pivot = lower + (upper - lower) / 2;
countInversions(auxiliary, data, lower, pivot, inversionCounter);
countInversions(auxiliary, data, pivot + 1, upper, inversionCounter);
int leftPtr = lower, rightPtr = pivot + 1, currentPos = lower;
while (leftPtr <= pivot && rightPtr <= upper) {
if (data[leftPtr] <= data[rightPtr]) {
auxiliary[currentPos++] = data[leftPtr++];
} else {
// Valor da direita menor que todos os restantes da esquerda
inversionCounter += (pivot - leftPtr + 1);
auxiliary[currentPos++] = data[rightPtr++];
}
}
while (leftPtr <= pivot) auxiliary[currentPos++] = data[leftPtr++];
while (rightPtr <= upper) auxiliary[currentPos++] = data[rightPtr++];
for (int idx = lower; idx <= upper; ++idx) {
data[idx] = auxiliary[idx];
}
}
Comparativo Técnico entre Métodos de Ordenação
Estabilidade
A estabilidade preserva a ordem relativa de chaves equivalentes. Algoritmos estáveis: Insertion, Bubble, Merge e Radix/Bucket. Algoritmos não estáveis: Selection, Shell, Quick e Heap. Aplicações que demandam ordenação multidimensional frequentemente exigem estabilidade para garantir regras secundárias.
Complexidade Temporal e de Memória Auxiliar
- O(n²): Insertion, Bubble, Selection.
- O(n log n): Quick, Heap, Merge.
- O(n): Bucket/Radix (limitado a domínios conhecidos).
- Espaço Extra: Merge e Bucket necessitam O(n). Quick ocupa O(log n) em média (pior caso O(n)). Ensertion e Heap operam in-place com O(1).
Fatores de Escolha
- Sequências parcial ou totalmente organizadas beneficiam diretamente Insertion e Bubble, enquanto Quick pode apresentar lentidão.
- Para pequenos volumes sem restrição de estabilidade, Selection ou Insertion oferecem implementação direta e baixo overhead.
- Amplitude finita e memória abundante justificam o uso de Bucket sort para ganho linear.
- Grandes datasets distribuídos aleatoriamente, sem exigência de estabilidade, têm no Quick Sort a opção preferencial em benchmarks práticos.
- Restrições rigorosas de memória combinadas com garantia O(n log n) no pior cenário apontam para Heap Sort.
Problema de Fixação
Enunciado
Solicite três números inteiros e apresente-os dispostos em ordem crescente, separados por espaços. A resolução deve empregar manualmente as estratégias discutidas, abstendo-se de funções prontas de bibliotecas padrão.
Especificação de Entrada
Três valores inteiros consecutivos na mesma linha.
Especificação de Saída
Sequência ordenada seguida de uma nova linha.
Referência Operacional
Entrada:
7 -4 12
Saída:
-4 7 12