Está en la página 1de 13

Ordenamiento por mezcla 1

Ordenamiento por mezcla


El algoritmo de ordenamiento por mezcla (merge sort en inglés) es un algoritmo de ordenamiento externo estable
basado en la técnica divide y vencerás. Es de complejidad O(n log n).

Descripción
Fue desarrollado en 1945 por John Von Neumann.[cita requerida]
Conceptualmente, el ordenamiento por mezcla funciona de la siguiente
manera:
1. Si la longitud de la lista es 0 ó 1, entonces ya está ordenada. En otro
caso:
2. Dividir la lista desordenada en dos sublistas de aproximadamente la Ejemplo de ordenamiento por mezcla.

mitad del tamaño.

3. Ordenar cada sublista recursivamente aplicando el ordenamiento por mezcla.


4. Mezclar las dos sublistas en una sola lista ordenada.
El ordenamiento por mezcla incorpora dos ideas principales para mejorar su tiempo de ejecución:
1. Una lista pequeña necesitará menos pasos para ordenarse que una lista grande.
2. Se necesitan menos pasos para construir una lista ordenada a partir de dos listas también ordenadas, que a partir
de dos listas desordenadas. Por ejemplo, sólo será necesario entrelazar cada lista una vez que están ordenadas.
A continuación se describe el algoritmo en pseudocódigo (se advierte de que no se incluyen casos especiales para
vectores vacíos, etc.; una implementación en un lenguaje de programación real debería tener en cuenta estos
detalles):

function mergesort(array A[x..y])


begin
if ((y-x) > 0):
array A1 := mergesort(A[x..(int( x+y / 2))])
array A2 := mergesort(A[int(1+(x+y / 2))..y])
return merge(A1, A2)
else:
return A
end

function merge(array A1[0..n1], array A2[0..n2])


begin
integer p1 := 0
integer p2 := 0
array R[0..(n1 + n2 + 2)]//suponiendo que n1 y n2 son las posiciones
//del array y no el length de este mismo, de otro modo seria (n1 + n2)
while (p1 <= n1 and p2 <= n2):
if (p1 <= n1 and A1[p1] <= A2[p2]):
R[p1 + p2] := A1[p1]
p1 := p1 + 1

else
Ordenamiento por mezcla 2

if (p2 <= n2 and A1[p1] > A2[p2]):


R[p1 + p2] := A2[p2]
p2 := p2 + 1
return R
end

Implementaciones

