Mediana en una secuencia de enteros (enteros en ejecución)

Dado que los enteros se leen de un flujo de datos. Encuentre la mediana de los elementos leídos de manera eficiente. Por simplicidad, suponga que no hay duplicados. Por ejemplo, consideremos la corriente 5, 15, 1, 3… 
 

After reading 1st element of stream - 5 -> median - 5
After reading 2nd element of stream - 5, 15 -> median - 10
After reading 3rd element of stream - 5, 15, 1 -> median - 5
After reading 4th element of stream - 5, 15, 1, 3 -> median - 4, so on...

Para dejarlo claro, cuando el tamaño de entrada es impar, tomamos el elemento medio de los datos ordenados. Si el tamaño de entrada es par, seleccionamos el promedio de los dos elementos del medio en el flujo ordenado.
Tenga en cuenta que la salida es la mediana efectiva de los enteros leídos del flujo hasta el momento. Tal algoritmo se llama algoritmo en línea. Cualquier algoritmo que pueda garantizar la salida de i -elementos después de procesar i -ésimo elemento, se dice que es un algoritmo en línea . Analicemos tres soluciones al problema anterior.

Método 1: ordenación por inserción

Si podemos ordenar los datos tal como aparecen, podemos ubicar fácilmente el elemento mediano. Insertion Sort es uno de esos algoritmos en línea que ordena los datos aparecidos hasta ahora. En cualquier instancia de clasificación, por ejemplo, después de clasificar el i -ésimo elemento, se clasifican los primeros i elementos de la array. La ordenación por inserción no depende de datos futuros para ordenar la entrada de datos hasta ese punto. En otras palabras, la ordenación por inserción considera los datos ordenados hasta el momento al insertar el siguiente elemento. Esta es la parte clave del ordenamiento por inserción que lo convierte en un algoritmo en línea.

Sin embargo, la ordenación por inserción toma O(n 2 ) tiempo para ordenar n elementos. Tal vez podamos usar  la búsqueda binaria en la ordenación por inserción para encontrar la ubicación del siguiente elemento en el tiempo O (log n). Sin embargo, no podemos hacer el movimiento de datos en el tiempo O (log n). No importa qué tan eficiente sea la implementación, toma tiempo polinomial en caso de ordenación por inserción.
Los lectores interesados ​​pueden probar la implementación del Método 1.

C++

// This code is contributed by Anjali Saxena
 
#include <bits/stdc++.h>
 
using namespace std;
 
// Function to find position to insert current element of
// stream using binary search
int binarySearch(int arr[], int item, int low, int high)
{
    if (low >= high) {
        return (item > arr[low]) ? (low + 1) : low;
    }
 
    int mid = (low + high) / 2;
 
    if (item == arr[mid])
        return mid + 1;
 
    if (item > arr[mid])
        return binarySearch(arr, item, mid + 1, high);
 
    return binarySearch(arr, item, low, mid - 1);
}
 
// Function to print median of stream of integers
void printMedian(int arr[], int n)
{
    int i, j, pos, num;
    int count = 1;
 
    cout << "Median after reading 1"
         << " element is " << arr[0] << "\n";
 
    for (i = 1; i < n; i++) {
        float median;
        j = i - 1;
        num = arr[i];
 
        // find position to insert current element in sorted
        // part of array
        pos = binarySearch(arr, num, 0, j);
 
        // move elements to right to create space to insert
        // the current element
        while (j >= pos) {
            arr[j + 1] = arr[j];
            j--;
        }
 
        arr[j + 1] = num;
 
        // increment count of sorted elements in array
        count++;
 
        // if odd number of integers are read from stream
        // then middle element in sorted order is median
        // else average of middle elements is median
        if (count % 2 != 0) {
            median = arr[count / 2];
        }
        else {
            median = (arr[(count / 2) - 1] + arr[count / 2])
                     / 2;
        }
 
        cout << "Median after reading " << i + 1
             << " elements is " << median << "\n";
    }
}
 
// Driver Code
int main()
{
    int arr[] = { 5, 15, 1, 3, 2, 8, 7, 9, 10, 6, 11, 4 };
    int n = sizeof(arr) / sizeof(arr[0]);
 
    printMedian(arr, n);
 
    return 0;
}

Java

// Java code to implement the approach
import java.util.*;
 
class GFG {
 
