Bisakah pohon dilintasi tanpa rekursi, tumpukan, atau antrian, dan hanya beberapa petunjuk?

15

Setengah dekade yang lalu saya duduk di kelas struktur data di mana profesor menawarkan kredit tambahan jika ada yang bisa melintasi pohon tanpa menggunakan rekursi, tumpukan, antrian, dll (atau struktur data serupa lainnya) dan hanya beberapa petunjuk. Saya datang dengan apa yang saya pikir merupakan jawaban yang jelas untuk pertanyaan yang akhirnya diterima oleh profesor. Saya duduk di kelas matematika diskrit dengan profesor lain di departemen yang sama - dan dia menegaskan bahwa tidak mungkin untuk melintasi pohon tanpa rekursi, tumpukan, antrian, dll., Dan solusi saya tidak valid.

Jadi, apakah mungkin, atau tidak mungkin? Mengapa atau mengapa tidak?

Sunting: Untuk menambahkan beberapa klarifikasi, saya menerapkan ini pada pohon biner yang memiliki tiga elemen - data yang disimpan di setiap node dan pointer ke dua anak. Solusi saya dapat diperluas ke pohon n-ary dengan hanya beberapa perubahan.

Guru struktur data saya tidak memberikan hambatan apa pun terhadap mutasi pohon, dan memang saya kemudian mengetahui bahwa solusinya sendiri adalah dengan menggunakan pointer anak untuk menunjuk kembali pohon dalam perjalanan turun. Profesor matematika diskrit saya mengatakan mutasi pohon berarti bahwa itu bukan lagi pohon sesuai dengan definisi matematika pohon, definisinya juga akan menghalangi setiap petunjuk kepada orang tua - yang akan cocok dengan kasus di mana saya menyelesaikannya di atas.

NL - Minta maaf kepada Monica
sumber
3
Anda perlu menentukan batasannya. Apakah saya diizinkan untuk memutasi pohon? Bagaimana pohon itu diwakili? (Misalnya, apakah setiap node memiliki pointer orangtua ke induknya?) Jawabannya akan tergantung pada kendala spesifik; tanpa menentukan batasan-batasan itu, ini bukan masalah yang diajukan dengan baik.
DW
2
Saya kira contraint profesor benar-benar ingin mengekspresikan adalah "dengan ruang tambahan". Tapi apa solusi Anda? HAI(1)
Raphael

Jawaban:

17

Banyak penelitian di bidang ini telah kubah, termotivasi oleh metode "murah" melintasi pohon dan struktur daftar umum dalam konteks pengumpulan sampah.

Pohon biner berulir adalah representasi yang disesuaikan dari pohon biner di mana beberapa nil-pointer digunakan untuk menautkan ke simpul penerus dalam pohon. Informasi tambahan ini dapat digunakan untuk melintasi pohon tanpa tumpukan. Namun, bit ekstra per node diperlukan untuk membedakan utas dari child-pointer. Wikipedia: Tree_traversal

Sejauh yang saya tahu pohon biner diimplementasikan menggunakan pointer dalam mode biasa (pointer kiri dan kanan per node) dapat dilalui menggunakan metode thread, dalam metode yang dikaitkan dengan Morris . NIL-pointer untuk sementara digunakan kembali untuk merutekan path kembali ke root. Bagian yang cerdik adalah bahwa selama traversal seseorang dapat membedakan tepi asli dari tautan-utas sementara, menggunakan cara mereka membentuk siklus di pohon).

Bagian yang baik: tidak ada struktur data tambahan. Bagian buruk: sedikit curang, tumpukan berada di dalam pohon dengan cara yang cerdas. Sangat pintar.

Bukti tumpukan tersembunyi ditunjukkan dalam P. Mateti dan R. Manghirmalani: Algoritma Traversal Pohon Morris, DOI: 10.1016 / 0167-6423 (88) 90063-9 yang Dipertimbangkan

JM Morris: Melintasi pohon biner secara sederhana dan murah. IPL 9 (1979) 197-200 DOI: 10.1016 / 0020-0190 (79) 90068-1

Lalu ada juga Lindstrom pemindaian . Metode ini "memutar" tiga pointer yang terlibat dalam setiap node (orang tua dan dua anak). Jika Anda ingin melakukan algoritma pre-order atau post-order yang layak, Anda memerlukan bit tambahan per node. Jika Anda hanya ingin mengunjungi semua node (tiga kali, tetapi Anda tidak pernah tahu kunjungan mana yang Anda lakukan) maka itu dapat dilakukan tanpa bit.

G. Lindstrom: Memindai struktur daftar tanpa tumpukan atau tag tag. IPL 2 (1973) 47-51. DOI: 10.1016 / 0020-0190 (73) 90012-4

Mungkin cara yang paling mudah adalah dengan metode Robson . Di sini tumpukan yang diperlukan untuk algoritma klasik di-threaded melalui daun.

JM Robson: Algoritma yang ditingkatkan untuk melintasi pohon biner tanpa tumpukan tambahan IPL 1 (1973) 149-152. 10.1016 / 0020-0190 (73) 90018-5

IPL = Surat Pemrosesan Informasi