Perl
sub mergesort {
mergesort_recursivo ($_[0], 0, $#{ $_[0] }); # Recibimos una
referencia a un array
}

sub mergesort_recursivo {
my ( $array, $primero, $ultimo ) = @_;

if ( $ultimo > $primero ) {


local $^W = 0; # Quitamos el aviso de exceso de
recursión

my $mitad = int(( $ultimo + $primero ) / 2);


mergesort_recursivo( $array, $primero, $mitad );
mergesort_recursivo( $array, $mitad + 1, $ultimo );
merge( $array, $primero, $mitad, $ultimo );
}
}

my @work; # Una variable global.

sub merge {
my ( $array, $primero, $mitad, $ultimo ) = @_;
my $n = $ultimo - $primero + 1;

# Inicializa @work con elementos importantes del array


for ( my $i = $primero, my $j = 0; $i <= $ultimo; ) {
$work[ $j++ ] = $array->[ $i++ ];
}

# Ahora hace la verdadera mezcla. Atraviesa el array


# y copia los elementos en orden inverso al array original
# $i es el índice del resultado de la mezcla, $j es el índice en
# la primera mitad de la copia de trabajo, $k el índice de la
segunda mitad.

$mitad = int(($primero + $ultimo) / 2) if $mitad > $ultimo;


my $n1 = $mitad - $primero + 1; # El tamaño de la primera
Ordenamiento por mezcla 3

mitad.

for ( my $i = $primero, my $j = 0, my $k = $n1;


$i <= $ultimo;
$i++ ) {

$array->[ $i ] =
$j < $n1
&&
( $k == $n || $work[ $j ] < $work[ $k ] )
? $work[ $j++ ]
: $work[ $k++ ]
;
}
}

C
void combinar(int array[], int inicio, int medio, int fin)
{
int aux[fin-inicio+1];
int indAux, indFst, indSnd;
int i;

indAux = 0; //<! indice del arreglo auxiliar


indFst = inicio; //<! indice de la primera mitad
indSnd = medio+1; //<! indice de la segunda mitad

while (indFst <= medio && indSnd <= fin)


{
if (array[indFst] <= array[indSnd])
{
aux[indAux++] = array[indFst++];
}
else
{
aux[indAux++] = array[indSnd++];
}
}

// Se copian los elementos de la primera mitad no comparados

while (indFst<=medio)
{
aux[indAux++] = array[indFst++];
}

// Se copian los elementos de la segunda mitad no comparados


Ordenamiento por mezcla 4

while (indSnd <= fin)


{
aux[indAux++] = array[indSnd++];
}

indAux = 0;

/* Finalmente se copian los elementos del array auxiliar (ordenados)


en el array original */

for (i = inicio; i <= fin; i++)


{
array[i] = aux[indAux++];
}
}

void mergeSort(int array[], int inicio, int fin)


{
int medio = (inicio + fin)>>1; // Division por 2 menos costosa

if (inicio < fin)


{
mergeSort(array, inicio, medio);
mergeSort(array, medio +1, fin);
combinar(array, inicio, medio, fin);
}
}

int main()
{
int i, v[11]= {6,7,1,7,8,36,7,4,7,4,4};

mergeSort(v, 0, 10);

for (i=0; i<11; i++)


{
printf("%i - ", v[i]);
}
}

C++
// En el código usamos la clase vector (#include <vector.h>) para crear los
vectores,
// obviamente funciona igual de bien si se utilizan los arrays tipo C:
TIPO V[]
template <class T, class U>
Ordenamiento por mezcla 5

void fusiona(vector<T>& v, U ini, U med, U fin) {


vector<T> aux(fin - ini + 1);
int i = ini; // Índice de la parte izquierda
int j = med + 1; // Índice de la parte derecha
int k = 0; // Índice del vector aux

/* Mientras ninguno de los indices llegue a su fin vamos realizando


comparaciones. El elemento más pequeño se copia al vector aux */
while (i <= med && j <= fin) {
if (v[i] < v[j]) {
aux[k] = v[i];
i++;
}
else {
aux[k] = v[j];
j++;
}
k++;
}

/* Uno de los dos sub-vectores ya ha sido copiado del todo,


simplemente
debemos copiar todo el sub-vector que nos falte */
while (i <= med) {
aux[k] = v[i];
i++;
k++;
}

while (j <= fin) {


aux[k] = v[j];
j++;
k++;
}

/* Copiamos los elementos ordenados de aux al vector original v */


for (int n = 0; n < aux.size(); ++n) v[ini + n] = aux[n];
}

template <class T, class U>


void merge_sort(vector<T>& v, U ini, U fin) {
/* Si ini = fin el sub-vector es de un solo elemento y, por lo
tanto
ya está ordenado por definición */
if (ini < fin) {
/*Considerar que el valor de med siempre es redondeado hacia abajo.*/
Ordenamiento por mezcla 6

int med = (ini + fin)/2;


merge_sort(v, ini, med);
merge_sort(v, med + 1, fin);
fusiona(v, ini, med, fin);
}
}

Visual Basic
Option Base 1

Private Sub Form_Load()


Dim N As Integer
N = InputBox("Tamaño del arreglo: ", "MergeSort")
ReDim A(N) As Integer
For i = 1 To N
A(i) = CInt(InputBox("Elemento " & i & ":"))
Next
MergeSort N, A, 1, N
Dim Arreglo As String
For j = 1 To N
Arreglo = Arreglo & A(j) & " "
Next
MsgBox Arreglo, vbInformation, "MergeSort"
Unload Me
End Sub

Sub Merge(N As Integer, ByRef A() As Integer, ini As Integer, med As Integer, fin As Integer)
Dim n1 As Integer
n1 = med - ini + 1
Dim n2 As Integer
n2 = fin - med
ReDim L(n1 + 1) As Integer
ReDim R(n2 + 1) As Integer
For z = 1 To n1
L(z) = A(ini + z - 1)
Next
For z = 1 To n2
R(z) = A(med + z)
Next
L(n1 + 1) = 32767
R(n2 + 1) = 32767
Dim i As Integer
Dim j As Integer
i = 1
j = 1
For k = ini To fin
If L(i) <= R(j) Then
Ordenamiento por mezcla 7

A(k) = L(i)
i = i + 1
ElseIf L(i) > R(j) Then
A(k) = R(j)
j = j + 1
End If
Next
End Sub

Sub MergeSort(N As Integer, ByRef A() As Integer, inicio As Integer, fin As Integer)
If inicio < fin Then
Dim medio As Integer
medio = (inicio + fin) \ 2
MergeSort N, A, inicio, medio
MergeSort N, A, medio + 1, fin
Merge N, A, inicio, medio, fin
End If
End Sub

Java
public class MergeSort{
private int A[];
public int[] OrdenaMerge(int[] L) {
int n = L.length;

if (n > 1){
int m = (int) (Math.ceil(n/2.0));
int [] L1 = new int[m];
int [] L2 = new int[n-m];

for (int i = 0; i < m; i++){


L1[i] = L[i];
}
for (int i = m; i < n; i++){
L2[i-m] = L[i];
}
L = merge(OrdenaMerge(L1), OrdenaMerge(L2));
}
return L;
}

public int[] eliminar(int [] l){


int [] L = new int[l.length-1];
for(int i = 1; i < l.length; i++){
L[i-1] = l[i];
}
return L;
Ordenamiento por mezcla 8

public int[] merge(int[] L1, int[] L2) {


int[] L = new int[L1.length+L2.length];
int i = 0;
while ((L1.length != 0) && (L2.length != 0)) {
if (L1[0] < L2[0]){
L[i++] = L1[0];
L1 = eliminar(L1);
if (L1.length == 0){
while (L2.length != 0) {
L[i++] = L2[0];
L2 = eliminar(L2);
}
}
}
else{
L[i++] = L2[0];
L2 = eliminar(L2);
if (L2.length == 0) {
while (L1.length != 0) {
L[i++] = L1[0];
L1 = eliminar(L1);
}
}
}
}
return L;
}

public void generarNumeros(){


Random ran = new Random();
int x;
for(int i = 0; i < A.length; i++){
x = (int)(ran.nextDouble()*10000);
A[i] = x;
}
}

public void imprimir(){


for(int i = 0; i < A.length; i++){
System.out.println(A[i]);
}
}

public int[] getA(){


return A;
Ordenamiento por mezcla 9

public void setA(int []A){


this.A = A;
}
}

C Sharp
public static class Algoritmos<T>

public static List<T> MergeSort(List<T> lista)

if (lista.Count > 1)

List<T> lista1 = new List<T>();

List<T> lista2 = new List<T>();

for (int i = 0; i < lista.Count; i++)

if (i < (lista.Count / 2))

lista1.Add(lista[i]);

else

lista2.Add(lista[i]);

lista1 = MergeSort(lista1);

lista2 = MergeSort(lista2);

return Merge(lista1, lista2);

else

return lista;

private static List<T> Merge(List<T> lista1, List<T> lista2)

List<T> listaSalida = new List<T>();

int p1 = 0, p2 = 0, n1 = (lista1.Count - 1), n2 =

(lista2.Count - 1);

while (p1 <= n1 || p2 <= n2)

if ((lista2.Count == p2) || (p1 <= n1 && string.Compare(lista1[p1].ToString(), lista2[p2].ToString()) <= 0))

listaSalida.Add(lista1[p1]);
Ordenamiento por mezcla 10

p1++;

else

if ((lista1.Count == p1) || (p2 <= n2 && string.Compare(lista1[p1].ToString(), lista2[p2].ToString()) > 0))

listaSalida.Add(lista2[p2]);

p2++;

return listaSalida;

Prolog
mergesort([],[]). %caso base
mergesort([X],[X]). %caso base
mergesort(XS,YS):-
divide(XS,LS,MS), %divido
mergesort(LS,KS), %ordeno una parte
mergesort(MS,NS), %ordeno la otra parte
mezcla(KS,NS,YS). %mezclo

coge(1,1,[X|_],[X]).
coge(N,M,[_|XS],NS):- %avanzo a la posicion
N>1,
L is N-1,
D is M-1,
coge(L,D,XS,NS).

coge(N,M,[X|XS],NS):- %cojo el elemento


N==1,
L is M-1,
coge(N,L,XS,PS),
concatena([X],PS,NS).

divide([X],[X],[]).
divide(XS,YS,ZS):-
longitud(XS,P),
L is P//2,
L1 is L+1,
coge(1,L,XS,YS),
coge(L1,P,XS,ZS).

mezcla(XS,[],XS).
Ordenamiento por mezcla 11

mezcla([],XS,XS).
mezcla([X|XS],[Y|YS],[X|ZS]):-
X<Y,
mezcla(XS,[Y|YS],ZS).
mezcla([X|XS],[Y|YS],[Y|ZS]):-
X>=Y,
mezcla([X|XS],YS,ZS).

longitud([],0).
longitud([_|Cola],N):-longitud(Cola,N1),N is N1+1.

Python
def mergeSort (numbers):
def merge (first, second):
mergedList = []

while len(first) > 0 and len(second) > 0:


if (first[0] < second[0]):
mergedList.append(first.pop(0))

else:
mergedList.append(second.pop(0))

mergedList += first
mergedList += second

return mergedList

if (len(numbers) == 1): return numbers

middle = len(numbers) // 2

first = mergeSort(numbers[0:middle])
second = mergeSort(numbers[middle:])

return merge(first, second)

Optimizando merge sort


En los ordenadores modernos, el principio de localidad puede ser primordial en la optimización de software, porque
se usan jerarquías de memoria multi-nivel. Se han propuesto versiones de cache-consciente del algoritmo de
ordenación por mezcla, cuyas operaciones han sido específicamente escogidas para minimizar el movimiento de
entrada y salida de páginas de la memoria caché de la máquina. Por ejemplo, el algorimo "tiled merge sort" deja de
particionar subarrays cuando se han alcanzado subarrays de tamaño S, donde S es el número de elementos que caben
en una única página en memoria. Cada uno de esos subarrays se ordenan con un algorimo de ordenación in-situ, para
evitar intercambios en memoria, y entonces se termina con el algoritmo de ordenamiento por mezcla en su versión
Ordenamiento por mezcla 12

recursiva estándar. Este algoritmo ha demostrado un mejor rendimiento en máquinas que se benefician de la
optimización caché.
M.A. Kronrod sugirió en 1969 una versión alternativa del algoritmo de ordenamiento por mezcla que usaba espacio
adicional constante. Este algoritmo fue refinado por Katajainen, Pasanen y Teuhola.

Comparación con otros algoritmos de ordenamiento


Aunque heapsort tiene los mismos límites de tiempo que merge sort, requiere sólo Θ(1) espacio auxiliar en lugar del
Θ(n) de merge sort, y es a menudo más rápido en implementaciones prácticas. Quicksort, sin embargo, es
considerado por mucho como el más rápido algoritmo de ordenamiento de propósito general. En el lado bueno,
merge sort es un ordenamiento estable, paraleliza mejor, y es más eficiente manejando medios secuenciales de
acceso lento. Merge sort es a menudo la mejor opción para ordenar una lista enlazada: en esta situación es
relativamente fácil implementar merge sort de manera que sólo requiera Θ(1) espacio extra, y el mal rendimiento de
las listas enlazadas ante el acceso aleatorio hace que otros algoritmos (como quicksort) den un bajo rendimiento, y
para otros (como heapsort) sea algo imposible.
Para Perl 5.8, merge sort es el algoritmo de ordenamiento por defecto (lo era quicksort en versiones anteriores de
Perl). En Java los métodos de ordenación de Arrays usan merge sort o una modificación de quicksort dependiendo de
los tipos de datos y por cuestiones de eficiencia cambian a ordenamiento por inserción cuando se están ordenando
menos de siete elementos en el array.

Enlaces externos

Implementaciones
• Sort::Merge [1] Módulo Perl en CPAN
• File::MergeSort [2] Módulo Perl en CPAN

Referencias
[1] http:/ / search. cpan. org/ perldoc?Sort::Merge
[2] http:/ / search. cpan. org/ perldoc?File::MergeSort
Fuentes y contribuyentes del artículo 13

Fuentes y contribuyentes del artículo


Ordenamiento por mezcla  Fuente: http://es.wikipedia.org/w/index.php?oldid=69613598  Contribuyentes: Aeveraal, Aliamondano, Ascánder, Biasoli, Damnerpalacios, Dem, Diegusjaimes,
Emferr, Grillitus, Halfdrag, Jacobo Tarrio, JoaquinFerrero, JulGor, Kelwin, Macro.masek, Muro de Aguas, Paulopin, Ricardogpn, Riemann'sZeta, STANHMAL, Savh, Shekatsu8er, Shooke,
UA31, V!rus, Xykatra, 73 ediciones anónimas

Fuentes de imagen, Licencias y contribuyentes


File:Merge-sort-example-300px.gif  Fuente: http://es.wikipedia.org/w/index.php?title=Archivo:Merge-sort-example-300px.gif  Licencia: Creative Commons Attribution-Sharealike 3.0
 Contribuyentes: Swfung8

Licencia
Creative Commons Attribution-Share Alike 3.0
//creativecommons.org/licenses/by-sa/3.0/

También podría gustarte