  // Function to find position to insert current element of
  // stream using binary search
  static int binarySearch(int arr[], int item, int low, int high)
  {
    if (low >= high) {
      return (item > arr[low]) ? (low + 1) : low;
    }
 
    int mid = (low + high) / 2;
 
    if (item == arr[mid])
      return mid + 1;
 
    if (item > arr[mid])
      return binarySearch(arr, item, mid + 1, high);
 
    return binarySearch(arr, item, low, mid - 1);
  }
 
  // Function to print median of stream of integers
  static void printMedian(int arr[], int n)
  {
    int i, j, pos, num;
    int count = 1;
 
    System.out.println( "Median after reading 1"
                       + " element is " + arr[0]);
 
    for (i = 1; i < n; i++) {
      float median;
      j = i - 1;
      num = arr[i];
 
      // find position to insert current element in sorted
      // part of array
      pos = binarySearch(arr, num, 0, j);
 
      // move elements to right to create space to insert
      // the current element
      while (j >= pos) {
        arr[j + 1] = arr[j];
        j--;
      }
 
      arr[j + 1] = num;
 
      // increment count of sorted elements in array
      count++;
 
      // if odd number of integers are read from stream
      // then middle element in sorted order is median
      // else average of middle elements is median
      if (count % 2 != 0) {
        median = arr[count / 2];
      }
      else {
        median = (arr[(count / 2) - 1] + arr[count / 2])
          / 2;
      }
 
      System.out.println( "Median after reading " + (i + 1)
                         + " elements is " + (int)median );
    }
  }
 
 
  // Driver code
  public static void main (String[] args) {
 
    int arr[] = { 5, 15, 1, 3, 2, 8, 7, 9, 10, 6, 11, 4 };
    int n = arr.length;
 
    printMedian(arr, n);
  }
}
 
// This code is contributed by sanjoy_62.

Python3

# Function to find position to insert current element of
# stream using binary search
def binarySearch(arr, item, low, high):
 
    if (low >= high):
        return (low + 1) if (item > arr[low]) else low
 
    mid = (low + high) // 2
 
    if (item == arr[mid]):
        return mid + 1
 
    if (item > arr[mid]):
        return binarySearch(arr, item, mid + 1, high)
 
    return binarySearch(arr, item, low, mid - 1)
 
