Membalik daftar menggunakan dua antrian

12

Pertanyaan ini terinspirasi oleh pertanyaan yang ada tentang apakah stack dapat disimulasikan menggunakan dua antrian dalam waktu diamortisasi per operasi stack. Jawabannya sepertinya tidak diketahui. Berikut adalah pertanyaan yang lebih spesifik, terkait dengan kasus khusus di mana semua operasi PUSH dilakukan terlebih dahulu, diikuti oleh semua operasi POP. Seberapa efisien daftar elemen dapat dibalik menggunakan dua antrian yang awalnya kosong? Operasi hukum adalah:NO(1)N

  1. Enqueue elemen berikutnya dari daftar input (ke ujung salah satu antrian).
  2. Dequeue elemen di kepala antrian baik dan enqueue lagi (ke ekor antrian baik).
  3. Dequeue elemen di kepala salah satu antrian dan tambahkan ke daftar output.

Jika daftar input terdiri dari elemen , bagaimana jumlah minimum operasi yang diperlukan untuk menghasilkan daftar output terbalik berperilaku? Sebuah bukti bahwa itu tumbuh lebih cepat daripada akan sangat menarik, karena itu akan menyelesaikan pertanyaan aslinya dalam negatif.[ N , N - 1 , . . . , 2 , 1 ] O ( N )[1,2,...,N1,N][N,N1,...,2,1]O(N)


Pembaruan (15 Jan 2011): Masalahnya dapat diselesaikan di , seperti yang ditunjukkan dalam jawaban yang diajukan dan komentar mereka; dan batas bawah sepele. Bisakah salah satu dari batasan ini diperbaiki?Ω ( N )O(NlogN)Ω(N)

mjqxxxx
sumber
Untuk memperjelas: dengan "elemen terakhir dari salah satu antrian" apakah Anda merujuk ke elemen di kepala antrian?
Peter Taylor
@ Peter: Ya, terima kasih atas klarifikasi. Saya telah mengedit pertanyaan.
mjqxxxx
Apakah tumpukan input dan output daftar? Jika demikian, n op1s (ke antrian yang sama) diikuti oleh n op3s sebaliknya, kan? Saya pikir saya harus kehilangan sesuatu yang penting.
jbapple
@ jbapple: Tidak, mereka bukan tumpukan. Anda perlu menulis elemen ke daftar output dalam urutan yang berlawanan, mereka membaca dari daftar input.
mjqxxxx

Jawaban:

11

Jika N adalah kekuatan dua, saya percaya operasi O (N log N) sudah cukup, bahkan untuk masalah yang agak lebih terbatas di mana semua item dimulai pada salah satu antrian dan harus berakhir dalam urutan terbalik pada salah satu antrian (tanpa daftar input dan output).

Dalam langkah-langkah O (N) dimungkinkan untuk memulai dengan semua elemen pada satu antrian, bermain "satu untukmu satu untukku" untuk membaginya menjadi subset bergantian pada antrian lainnya, dan kemudian menggabungkan semuanya kembali menjadi satu antrian. Dalam hal representasi biner dari posisi item, ini mengimplementasikan operasi rotasi.

Dalam langkah-langkah O (N) juga dimungkinkan untuk menarik pasangan elemen dari satu antrian, menukar mereka, lalu memasangnya kembali, membalikkan semua pasangan. Dalam hal representasi biner dari posisi item, ini melengkapi bit order posisi rendah.

Dengan mengulangi O (log N) kali unshuffle dan swap berpasangan, kita dapat melengkapi semua bit dari representasi biner dari posisi - yang sama dengan membalikkan daftar.

David Eppstein
sumber
Kemudian Anda dapat memecah daftar menjadi representasi biner dan membalikkan sepotong demi sepotong untuk algoritma O (n lg n), saya pikir.
jbapple
Saya berpikir seseorang dapat memperluas ke semua N dengan menggunakan pohon 2-3 bukannya biner, tapi mungkin ide Anda lebih sederhana. Tetapi bagaimana Anda membalikkan masing-masing bagian O (log n) dalam langkah-langkah total O (n log n)?
David Eppstein
Waktunya adalah O (jumlah (2 ^ i) lg (2 ^ i)) untuk saya dari 0 hingga [lg n], yang Wolfram alpha katakan adalah O (n lg n): wolframalpha.com/input/?i=sum+ (2 ^ k) + log2 + (2 ^ k) + dari + 0 + hingga + log2 + n
jbapple
Tentu, jika Anda dapat membalik masing-masing bagian dalam waktu sebanding dengan panjangnya kali log, Anda selesai. Tetapi Anda harus meletakkan potongan-potongan itu di suatu tempat begitu Anda membalikkannya, dan itu mungkin membuatnya lebih sulit untuk membalikkan potongan yang tersisa.
David Eppstein
Masalahnya menempatkan "daftar keluaran". Bisakah kita taruh di sana?
jbapple
1

i=0N/21(N2i2)

Beri nama dua antrian yang tersedia sebagai kiri dan kanan. Berikut adalah ide dasar dari algoritma ini dengan asumsi bahwa N adalah genap:

  1. Baca nilai dari daftar awal elemen dan dorong semua angka ganjil ke antrian kiri dan bahkan angka ke antrian kanan
  2. Salah satu langkah pertama cara tercepat untuk menghasilkan nilai maksimum adalah dengan mentransfer elemen N / 2-1 dari antrian kanan ke antrian kiri dan memasukkan nilai teratas dari antrian kanan ke daftar keluaran
  3. Sekarang kita harus melakukan hal yang sama untuk antrian lain - mentransfer elemen N / 2-1 dari antrian kiri ke antrian kanan dan memasukkan elemen atas dari antrian kiri ke daftar output
  4. Tukar antrian dan ulangi langkah 2 dan 3 untuk N = N-2

Sangat mudah untuk melihat bagaimana algoritma seharusnya bekerja untuk N. aneh

Elalfer
sumber
Anda dapat menggunakan $ ... $ untuk memasukkan kode LaTeX-ish (minus \).
Mark Reitblatt