Invertire un elenco usando due code


12

Questa domanda si ispira a una domanda esistente sulla possibilità di simulare uno stack utilizzando due code in ammortizzato per operazione di stack. La risposta sembra essere sconosciuta. Ecco una domanda più specifica, corrispondente al caso speciale in cui tutte le operazioni PUSH vengono eseguite per prime, seguite da tutte le operazioni POP. Con quale efficienza è possibile invertire un elenco di N elementi utilizzando due code inizialmente vuote? Le operazioni legali sono:O(1)N

  1. Accoda l'elemento successivo dall'elenco di input (alla coda di una delle due code).
  2. Dequeue l'elemento in testa a una delle code e accoda di nuovo (alla coda di entrambe le code).
  3. Dequeue l'elemento in testa a una delle code e aggiungerlo all'elenco di output.

Se la lista ingresso è costituito da elementi , come fa il numero minimo di operazioni necessarie per generare la lista di uscita invertita [ N , N - 1 , . . . , 2 , 1 ] comportarsi? Una prova che cresce più velocemente di sarebbe particolarmente interessante, dal momento che risolverebbe la domanda originale in senso negativo.[1,2,...,N1,N][N,N1,...,2,1]O(N)


Aggiornamento (15 gennaio 2011): il problema può essere risolto in , come mostrato nelle risposte inviate e nei loro commenti; e un limite inferiore di è banale. Uno di questi limiti può essere migliorato?Ω ( N )O(NlogN)Ω(N)


Per chiarire: con "l'ultimo elemento di una delle due code" ti riferisci all'elemento in testa alla coda?
Peter Taylor,

@Peter: Sì, grazie per il chiarimento. Ho modificato la domanda.
mjqxxxx,

Gli stack degli elenchi di input e output sono entrambi? In tal caso, n op1s (nella stessa coda) seguito da n op3s fa il contrario, giusto? Penso che mi manchi qualcosa di importante.
jbapple,

@jbapple: No, non sono pile. È necessario scrivere elementi nell'elenco di output nell'ordine opposto in cui sono stati letti dall'elenco di input.
mjqxxxx,

Risposte:


11

Se N è una potenza di due, credo che le operazioni O (N log N) siano sufficienti, anche per un problema un po 'più limitato in cui tutti gli elementi iniziano su una delle code e devono finire in ordine inverso su una delle code (senza gli elenchi di input e output).

In O (N) passi è possibile iniziare con tutti gli elementi su una coda, giocare "uno per te uno per me" per dividerli in sottoinsiemi alternati sull'altra coda, e poi concatenarli tutti in una coda. In termini di rappresentazioni binarie delle posizioni degli oggetti, questo implementa un'operazione di rotazione.

Nei passaggi O (N) è anche possibile estrarre coppie di elementi da una coda, scambiarli, quindi rimetterli indietro, invertendo tutte le coppie. In termini di rappresentazioni binarie delle posizioni degli oggetti, questo completa il bit di ordine basso della posizione.

Ripetendo O (log N) volte uno shuffle e uno swap a coppie, possiamo integrare tutti i bit delle rappresentazioni binarie delle posizioni - che è la stessa cosa che invertire l'elenco.


Quindi puoi scomporre l'elenco in una rappresentazione binaria e invertire pezzo per pezzo per un algoritmo O (n lg n), credo.
jbapple,

Pensavo che si potesse estendere a tutti gli N usando un albero 2-3 anziché binario, ma forse la tua idea è più semplice. Ma come si fa a invertire ciascuno dei pezzi O (log n) in passi totali O (n log n)?
David Eppstein,

Il tempo è O (somma (2 ^ i) lg (2 ^ i)) per i da 0 a [lg n], che Wolfram alpha dice è O (n lg n): wolframalpha.com/input/?i=sum+ (2 ^ k) + log2 + (2 ^ k) + da + 0 + a + log2 + n
jbapple

Certo, se puoi invertire ciascuno dei pezzi in tempo proporzionale alla sua lunghezza per il suo registro, il gioco è fatto. Ma devi mettere i pezzi da qualche parte una volta che li hai invertiti, e ciò potrebbe rendere più difficile invertire i pezzi rimanenti.
David Eppstein,

Il problema presenta un "elenco di output". Possiamo metterli lì?
jbapple,

1

i=0N/21(N2i2)

Consente di nominare due code disponibili come sinistra e destra. Ecco l'idea di base di questo algoritmo con il presupposto che N sia pari:

  1. Leggere i valori dall'elenco iniziale di elementi e inserire tutti i numeri dispari nella coda sinistra e i numeri pari nella coda destra
  2. Uno dei primi passi il modo più veloce per generare il valore massimo è trasferire N / 2-1 elementi dalla coda destra a quella sinistra e far apparire il valore superiore dalla coda destra nell'elenco di output
  3. Ora dobbiamo fare lo stesso per un'altra coda: trasferire gli elementi N / 2-1 dalla coda sinistra a quella destra e inserire l'elemento superiore dalla coda sinistra nell'elenco di output
  4. Scambia le code e ripeti i passaggi 2 e 3 per N = N-2

È facile vedere come l'algoritmo dovrebbe funzionare per N. dispari


È possibile utilizzare $ ... $ per inserire il codice LaTeX-ish (meno il \).
Mark Reitblatt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.