Katakanlah Anda ingin mengimplementasikan pencarian pertama dari pohon biner secara rekursif . Bagaimana Anda melakukannya?
Apakah mungkin hanya menggunakan tumpukan panggilan sebagai penyimpanan tambahan?
Katakanlah Anda ingin mengimplementasikan pencarian pertama dari pohon biner secara rekursif . Bagaimana Anda melakukannya?
Apakah mungkin hanya menggunakan tumpukan panggilan sebagai penyimpanan tambahan?
Jawaban:
(Saya berasumsi bahwa ini hanya semacam latihan pemikiran, atau bahkan trik mengerjakan pekerjaan rumah / wawancara, tapi saya kira saya bisa membayangkan beberapa skenario aneh di mana Anda tidak diizinkan menimbun ruang untuk beberapa alasan [beberapa kebiasaan yang sangat buruk manajer memori? beberapa masalah runtime / OS yang aneh?] ketika Anda masih memiliki akses ke tumpukan ...)
Breadth-first traversal secara tradisional menggunakan antrian, bukan tumpukan. Sifat antrian dan tumpukan cukup berlawanan, jadi mencoba menggunakan panggilan stack (yang merupakan tumpukan, maka nama) sebagai penyimpanan tambahan (antrian) cukup banyak ditakdirkan untuk gagal, kecuali jika Anda melakukan sesuatu yang konyol dengan tumpukan panggilan yang seharusnya tidak Anda lakukan.
Pada token yang sama, sifat dari setiap rekursi non-ekor yang Anda coba implementasikan pada dasarnya menambahkan tumpukan ke algoritma. Ini membuatnya tidak lagi luas pencarian pertama pada pohon biner, dan dengan demikian run-time dan yang lainnya untuk BFS tradisional tidak lagi sepenuhnya berlaku. Tentu saja, Anda selalu dapat dengan mudah mengubah perulangan apa pun menjadi panggilan rekursif, tetapi itu bukan jenis rekursi yang berarti.
Namun, ada cara, seperti yang ditunjukkan oleh orang lain, untuk mengimplementasikan sesuatu yang mengikuti semantik BFS dengan biaya tertentu. Jika biaya perbandingannya mahal tetapi node traversal murah, maka seperti yang dilakukan @Simon Buchan , Anda bisa menjalankan pencarian kedalaman-iteratif pertama, hanya memproses daun. Ini berarti tidak ada antrian tumbuh yang disimpan di heap, hanya variabel kedalaman lokal, dan tumpukan yang dibangun berulang-ulang di tumpukan panggilan saat pohon dilintasi berulang-ulang. Dan seperti yang dicatat oleh @Patrick , pohon biner yang didukung oleh array biasanya disimpan dalam urutan traversal pertama, jadi pencarian pertama yang luas akan sepele, juga tanpa perlu antrian tambahan.
sumber
Jika Anda menggunakan array untuk mendukung pohon biner, Anda dapat menentukan simpul berikutnya secara aljabar. jika
i
adalah simpul, maka anak-anaknya dapat ditemukan di2i + 1
(untuk simpul kiri) dan2i + 2
(untuk simpul kanan). Tetangga node berikutnya diberikan olehi + 1
, kecualii
kekuatan dari2
Inilah pseudocode untuk implementasi yang sangat naif dari pencarian pertama luasnya pada pohon pencarian biner array yang didukung. Ini mengasumsikan array ukuran tetap dan karenanya pohon kedalaman tetap. Ini akan melihat node tanpa orangtua, dan dapat membuat tumpukan besar tidak terkelola.
sumber
Saya tidak dapat menemukan cara untuk melakukannya sepenuhnya rekursif (tanpa struktur data tambahan). Tetapi jika antrian Q dilewatkan dengan referensi, maka Anda dapat memiliki fungsi rekursif ekor konyol berikut:
sumber
Metode berikut menggunakan algoritma DFS untuk mendapatkan semua node di kedalaman tertentu - yang sama dengan melakukan BFS untuk tingkat itu. Jika Anda menemukan kedalaman pohon dan melakukan ini untuk semua tingkatan, hasilnya akan sama dengan BFS.
Menemukan kedalaman pohon adalah sepotong kue:
sumber
level
nol.Rekursi BFS dan DFS sederhana di Jawa:
Cukup tekan / tawarkan simpul akar pohon di stack / antrian dan panggil fungsi-fungsi ini.
sumber
Saya menemukan algoritma terkait Breadth-First traversal terkait rekursif (bahkan fungsional) yang sangat indah. Bukan ide saya, tapi saya pikir itu harus disebutkan dalam topik ini.
Chris Okasaki menjelaskan algoritme penomoran pertamanya yang luas dari ICFP 2000 di http://okasaki.blogspot.de/2008/07/breadth-first-numbering-algorithm-in.html sangat jelas hanya dengan 3 gambar.
Implementasi Scala dari Debasish Ghosh, yang saya temukan di http://debasishg.blogspot.de/2008/09/breadth-first-first-numbering-okasakis.html , adalah:
sumber
Cara bodoh:
sumber
Inilah solusi Scala singkat :
Ide menggunakan nilai kembali sebagai akumulator sangat cocok. Dapat diimplementasikan dalam bahasa lain dengan cara yang sama, hanya pastikan bahwa proses rekursif Anda daftar node .
Daftar kode tes (menggunakan pohon tes @marco):
Keluaran:
sumber
Berikut ini implementasi python:
sumber
Berikut ini adalah implementasi Scala 2.11.4 dari BFS rekursif. Saya telah mengorbankan optimisasi panggilan ekor untuk singkatnya, tetapi versi TCOd sangat mirip. Lihat juga postingan @snv .
sumber
Berikut ini sepertinya cukup alami bagi saya, menggunakan Haskell. Ulangi secara berulang di atas level pohon (di sini saya mengumpulkan nama menjadi string besar yang diperintahkan untuk menunjukkan jalur melalui pohon):
sumber
Berikut ini adalah implementasi Python traversal rekursif BFS, bekerja untuk grafik tanpa siklus.
sumber
Saya ingin menambahkan sen saya ke jawaban teratas karena jika bahasa mendukung sesuatu seperti generator, bfs dapat dilakukan secara rekursif.
Untuk mulai dengan, jawaban @ Tanzelax berbunyi:
Memang, stack pemanggilan fungsi biasa tidak akan berperilaku seperti stack normal. Tetapi fungsi generator akan menunda eksekusi fungsi sehingga memberi kita kesempatan untuk menghasilkan anak-anak node level berikutnya tanpa menggali keturunan node yang lebih dalam.
Kode berikut adalah bfs rekursif dengan Python.
Intuisi di sini adalah:
sumber
Saya harus mengimplementasikan heap traversal yang menghasilkan dalam urutan BFS. Ini sebenarnya bukan BFS tetapi menyelesaikan tugas yang sama.
sumber
Biarkan v menjadi titik awal
Biarkan G menjadi grafik yang dipermasalahkan
Berikut ini adalah kode semu tanpa menggunakan antrian
sumber
BFS untuk pohon biner (atau n-ary) dapat dilakukan secara rekursif tanpa antrian sebagai berikut (di sini di Jawa):
Contoh nomor pencetakan traversal 1-12 dalam urutan menaik:
sumber
sumber
Berikut adalah Implementasi JavaScript yang memalsukan Breadth First Traversal dengan Rekursi Depth First. Saya menyimpan nilai-nilai simpul di setiap kedalaman di dalam array, di dalam hash. Jika level sudah ada (kami memiliki tabrakan), jadi kami hanya mendorong ke array di level itu. Anda bisa menggunakan array bukan objek JavaScript juga karena level kami numerik dan dapat berfungsi sebagai indeks array. Anda dapat mengembalikan node, nilai, dikonversi ke Daftar Tertaut, atau apa pun yang Anda inginkan. Saya hanya mengembalikan nilai demi kesederhanaan.
Berikut ini adalah contoh Breadth First Traversal yang sebenarnya menggunakan pendekatan iteratif.
sumber
Berikut ini adalah kode saya untuk implementasi sepenuhnya rekursif dari pencarian luas-pertama dari grafik dua arah tanpa menggunakan loop dan antrian.
sumber
C # implementasi algoritma pencarian luas-rekursif pertama untuk pohon biner.
Visualisasi data pohon biner
Jika Anda ingin algoritma berfungsi tidak hanya dengan binary-tree tetapi dengan grafik yang dapat memiliki dua dan lebih banyak node yang menunjuk ke node lain yang sama, Anda harus menghindari siklus sendiri dengan memegang daftar node yang sudah dikunjungi. Implementasinya mungkin terlihat seperti ini.
Visualisasi data grafik
sumber
Saya telah membuat program menggunakan c ++ yang bekerja dalam grafik gabungan dan terpisah juga.
sumber