Merge Sort with O(1) extra space merge and O(n lg n) time [Solo enteros sin signo]

Hemos hablado de Merge sort . Cómo modificar el algoritmo para que la fusión funcione en O(1) espacio extra y el algoritmo aún funcione en O(n Log n) tiempo. Podemos suponer que los valores de entrada son solo números enteros.

Ejemplos: 

Input : 5 4 3 2 1
Output : 1 2 3 4 5

Input : 999 612 589 856 56 945 243
Output : 56 243 589 612 856 945 999

Para los tipos enteros, la ordenación por combinación se puede hacer en el lugar usando algún truco matemático de módulo y división. Eso significa almacenar el valor de dos elementos en un índice y se puede extraer usando el módulo y la división. 

Primero tenemos que encontrar un valor mayor que todos los elementos de la array. Ahora podemos almacenar el valor original como módulo y el segundo valor como división. Supongamos que queremos almacenar arr[i] y arr[j] en el índice i (significa en arr[i]). Primero tenemos que encontrar un ‘maxval’ mayor que arr[i] y arr[j]. Ahora podemos almacenar como arr[i] = arr[i] + arr[j]*maxval . Ahora arr[i]%maxval dará el valor original de arr[i] y arr[i]/maxval dará el valor de arr[j]. Entonces, a continuación se muestra la implementación en el ordenamiento por fusión.

Enfoque: (División Euclidiana)

                                           dividendo = divisor * cociente + resto

ej: 5/3 = q:1, r:2 aplicando euclidiana: 3*1+2 =>5 (dividendo)

divisor = maxele (elemento máximo absoluto en la array) + 1 (para que siempre obtengamos un resto distinto de cero)
cociente = min (primero, segundo)
resto = elemento original

Nota: (al obtener el elemento actual, suponga que el contenedor actual ya tiene un elemento codificado, por lo tanto, use % divisor)
primero = arr[i] % divisor
segundo = arr[j] % divisor 

elemento codificado = resto + cociente*divisor

Posibles problemas en la fusión:

1. Si el número actual es Integer.MAX, entonces el nuevo valor codificado, que generalmente es mayor que el elemento actual, causará un desbordamiento de números enteros y corrupción de datos (en python no hay límite para el tamaño del número, por lo que este problema no ocurrirá).

