Ini membutuhkan fungsi rekursif yang sangat dasar untuk mengurai pasangan anak / induk ke struktur pohon dan fungsi rekursif lain untuk mencetaknya. Hanya satu fungsi yang cukup tetapi berikut dua untuk kejelasan (fungsi gabungan dapat ditemukan di akhir jawaban ini).
Pertama-tama, inisialisasi larik pasangan anak / induk:
$tree = array(
'H' => 'G',
'F' => 'G',
'G' => 'D',
'E' => 'D',
'A' => 'E',
'B' => 'C',
'C' => 'E',
'D' => null
);
Kemudian fungsi yang mem-parsing array itu menjadi struktur hierarki pohon:
function parseTree($tree, $root = null) {
$return = array();
# Traverse the tree and search for direct children of the root
foreach($tree as $child => $parent) {
# A direct child is found
if($parent == $root) {
# Remove item from tree (we don't need to traverse this again)
unset($tree[$child]);
# Append the child into result array and parse its children
$return[] = array(
'name' => $child,
'children' => parseTree($tree, $child)
);
}
}
return empty($return) ? null : $return;
}
Dan fungsi yang melintasi pohon itu untuk mencetak daftar yang tidak berurutan:
function printTree($tree) {
if(!is_null($tree) && count($tree) > 0) {
echo '<ul>';
foreach($tree as $node) {
echo '<li>'.$node['name'];
printTree($node['children']);
echo '</li>';
}
echo '</ul>';
}
}
Dan penggunaan sebenarnya:
$result = parseTree($tree);
printTree($result);
Berikut isi dari $result
:
Array(
[0] => Array(
[name] => D
[children] => Array(
[0] => Array(
[name] => G
[children] => Array(
[0] => Array(
[name] => H
[children] => NULL
)
[1] => Array(
[name] => F
[children] => NULL
)
)
)
[1] => Array(
[name] => E
[children] => Array(
[0] => Array(
[name] => A
[children] => NULL
)
[1] => Array(
[name] => C
[children] => Array(
[0] => Array(
[name] => B
[children] => NULL
)
)
)
)
)
)
)
)
Jika Anda ingin sedikit lebih efisien, Anda dapat menggabungkan fungsi-fungsi itu menjadi satu dan mengurangi jumlah iterasi yang dibuat:
function parseAndPrintTree($root, $tree) {
$return = array();
if(!is_null($tree) && count($tree) > 0) {
echo '<ul>';
foreach($tree as $child => $parent) {
if($parent == $root) {
unset($tree[$child]);
echo '<li>'.$child;
parseAndPrintTree($child, $tree);
echo '</li>';
}
}
echo '</ul>';
}
}
Anda hanya akan menyimpan 8 iterasi pada kumpulan data sekecil ini tetapi pada kumpulan yang lebih besar itu bisa membuat perbedaan.
Namun Fungsi Lain Untuk Membuat Pohon (tidak ada rekursi yang terlibat, sebagai gantinya menggunakan referensi):
Mengembalikan larik hierarki seperti ini:
Yang dapat dengan mudah dicetak sebagai daftar HTML menggunakan fungsi rekursif.
sumber
Cara lain yang lebih disederhanakan untuk mengubah struktur datar
$tree
menjadi hierarki. Hanya satu larik sementara yang diperlukan untuk mengeksposnya:Itu saja untuk membuat hierarki menjadi array multidimensi:
Outputnya kurang sepele jika Anda ingin menghindari rekursi (bisa menjadi beban dengan struktur besar).
Saya selalu ingin memecahkan "dilema" UL / LI untuk mengeluarkan sebuah array. Dilemanya adalah, setiap item tidak mengetahui apakah anak akan menindaklanjuti atau tidak atau berapa banyak elemen sebelumnya yang perlu ditutup. Dalam jawaban lain saya sudah memecahkannya dengan menggunakan
RecursiveIteratorIterator
dan mencarigetDepth()
dan meta-informasi lain yang saya tulis sendiriIterator
: Mendapatkan model set bersarang ke dalam<ul>
tetapi menyembunyikan subpohon "tertutup" . Itu jawaban menunjukkan juga bahwa dengan iterator Anda cukup fleksibel.Namun itu adalah daftar yang telah diurutkan sebelumnya, jadi tidak akan cocok untuk contoh Anda. Selain itu saya selalu ingin menyelesaikan ini untuk semacam struktur pohon standar dan HTML
<ul>
dan<li>
elemen.Konsep dasar yang saya kemukakan adalah sebagai berikut:
TreeNode
- Mengabstraksi setiap elemen menjadiTreeNode
tipe sederhana yang dapat memberikan nilainya (misalnyaName
) dan memiliki turunan atau tidak.TreeNodesIterator
- ARecursiveIterator
yang mampu melakukan iterasi atas satu set (array) iniTreeNodes
. Itu cukup sederhana karenaTreeNode
tipe sudah tahu apakah ia memiliki anak dan yang mana.RecursiveListIterator
- ARecursiveIteratorIterator
yang memiliki semua peristiwa yang diperlukan saat iterasi secara rekursif melalui segala jenisRecursiveIterator
:beginIteration
/endIteration
- Awal dan akhir daftar utama.beginElement
/endElement
- Awal dan akhir setiap elemen.beginChildren
/endChildren
- Awal dan akhir setiap daftar anak. IniRecursiveListIterator
hanya menyediakan acara ini dalam bentuk pemanggilan fungsi. daftar anak-anak, seperti yang biasa untuk<ul><li>
daftar, dibuka dan ditutup di dalam<li>
elemen induknya . Oleh karena ituendElement
acara tersebut dipecat setelahendChildren
acara yang sesuai . Ini dapat diubah atau dibuat dapat dikonfigurasi untuk memperluas penggunaan kelas ini. Peristiwa didistribusikan sebagai panggilan fungsi ke objek dekorator kemudian, untuk memisahkan hal-hal.ListDecorator
- Kelas "dekorator" yang hanya menerima peristiwaRecursiveListIterator
.Saya mulai dengan logika keluaran utama. Diambil
$tree
array hirarkis sekarang , kode akhirnya terlihat seperti berikut:Penampilan let pertama ke dalam
ListDecorator
yang hanya membungkus<ul>
dan<li>
elemen dan memutuskan tentang bagaimana struktur daftar adalah output:Konstruktor mengambil iterator daftar yang sedang dikerjakannya.
inset
hanyalah fungsi pembantu untuk lekukan yang bagus pada keluaran. Sisanya hanyalah fungsi keluaran untuk setiap acara:Dengan mengingat fungsi-fungsi output ini, ini adalah output utama / loop lagi, saya melakukannya selangkah demi selangkah:
Buat root
TreeNode
yang akan digunakan untuk memulai iterasi:Ini
TreeNodesIterator
adalahRecursiveIterator
yang memungkinkan iterasi rekursif melalui satu$root
node. Itu diteruskan sebagai array karena kelas itu membutuhkan sesuatu untuk diiterasi dan memungkinkan penggunaan kembali dengan satu set turunan yang juga merupakan arrayTreeNode
elemen.Ini
RecursiveListIterator
adalahRecursiveIteratorIterator
yang menyediakan acara tersebut. Untuk memanfaatkannya, hanyaListDecorator
perlu disediakan (kelas di atas) dan ditugaskan denganaddDecorator
:Kemudian semuanya diatur ke
foreach
atasnya dan mengeluarkan setiap node:Seperti yang ditunjukkan contoh ini, seluruh logika output dikemas dalam
ListDecorator
kelas dan single iniforeach
. Seluruh traversal rekursif telah sepenuhnya dikemas ke dalam iterator rekursif SPL yang menyediakan prosedur bertumpuk, yang berarti secara internal tidak ada panggilan fungsi rekursi yang dilakukan.Berbasis peristiwa
ListDecorator
memungkinkan Anda mengubah keluaran secara khusus dan menyediakan beberapa jenis daftar untuk struktur data yang sama. Bahkan dimungkinkan untuk mengubah input karena data array telah dienkapsulasiTreeNode
.Contoh kode lengkap:
Outpupt:
Demo (varian PHP 5.2)
Varian yang mungkin adalah iterator yang melakukan iterasi atas apa pun
RecursiveIterator
dan memberikan iterasi atas semua peristiwa yang dapat terjadi. Sebuah switch / case di dalam foreach loop kemudian dapat menangani kejadian tersebut.Terkait:
sumber
Nah, pertama-tama saya akan mengubah array lurus dari pasangan nilai kunci menjadi array hierarki
Itu akan dapat mengubah array datar dengan parent_id dan id menjadi hierarki:
Kemudian, buat saja fungsi rendering:
sumber
Meskipun solusi Alexander-Konstantinov mungkin tampak tidak mudah untuk dibaca pada awalnya, namun solusi tersebut sangat jenius dan secara eksponensial lebih baik dalam hal kinerja, ini seharusnya dipilih sebagai jawaban terbaik.
Terima kasih sobat, saya membuat patokan untuk menghormati Anda untuk membandingkan 2 solusi yang disajikan dalam posting ini.
Saya memiliki pohon datar @ 250k dengan 6 level yang harus saya konversi dan saya sedang mencari cara yang lebih baik untuk melakukannya dan menghindari iterasi rekursif.
Rekursi vs Referensi:
Outputnya berbicara sendiri:
sumber
Nah, untuk mengurai menjadi UL dan LI, itu akan menjadi seperti:
Tetapi saya ingin melihat solusi yang tidak mengharuskan Anda untuk berulang-ulang melalui array begitu sering ...
sumber
Inilah yang saya dapatkan:
keluaran:
sumber
Hubungan induk-anak bersarang Array
Ambil semua record dari database dan membuat array bersarang.
Cetak data Kategori dan Subkategori dalam format json
sumber
$ aa = $ this-> parseTree ($ tree);
sumber
Pertanyaan lama, tetapi saya juga harus melakukan ini dan contoh dengan rekursi membuat saya sakit kepala. Dalam database saya, kami memiliki
locations
tabel, yang merupakanloca_id
PK (Anak) dan referensi mandiriloca_parent_id
(Induk).Tujuannya adalah untuk merepresentasikan struktur ini dalam HTML. Permintaan sederhana dari couyrse mengembalikan data adalah beberapa urutan tetap tetapi saya menemukan tidak cukup baik untuk menampilkan data tersebut secara alami. Yang benar-benar saya inginkan adalah penanganan berjalan pohon Oracle
LEVEL
untuk membantu tampilan.Saya memutuskan untuk menggunakan gagasan 'jalur' untuk mengidentifikasi setiap entri secara unik. Sebagai contoh:
Menyortir larik berdasarkan jalur akan mempermudah proses untuk tampilan yang bermakna.
Saya menyadari bahwa penggunaan array dan jenis asosiatif adalah curang karena menyembunyikan kompleksitas rekursif dari operasi, tetapi bagi saya ini terlihat lebih sederhana:
sumber
Cara Membuat Tampilan dan Menu Pohon Dinamis
Langkah 1: Pertama kita akan membuat tabel treeview di database mysql. tabel ini berisi empat kolom.id adalah id tugas dan nama adalah nama tugas.
Langkah 2: Metode rekursif tampilan pohon yang telah saya buat di bawah metode createTreeView () pohon yang memanggil rekursif jika id tugas saat ini lebih besar dari id tugas sebelumnya.
Langkah 3: Buat file indeks untuk menampilkan tampilan struktur pohon. Ini adalah file utama dari contoh treeview di sini kita akan memanggil metode createTreeView () dengan parameter yang diperlukan.
Langkah 4: Buat file CSS style.css Di sini kita akan menulis semua kelas terkait css, saat ini saya menggunakan daftar pesanan untuk membuat tampilan pohon. Anda juga dapat mengubah jalur gambar di sini.
Keterangan lebih lanjut
sumber