Hendrik Jan
sumber
Saya juga menyukai solusi ini, meskipun tidak ada yang saya dapat selama tahun pertama kelas ilmu komputer. Ya, mungkin curang sesuai dengan aturan profesor saya.
NL - Minta maaf kepada Monica
2
Bisakah Anda memberikan tautan / referensi untuk strategi?
Raphael
1
Bagian buruk sebenarnya dari metode itu adalah Anda tidak dapat memiliki lebih dari satu traversal yang terjadi pada satu waktu.
Gilles 'SANGAT berhenti menjadi jahat'
6

v

Yuval Filmus
sumber
Ini mirip dengan solusi yang profesor struktur data yang mengusulkan masalah yang digunakan untuk menyelesaikannya. Profesor matematika yang berbeda menolak bahwa "ini telah menjadi grafik daripada pohon" jika ada petunjuk kembali ke orang tua.
NL - Minta maaf kepada Monica
@NathanLiddle: Itu akan tergantung pada definisi pohon yang digunakan (yang tidak Anda berikan). Dalam "dunia nyata", representasi pohon Yuval masuk akal bahkan jika teori graf akan mengatakan hal-hal yang ia tentukan bukan pohon, tentu saja.
Raphael
@ Raphael Ya, dan memenuhi persyaratan profesor asli, jadi itu adalah jawaban yang dapat diterima bagi saya.
NL - Minta maaf kepada Monica
0

Solusi saya adalah traversal bredth-first menggunakan nested for-loop untuk brute force pohon. Ini tidak efisien dengan cara apa pun, dan memang struktur data rekursif seperti pohon memohon untuk traversal rekursif, tetapi pertanyaannya bukan apakah pohon dapat dilintasi secara efisien, adalah apakah itu mungkin.

Pseudocode:
root = pointer root 
depth = integer 0
finished = bool false
//If we n-ary tree also track how many children have been found 
//on the node with the most children for the purposes of this psuedocode 
//we'll assume a binary tree and insert a magic number of 2 so that we 
//can use bitwise operators instead of integer division 
while(!finished)
    ++depth
    treePosition = pointer root
    finished = true;
    for i := 0..2**depth
        for j := 0..depth
            if (i & j) //bitwise operator explained below
                // if right child doesn't exist break the loop
                treePosition = treePosition.rightChild
            else
                // if left child doesn't exist break the loop
                treePosition = treePosition.leftChild
        if j has any children
            finished = false
            do anything else you want when visiting the node

Untuk beberapa level pertama akan terlihat seperti ini, seperti yang Anda lihat, operator bitwise dalam pseudocode hanya memutuskan belokan kiri atau kanan pada pohon biner:

2**1       0               1
2**2   00      01      10      11
2**3 000 001 010 011 100 101 110 111

Untuk n-ary, Anda akan mengambil i% (maxChildren ** j) / j untuk menentukan jalur mana yang akan diambil antara 0 dan maxChildren.

Pada setiap node di n-ary Anda juga perlu memeriksa untuk melihat apakah jumlah anak lebih besar dari maxChildren dan memperbaruinya dengan tepat.

NL - Minta maaf kepada Monica
sumber
Jika Anda ingin menggunakan lebih dari biner, Anda perlu mengganti angka ajaib 2 dengan variabel yang akan ditambahkan agar sesuai dengan anak-anak maks yang dilihatnya, dan alih-alih operator bitwise, Anda harus membaginya dengan variabel yang sama yang dinaikkan menjadi kekuatan kedalaman pohon di mana Anda berada.
NL - Minta maaf kepada Monica
HAI(1)HAI(lgn)HAI(1)HAI(n)HAI(1)ruang tambahan "). Misalnya, apa yang Anda lakukan jika depthmelebihi lebar int?
DW
DW, profesor yang mengajukan masalah tidak menempatkan kendala pada masalah itu, dan apa yang sangat mengganggu saya tentang diskusi saya dengan profesor matematika diskrit adalah bahwa ia TIDAK PERNAH mengakui bahwa bahkan mungkin untuk melintasi pohon tanpa rekursi, tumpukan, atau antrian, berapa pun biayanya. Satu-satunya hal yang diperlihatkan oleh solusi saya adalah bahwa adalah mungkin untuk melakukan apa saja secara iteratif yang dapat dilakukan secara rekursif, bahkan jika Anda menghapus opsi untuk tumpukan, antrian, dll.
NL - Minta maaf ke Monica
Ini adalah satu hal untuk mengatakan itu tidak dapat diselesaikan tanpa O (1) ruang tambahan, itu adalah hal lain untuk menyatakan masalah tidak dapat diselesaikan tanpa rekursi, tumpukan, atau antrian. Dan sebenarnya, setelah melihat kode saya, profesor matematika diskrit masih tidak akan menyetujui maksudnya karena dia mengatakan "i" pada baris pertama untuk loop menggantikan antrian. Bagaimana itu untuk keras kepala?
NL - Minta maaf kepada Monica
1
@NathanLiddle, periksa lagi. Bilangan bulat Anda iagak depthlebar. Jika depthadaΘ(n) (yang bisa jadi, di pohon-pohon yang tidak seimbang), maka Anda perlu Θ(n)ruang untuk menyimpan integer i, sehingga solusinya membutuhkan lebih dariHAI(1)ruang tambahan.
DW