Trovare la mediana - 2#4074

Trovare la mediana - 2 (Editoriale)

Modelliamo la soluzione del problema utilizzando un array lineare. Ad ogni passo memorizzeremo in esso i numeri in arrivo in forma ordinata. La posizione per l'inserimento di un nuovo elemento verrà trovata mediante ricerca binaria. Tuttavia, l'operazione di inserimento stessa (ad esempio, se l'array è implementato utilizzando la struttura dati ) viene eseguita in tempo lineare. Pertanto, la soluzione complessiva con complessità temporale O(n^2) non rientrerà nel limite di tempo.

Dichiariamo due heap: uno — per memorizzare il minimo (-heap), l'altro — per memorizzare il massimo (-heap). Organizziamo il loro funzionamento in modo che siano soddisfatte le seguenti condizioni:

Quando si aggiunge un nuovo elemento, lo inseriamo nel -heap se non è minore dell'elemento minimo di questo heap; altrimenti — nel -heap. Successivamente eseguiamo il bilanciamento degli heap per mantenere le proprietà sopra indicate:

La mediana della sequenza corrente viene determinata come segue:

L'inserimento di un elemento nell'heap e il successivo bilanciamento vengono eseguiti in tempo O(log_2n). Pertanto, il tempo totale di esecuzione dell'algoritmo è O(nlog_2n).

Esempio

Consideriamo il processo di calcolo della mediana con l'arrivo sequenziale dei numeri. Per chiarezza, supporremo che dopo l'aggiunta di ogni nuovo numero la sequenza venga ordinata. Sotto ogni sequenza è indicato il valore corrispondente della mediana.

Dopo aver elaborato tutti gli elementi dell'esempio, lo stato degli heap sarà il seguente:

Poiché il numero di elementi è dispari, la mediana è uguale all'elemento minimo del -heap, cioè .

Supponiamo che arrivi successivamente il numero . Poiché non è minore dell'elemento minimo del -heap, lo aggiungiamo al -heap. Dopo di che la dimensione del -heap risulterà maggiore di due elementi rispetto alla dimensione del -heap, quindi è necessario eseguire il bilanciamento: trasferire l'elemento minimo del -heap () nel -heap. In altre parole, rimuoviamo dal -heap e lo aggiungiamo al -heap.

Ora il numero totale di elementi nell'array è pari, quindi la mediana viene determinata come la media aritmetica dell'elemento minimo del -heap () e dell'elemento massimo del -heap (), cioè (35 + 4) / 2 = 19. Nel problema è richiesto di stampare solo la parte intera della mediana.

Implementazione dell'algoritmo

Dichiariamo il -heap mMinHeap e il -heap mMaxHeap.

priority_queue<int, vector<int>, greater<int> > mMinHeap;
priority_queue<int, vector<int>, less<int> > mMaxHeap;

Inizializziamo gli heap. Nella variabile memorizzeremo il numero di numeri ricevuti in ingresso. Per comodità, inizializziamo gli heap con elementi fittizi.

mMaxHeap.push(-MAX); mMinHeap.push(MAX);
c = 1;

Elaboriamo il numero successivo.

while(scanf("%d",&n) == 1) 
{ 

A seconda del valore di , lo inseriamo in uno degli heap.

  if (n >= mMinHeap.top()) mMinHeap.push(n);
  else mMaxHeap.push(n);

Se la dimensione del -heap supera la dimensione del -heap, oppure la dimensione del -heap supera di più di un elemento la dimensione del -heap, eseguiamo il bilanciamento.

  if(mMaxHeap.size() > mMinHeap.size())
  { 

Trasferiamo l'elemento massimo del -heap nel -heap.

    mMinHeap.push(mMaxHeap.top());
    mMaxHeap.pop();
  } else

  if(mMaxHeap.size() + 1 < mMinHeap.size())
  { 

Trasferiamo l'elemento minimo del -heap nel -heap.

    mMaxHeap.push(mMinHeap.top());
    mMinHeap.pop();
  }

A seconda della parità del numero di elementi nell'array, stampiamo il valore della mediana.

  if (c % 2) printf("%d\n",mMinHeap.top()); 
  else printf("%d\n",(mMinHeap.top() + mMaxHeap.top())/2); 
  c++;
}