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 < [Link](); ++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 = [Link];
if (n > 1){
int m = (int) ([Link](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[[Link]-1];
for(int i = 1; i < [Link]; i++){
L[i-1] = l[i];
}
return L;
Ordenamiento por mezcla 8
public int[] merge(int[] L1, int[] L2) {
int[] L = new int[[Link]+[Link]];
int i = 0;
while (([Link] != 0) && ([Link] != 0)) {
if (L1[0] < L2[0]){
L[i++] = L1[0];
L1 = eliminar(L1);
if ([Link] == 0){
while ([Link] != 0) {
L[i++] = L2[0];
L2 = eliminar(L2);
}
}
}
else{
L[i++] = L2[0];
L2 = eliminar(L2);
if ([Link] == 0) {
while ([Link] != 0) {
L[i++] = L1[0];
L1 = eliminar(L1);
}
}
}
}
return L;
}
public void generarNumeros(){
Random ran = new Random();
int x;
for(int i = 0; i < [Link]; i++){
x = (int)([Link]()*10000);
A[i] = x;
}
}
public void imprimir(){
for(int i = 0; i < [Link]; i++){
[Link](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 ([Link] > 1)
List<T> lista1 = new List<T>();
List<T> lista2 = new List<T>();
for (int i = 0; i < [Link]; i++)
if (i < ([Link] / 2))
[Link](lista[i]);
else
[Link](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 = ([Link] - 1), n2 =
([Link] - 1);
while (p1 <= n1 || p2 <= n2)
if (([Link] == p2) || (p1 <= n1 && [Link](lista1[p1].ToString(), lista2[p2].ToString()) <= 0))
[Link](lista1[p1]);
Ordenamiento por mezcla 10
p1++;
else
if (([Link] == p1) || (p2 <= n2 && [Link](lista1[p1].ToString(), lista2[p2].ToString()) > 0))
[Link](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]):
[Link]([Link](0))
else:
[Link]([Link](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: [Link] Contribuyentes: Aeveraal, Aliamondano, Ascánder, Biasoli, Damnerpalacios, Dem, Diegusjaimes,
Emferr, Grillitus, Halfdrag, Jacobo Tarrio, JoaquinFerrero, JulGor, Kelwin, [Link], 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:[Link] Fuente: [Link] Licencia: Creative Commons Attribution-Sharealike 3.0
Contribuyentes: Swfung8
Licencia
Creative Commons Attribution-Share Alike 3.0
//[Link]/licenses/by-sa/3.0/