# Function to print median of stream of integers
def printMedian(arr, n):
 
    i, j, pos, num = 0, 0, 0, 0
    count = 1
 
    print(f"Median after reading 1 element is {arr[0]}")
 
    for i in range(1, n):
        median = 0
        j = i - 1
        num = arr[i]
 
        # find position to insert current element in sorted
        # part of array
        pos = binarySearch(arr, num, 0, j)
 
        # move elements to right to create space to insert
        # the current element
        while (j >= pos):
            arr[j + 1] = arr[j]
            j -= 1
 
        arr[j + 1] = num
 
        # increment count of sorted elements in array
        count += 1
 
        # if odd number of integers are read from stream
        # then middle element in sorted order is median
        # else average of middle elements is median
        if (count % 2 != 0):
            median = arr[count // 2]
 
        else:
            median = (arr[(count // 2) - 1] + arr[count // 2]) // 2
 
        print(f"Median after reading {i + 1} elements is {median} ")
 
# Driver Code
if __name__ == "__main__":
 
    arr = [5, 15, 1, 3, 2, 8, 7, 9, 10, 6, 11, 4]
    n = len(arr)
 
    printMedian(arr, n)
 
# This code is contributed by rakeshsahni

C#

// C# program for the above approach
using System;
class GFG{
 
  // Function to find position to insert current element of
  // stream using binary search
  static int binarySearch(int[] arr, int item, int low, int high)
  {
    if (low >= high) {
      return (item > arr[low]) ? (low + 1) : low;
    }
 
    int mid = (low + high) / 2;
 
    if (item == arr[mid])
      return mid + 1;
 
    if (item > arr[mid])
      return binarySearch(arr, item, mid + 1, high);
 
    return binarySearch(arr, item, low, mid - 1);
  }
 
  // Function to print median of stream of integers
  static void printMedian(int[] arr, int n)
  {
    int i, j, pos, num;
    int count = 1;
 
    Console.WriteLine( "Median after reading 1"
                       + " element is " + arr[0]);
 
    for (i = 1; i < n; i++) {
      float median;
      j = i - 1;
      num = arr[i];
 
      // find position to insert current element in sorted
      // part of array
      pos = binarySearch(arr, num, 0, j);
 
      // move elements to right to create space to insert
      // the current element
      while (j >= pos) {
        arr[j + 1] = arr[j];
        j--;
      }
 
      arr[j + 1] = num;
 
      // increment count of sorted elements in array
      count++;
 
      // if odd number of integers are read from stream
      // then middle element in sorted order is median
      // else average of middle elements is median
      if (count % 2 != 0) {
        median = arr[count / 2];
      }
      else {
        median = (arr[(count / 2) - 1] + arr[count / 2])
          / 2;
      }
 
      Console.WriteLine( "Median after reading " + (i + 1)
                         + " elements is " + (int)median );
    }
  }
 
 
// Driver Code
public static void Main(String[] args)
{
    int[] arr = { 5, 15, 1, 3, 2, 8, 7, 9, 10, 6, 11, 4 };
    int n = arr.Length;
 
    printMedian(arr, n);
}
}
 
// This code is contributed by code_hunt.

Javascript

<script>
    // JavaScript implementation for the above approach
 
    // Function to find position to insert current element of
    // stream using binary search
    const binarySearch = (arr, item, low, high) => {
        if (low >= high) {
            return (item > arr[low]) ? (low + 1) : low;
        }
 
        let mid = parseInt((low + high) / 2);
 
        if (item == arr[mid])
            return mid + 1;
 
        if (item > arr[mid])
            return binarySearch(arr, item, mid + 1, high);
 
        return binarySearch(arr, item, low, mid - 1);
    }
 
    // Function to print median of stream of integers
    const printMedian = (arr, n) => {
        let i, j, pos, num;
        let count = 1;
 
        document.write(`Median after reading 1 element is ${arr[0]}<br/>`);
 
        for (i = 1; i < n; i++) {
            let median;
            j = i - 1;
            num = arr[i];
 
            // find position to insert current element in sorted
            // part of array
            pos = binarySearch(arr, num, 0, j);
 
            // move elements to right to create space to insert
            // the current element
            while (j >= pos) {
                arr[j + 1] = arr[j];
                j--;
            }
 
            arr[j + 1] = num;
 
            // increment count of sorted elements in array
            count++;
 
            // if odd number of integers are read from stream
            // then middle element in sorted order is median
            // else average of middle elements is median
            if (count % 2 != 0) {
                median = arr[parseInt(count / 2)];
            }
            else {
                median = parseInt((arr[parseInt(count / 2) - 1] + arr[parseInt(count / 2)]) / 2);
            }
 
            document.write(`Median after reading ${i + 1} elements is ${median}<br/>`);
        }
    }
 
    // Driver Code
    let arr = [5, 15, 1, 3, 2, 8, 7, 9, 10, 6, 11, 4];
    let n = arr.length;
 
    printMedian(arr, n);
 
 // This code is contributed by rakeshsahni
 
</script>
Producción

Median after reading 1 element is 5
Median after reading 2 elements is 10
Median after reading 3 elements is 5
Median after reading 4 elements is 4
Median after reading 5 elements is 3
Median after reading 6 elements is 4
Median after reading 7 elements is 5
Median after reading 8 elements is 6
Median after reading 9 elements is 7
Median after reading 10 elements is 6
Median after reading 11 elements is 7
Median after reading 12 elements is 6

Complejidad de Tiempo: O(n 2 )
Complejidad de Espacio: O(1)

Método 2:  árbol de búsqueda binario autoequilibrado aumentado (AVL, RB, etc.)
En cada Node de BST, mantenga una cantidad de elementos en el subárbol con raíz en ese Node. Podemos usar un Node como la raíz de un árbol binario simple, cuyo hijo izquierdo es BST autoequilibrado con elementos menores que root y cuyo hijo derecho es BST autoequilibrado con elementos mayores que root. El elemento raíz siempre tiene una mediana efectiva .

Si los subárboles izquierdo y derecho contienen el mismo número de elementos, el Node raíz contiene el promedio de los datos raíz del subárbol izquierdo y derecho. De lo contrario, la raíz contiene los mismos datos que la raíz del subárbol que tiene más elementos. Después de procesar un elemento entrante, los subárboles izquierdo y derecho (BST) difieren al máximo en 1.

El BST autoequilibrado es costoso en la gestión del factor de equilibrio del BST. Sin embargo, proporcionan datos ordenados que no necesitamos. Solo necesitamos la mediana. El siguiente método utiliza Heaps para rastrear la mediana.

Método 3:  montones De manera
similar al equilibrio de BST en el método 2 anterior, podemos usar un montón máximo en el lado izquierdo para representar elementos que son menos que efectivos mediana y un montón mínimo en el lado derecho para representar elementos que son mayores que efectivos mediana _

Después de procesar un elemento entrante, la cantidad de elementos en los montones difiere como máximo en 1 elemento. Cuando ambos montones contienen la misma cantidad de elementos, seleccionamos el promedio de los datos raíz de los montones como mediana efectiva . Cuando los montones no están equilibrados, seleccionamos la mediana efectiva de la raíz del montón que contiene más elementos.

A continuación se muestra la implementación del método anterior. Para que el algoritmo construya estos montones, lea el código resaltado.

C

#include <iostream>
using namespace std;
 
// Heap capacity
#define MAX_HEAP_SIZE (128)
#define ARRAY_SIZE(a) sizeof(a)/sizeof(a[0])
 
//// Utility functions
 
// exchange a and b
inline
void Exch(int &a, int &b)
{
    int aux = a;
    a = b;
    b = aux;
}
 
// Greater and Smaller are used as comparators
bool Greater(int a, int b)
{
    return a > b;
}
 
bool Smaller(int a, int b)
{
    return a < b;
}
 
int Average(int a, int b)
{
    return (a + b) / 2;
}
 
// Signum function
// = 0  if a == b  - heaps are balanced
// = -1 if a < b   - left contains less elements than right
// = 1  if a > b   - left contains more elements than right
int Signum(int a, int b)
{
    if( a == b )
        return 0;
 
    return a < b ? -1 : 1;
}
 
// Heap implementation
// The functionality is embedded into
// Heap abstract class to avoid code duplication
class Heap
{
public:
    // Initializes heap array and comparator required
    // in heapification
    Heap(int *b, bool (*c)(int, int)) : A(b), comp(c)
    {
        heapSize = -1;
    }
 
    // Frees up dynamic memory
    virtual ~Heap()
    {
        if( A )
        {
            delete[] A;
        }
    }
 
    // We need only these four interfaces of Heap ADT
    virtual bool Insert(int e) = 0;
    virtual int  GetTop() = 0;
    virtual int  ExtractTop() = 0;
    virtual int  GetCount() = 0;
 
protected:
 
    // We are also using location 0 of array
    int left(int i)
    {
        return 2 * i + 1;
    }
 
    int right(int i)
    {
        return 2 * (i + 1);
    }
 
    int parent(int i)
    {
        if( i <= 0 )
        {
            return -1;
        }
 
        return (i - 1)/2;
    }
 
    // Heap array
    int   *A;
    // Comparator
    bool  (*comp)(int, int);
    // Heap size
    int   heapSize;
 
    // Returns top element of heap data structure
    int top(void)
    {
        int max = -1;
 
        if( heapSize >= 0 )
        {
            max = A[0];
        }
 
        return max;
    }
 
    // Returns number of elements in heap
    int count()
    {
        return heapSize + 1;
    }
 
    // Heapification
    // Note that, for the current median tracing problem
    // we need to heapify only towards root, always
    void heapify(int i)
    {
        int p = parent(i);
 
        // comp - differentiate MaxHeap and MinHeap
        // percolates up
        if( p >= 0 && comp(A[i], A[p]) )
        {
            Exch(A[i], A[p]);
            heapify(p);
        }
    }
 
    // Deletes root of heap
    int deleteTop()
    {
        int del = -1;
 
        if( heapSize > -1)
        {
            del = A[0];
 
            Exch(A[0], A[heapSize]);
            heapSize--;
            heapify(parent(heapSize+1));
        }
 
        return del;
    }
 
    // Helper to insert key into Heap
    bool insertHelper(int key)
    {
        bool ret = false;
 
        if( heapSize < MAX_HEAP_SIZE )
        {
            ret = true;
            heapSize++;
            A[heapSize] = key;
            heapify(heapSize);
        }
 
        return ret;
    }
};
 
// Specialization of Heap to define MaxHeap
class MaxHeap : public Heap
{
private:
 
public:
    MaxHeap() : Heap(new int[MAX_HEAP_SIZE], &Greater)  {  }
 
    ~MaxHeap()  { }
 
    // Wrapper to return root of Max Heap
    int GetTop()
    {
        return top();
    }
 
    // Wrapper to delete and return root of Max Heap
    int ExtractTop()
    {
        return deleteTop();
    }
 
    // Wrapper to return # elements of Max Heap
    int  GetCount()
    {
        return count();
    }
 
    // Wrapper to insert into Max Heap
    bool Insert(int key)
    {
        return insertHelper(key);
    }
};
 
// Specialization of Heap to define MinHeap
class MinHeap : public Heap
{
private:
 
public:
 
    MinHeap() : Heap(new int[MAX_HEAP_SIZE], &Smaller) { }
 
    ~MinHeap() { }
 
    // Wrapper to return root of Min Heap
    int GetTop()
    {
        return top();
    }
 
    // Wrapper to delete and return root of Min Heap
    int ExtractTop()
    {
        return deleteTop();
    }
 
    // Wrapper to return # elements of Min Heap
    int  GetCount()
    {
        return count();
    }
 
    // Wrapper to insert into Min Heap
    bool Insert(int key)
    {
        return insertHelper(key);
    }
};
 
// Function implementing algorithm to find median so far.
int getMedian(int e, int &m, Heap &l, Heap &r)
{
    // Are heaps balanced? If yes, sig will be 0
    int sig = Signum(l.GetCount(), r.GetCount());
    switch(sig)
    {
    case 1: // There are more elements in left (max) heap
 
        if( e < m ) // current element fits in left (max) heap
        {
            // Remove top element from left heap and
            // insert into right heap
            r.Insert(l.ExtractTop());
 
            // current element fits in left (max) heap
            l.Insert(e);
        }
        else
        {
            // current element fits in right (min) heap
            r.Insert(e);
        }
 
        // Both heaps are balanced
        m = Average(l.GetTop(), r.GetTop());
 
        break;
 
    case 0: // The left and right heaps contain same number of elements
 
        if( e < m ) // current element fits in left (max) heap
        {
            l.Insert(e);
            m = l.GetTop();
        }
        else
        {
            // current element fits in right (min) heap
            r.Insert(e);
            m = r.GetTop();
        }
 
        break;
 
    case -1: // There are more elements in right (min) heap
 
        if( e < m ) // current element fits in left (max) heap
        {
            l.Insert(e);
        }
        else
        {
            // Remove top element from right heap and
            // insert into left heap
            l.Insert(r.ExtractTop());
 
            // current element fits in right (min) heap
            r.Insert(e);
        }
 
        // Both heaps are balanced
        m = Average(l.GetTop(), r.GetTop());
 
        break;
    }
 
    // No need to return, m already updated
    return m;
}
 
void printMedian(int A[], int size)
{
    int m = 0; // effective median
    Heap *left  = new MaxHeap();
    Heap *right = new MinHeap();
 
    for(int i = 0; i < size; i++)
    {
        m = getMedian(A[i], m, *left, *right);
 
        cout << m << endl;
    }
 
    // C++ more flexible, ensure no leaks
    delete left;
    delete right;
}
// Driver code
int main()
{
    int A[] = {5, 15, 1, 3, 2, 8, 7, 9, 10, 6, 11, 4};
    int size = ARRAY_SIZE(A);
 
    // In lieu of A, we can also use data read from a stream
    printMedian(A, size);
 
    return 0;
}

Python3

# code
from heapq import heappush, heappop, heapify
import math
minHeap=[]
heapify(minHeap)
maxHeap=[]
heapify(maxHeap)
def insertHeaps(num):
    heappush(maxHeap,-num)                ### Pushing negative element to obtain a minHeap for
    heappush(minHeap,-heappop(maxHeap))    ### the negative counterpart
   
    if len(minHeap) > len(maxHeap):
        heappush(maxHeap,-heappop(minHeap))
     
def getMedian():
    if len(minHeap)!= len(maxHeap):
        return -maxHeap[0]
    else:
        return (minHeap[0]- maxHeap[0])/2
   
 
if __name__== '__main__':
    A= [5, 15, 1, 3, 2, 8, 7, 9, 10, 6, 11, 4]
    n= len(A)
    for i in range(n):
        insertHeaps(A[i])
        print(math.floor(getMedian()))

Complejidad de tiempo: si omitimos la forma en que se leyó el flujo, la complejidad del hallazgo mediano es O (N log N) , ya que necesitamos leer el flujo y debido a las inserciones/eliminaciones de montón.

Espacio auxiliar: O(N)
A primera vista, el código anterior puede parecer complejo. Si lees el código cuidadosamente, es un algoritmo simple. 

Mediana de flujo de enteros en ejecución usando STL

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 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 *