2. No maneja números negativos (es decir, al codificar un número -ve (actual) con otro número -ve (elegido más pequeño) el signo no se puede conservar ya que ambos números tienen el signo -ve. También se deben usar valores absolutos cuando se calcula dividendo = divisor*cociente+resto (divisor = maxele, cociente = menor, resto = original) y se debe restaurar el signo, es posible que no funcione debido a un problema de conservación del signo.

3. Solo aplicable a números enteros sin signo, como índices que normalmente no son negativos.

4. AUX = O(n) en el peor de los casos, asumiendo que en un lenguaje como python donde no hay límite para el tamaño de palabra/entero, cuando los elementos de la array de entrada están casi en Integer.MAX, entonces el valor codificado requerirá posiblemente un espacio de 2x bits para representan un nuevo número, el espacio de bits 2x en total puede convertirse en un tamaño de array +1x, que es casi como crear una array AUX pero de forma indirecta.

5. Las operaciones de modificación y división son las más costosas, por lo que reducen el rendimiento general (hasta cierto punto).

C++

// C++ program to sort an array using merge sort such
// that merge operation takes O(1) extra space.
#include <bits/stdc++.h>
using namespace std;
void merge(int arr[], int beg, int mid, int end, int maxele)
{
    int i = beg;
    int j = mid + 1;
    int k = beg;
    while (i <= mid && j <= end) {
        if (arr[i] % maxele <= arr[j] % maxele) {
            arr[k] = arr[k] + (arr[i] % maxele) * maxele;
            k++;
            i++;
        }
        else {
            arr[k] = arr[k] + (arr[j] % maxele) * maxele;
            k++;
            j++;
        }
    }
    while (i <= mid) {
        arr[k] = arr[k] + (arr[i] % maxele) * maxele;
        k++;
        i++;
    }
    while (j <= end) {
        arr[k] = arr[k] + (arr[j] % maxele) * maxele;
        k++;
        j++;
    }
 
    // Obtaining actual values
    for (int i = beg; i <= end; i++)
        arr[i] = arr[i] / maxele;
}
 
// Recursive merge sort with extra parameter, naxele
void mergeSortRec(int arr[], int beg, int end, int maxele)
{
    if (beg < end) {
        int mid = (beg + end) / 2;
        mergeSortRec(arr, beg, mid, maxele);
        mergeSortRec(arr, mid + 1, end, maxele);
        merge(arr, beg, mid, end, maxele);
    }
}
 
// This functions finds max element and calls recursive
// merge sort.
void mergeSort(int arr[], int n)
{
   int maxele = *max_element(arr, arr+n) + 1;
   mergeSortRec(arr, 0, n-1, maxele);
}
 
int main()
{
    int arr[] = { 999, 612, 589, 856, 56, 945, 243 };
    int n = sizeof(arr) / sizeof(arr[0]);
     
    mergeSort(arr, n);
 
    cout << "Sorted array \n";
    for (int i = 0; i < n; i++)
        cout << arr[i] << " ";
    return 0;
}

Java

// Java program to sort an array
// using merge sort such that
// merge operation takes O(1)
// extra space.
import java.util.Arrays;
 
class GFG
{
 
    static void merge(int[] arr, int beg,
                        int mid, int end,
                        int maxele)
    {
        int i = beg;
        int j = mid + 1;
        int k = beg;
        while (i <= mid && j <= end)
        {
            if (arr[i] % maxele <=
                arr[j] % maxele)
            {
                arr[k] = arr[k] + (arr[i]
                        % maxele) * maxele;
                k++;
                i++;
            }
            else
            {
                arr[k] = arr[k] +
                        (arr[j] % maxele)
                        * maxele;
                k++;
                j++;
            }
        }
        while (i <= mid)
        {
            arr[k] = arr[k] + (arr[i]
                    % maxele) * maxele;
            k++;
            i++;
        }
        while (j <= end)
        {
            arr[k] = arr[k] + (arr[j]
                    % maxele) * maxele;
            k++;
            j++;
        }
 
        // Obtaining actual values
        for (i = beg; i <= end; i++)
        {
            arr[i] = arr[i] / maxele;
        }
    }
 
    // Recursive merge sort
    // with extra parameter, naxele
    static void mergeSortRec(int[] arr, int beg,
            int end, int maxele)
    {
        if (beg < end)
        {
            int mid = (beg + end) / 2;
            mergeSortRec(arr, beg,
                        mid, maxele);
            mergeSortRec(arr, mid + 1,
                        end, maxele);
            merge(arr, beg, mid,
                    end, maxele);
        }
    }
 
    // This functions finds
    // max element and calls
    // recursive merge sort.
    static void mergeSort(int[] arr, int n)
    {
        int maxele = Arrays.stream(arr).max().getAsInt() + 1;
        mergeSortRec(arr, 0, n - 1, maxele);
    }
 
    // Driver code
    public static void main(String[] args)
    {
 
        int[] arr = {999, 612, 589,
                    856, 56, 945, 243};
        int n = arr.length;
 
        mergeSort(arr, n);
 
        System.out.println("Sorted array ");
        for (int i = 0; i < n; i++)
        {
            System.out.print(arr[i] + " ");
        }
    }
}
 
// This code is contributed by 29AjayKumar

Python3

# Python3 program to sort an array using
# merge sort such that merge operation
# takes O(1) extra space.
def merge(arr, beg, mid, end, maxele):
     
    i = beg
    j = mid + 1
    k = beg
     
    while (i <= mid and j <= end):
        if (arr[i] % maxele <= arr[j] % maxele):
            arr[k] = arr[k] + (arr[i] %
                    maxele) * maxele
            k += 1
            i += 1
        else:
            arr[k] = arr[k] + (arr[j] %
                    maxele) * maxele
            k += 1
            j += 1
             
    while (i <= mid):
        arr[k] = arr[k] + (arr[i] %
                maxele) * maxele
        k += 1
        i += 1
    while (j <= end):
        arr[k] = arr[k] + (arr[j] %
                maxele) * maxele
        k += 1
        j += 1
 
    # Obtaining actual values
    for i in range(beg, end + 1):
        arr[i] = arr[i] // maxele
 
# Recursive merge sort with extra
# parameter, naxele
def mergeSortRec(arr, beg, end, maxele):
     
    if (beg < end):
        mid = (beg + end) // 2
        mergeSortRec(arr, beg, mid, maxele)
        mergeSortRec(arr, mid + 1, end, maxele)
        merge(arr, beg, mid, end, maxele)
 
# This functions finds max element and
# calls recursive merge sort.
def mergeSort(arr, n):
     
   maxele = max(arr) + 1
   mergeSortRec(arr, 0, n - 1, maxele)
 
# Driver Code
if __name__ == '__main__':
 
    arr = [ 999, 612, 589, 856, 56, 945, 243 ]
    n =  len(arr)
    mergeSort(arr, n)
 
    print("Sorted array")
     
    for i in range(n):
        print(arr[i], end = " ")
 
# This code is contributed by mohit kumar 29

C#

// C# program to sort an array
// using merge sort such that
// merge operation takes O(1)
// extra space.
using System;
using System.Linq;
 
class GFG
{
static void merge(int []arr, int beg,
                  int mid, int end,
                  int maxele)
{
    int i = beg;
    int j = mid + 1;
    int k = beg;
    while (i <= mid && j <= end)
    {
        if (arr[i] %
            maxele <= arr[j] % maxele)
        {
            arr[k] = arr[k] + (arr[i] %
                     maxele) * maxele;
            k++;
            i++;
        }
        else
        {
            arr[k] = arr[k] +
                    (arr[j] % maxele) *
                              maxele;
            k++;
            j++;
        }
    }
    while (i <= mid)
    {
        arr[k] = arr[k] + (arr[i] %
                 maxele) * maxele;
        k++;
        i++;
    }
    while (j <= end)
    {
        arr[k] = arr[k] + (arr[j] %
                 maxele) * maxele;
        k++;
        j++;
    }
 
    // Obtaining actual values
    for ( i = beg; i <= end; i++)
        arr[i] = arr[i] / maxele;
}
 
// Recursive merge sort
// with extra parameter, naxele
static void mergeSortRec(int []arr, int beg,
                         int end, int maxele)
{
    if (beg < end)
    {
        int mid = (beg + end) / 2;
        mergeSortRec(arr, beg,
                     mid, maxele);
        mergeSortRec(arr, mid + 1,
                     end, maxele);
        merge(arr, beg, mid,
              end, maxele);
    }
}
 
// This functions finds
// max element and calls
// recursive merge sort.
static void mergeSort(int []arr, int n)
{
    int maxele = arr.Max() + 1;
    mergeSortRec(arr, 0, n - 1, maxele);
}
 
//Driver code
public static void Main ()
{
    int []arr = {999, 612, 589,
                 856, 56, 945, 243};
    int n = arr.Length;
 
    mergeSort(arr, n);
 
    Console.WriteLine("Sorted array ");
    for (int i = 0; i < n; i++)
        Console.Write( arr[i] + " ");
}
}
 
// This code is contributed
// by inder_verma.

Javascript

<script>
// Javascript program to sort an array
// using merge sort such that
// merge operation takes O(1)
// extra space.   
     
    function merge(arr,beg,mid,end,maxele)
    {
        let i = beg;
        let j = mid + 1;
        let k = beg;
        while (i <= mid && j <= end)
        {
            if (arr[i] % maxele <=
                arr[j] % maxele)
            {
                arr[k] = arr[k] + (arr[i]
                        % maxele) * maxele;
                k++;
                i++;
            }
            else
            {
                arr[k] = arr[k] +
                        (arr[j] % maxele)
                        * maxele;
                k++;
                j++;
            }
        }
        while (i <= mid)
        {
            arr[k] = arr[k] + (arr[i]
                    % maxele) * maxele;
            k++;
            i++;
        }
        while (j <= end)
        {
            arr[k] = arr[k] + (arr[j]
                    % maxele) * maxele;
            k++;
            j++;
        }
  
        // Obtaining actual values
        for (i = beg; i <= end; i++)
        {
            arr[i] = Math.floor(arr[i] / maxele);
        }
    }
     
    // Recursive merge sort
    // with extra parameter, naxele
    function mergeSortRec(arr,beg,end,maxele)
    {
        if (beg < end)
        {
            let mid = Math.floor((beg + end) / 2);
            mergeSortRec(arr, beg,
                        mid, maxele);
            mergeSortRec(arr, mid + 1,
                        end, maxele);
            merge(arr, beg, mid,
                    end, maxele);
        }
    }
     
    // This functions finds
    // max element and calls
    // recursive merge sort.
    function  mergeSort(arr,n)
    {
        let maxele = Math.max(...arr) + 1;
        mergeSortRec(arr, 0, n - 1, maxele);
     
    }
     
    // Driver code
    let arr=[999, 612, 589,
                    856, 56, 945, 243];
                     
    let n = arr.length;
    mergeSort(arr, n);
     
    document.write("Sorted array <br>");
    for (let i = 0; i < n; i++)
        {
            document.write(arr[i] + " ");
        }
     
// This code is contributed by patel2127
</script>
Producción: 

Sorted array 
56 243 589 612 856 945 999

 

Publicación traducida automáticamente

Artículo escrito por Ankesh Kumar y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *