база данных — не удается отобразить все дерево в предварительном порядке обхода в переполнении стека

У меня есть таблица в моей базе данных, которая содержит много генеалогических деревьев.

-----------------------------
- id  name              parent_id
-----------------------------
- 1   grandfather       NULL
- 2   father            1
- 3   uncle             1
- 4   son               2
- 5   brother           2
- 6   cousin's dauther  7
- 7   cousin            8
- 8   auntie            1

Проблема в том, что я не могу показать все имена из-за крайнего случая:

-Когда у меня есть человек с parent_id, который больше, чем его parent_id родителя
(см. дочь двоюродного брата)

Я использую эти запросы, чтобы получить таблицу:

    $sql = "SELECT p1.id, p1.name, p1.parent_id FROM pariente p1
ORDER BY p1.parent_id";
$result = $conn->query($sql);

Проблема в том, что если я использую «ORDER BY parent_id», то «двоюродный брат двоюродного брата» не будет отображаться, а если я использую «ORDER BY id», то «двоюродный брат» не будет отображаться.

Я использую эти функции, чтобы превратить дерево в массив и нарисовать его:

        function make_tree($data, $root) {
$tree = [];
foreach ($data as $node) {
insert($tree, $node);
}

return $tree;
}

function insert(&$root, &$node) {
if (!$root) {
$root = $node;
}
else if ($root["id"] === $node["parent_id"]) {
$root["children"][] = $node;
}
else if (array_key_exists("children", $root)) {
foreach ($root["children"] as &$c) {
if (insert($c, $node)) {
break;
}
}
}
}

function preorder2(&$root) {
if ($root) {
echo "<li>";
echo $root["name"];

if (array_key_exists("children", $root)) {
echo "<ul>";
foreach ($root["children"] as $c) {
preorder2($c);
}
echo "</ul>";
}
echo "</li>";
}
}
?>

И после того, как я использую это для вызова функций:

<div>

<?php
while( $row = mysqli_fetch_assoc( $result)){
$resguard[] = $row;
}
$tree = make_tree($resguard);
preorder2($tree);
?>
</div>

3

Решение

Однажды у меня была похожая проблема, и вот как я ее исправил.

  1. Итерируйте по набору данных, помещая каждый узел в ваш массив, и следите за тем, что вы хотите сделать своим корневым узлом.

  2. Итерация по массиву. Для каждого узла, где parent_id не равен NULL, ищите родительский узел по id и добавьте текущий узел как дочерний. Там нет необходимости использовать рекурсию при построении дерева.

1

Другие решения

В конце концов, я считаю, что я не получил более точного ответа, но это заставило меня задуматься, и я решил проблему (все еще используя способ, которым ggorlen показывает дерево).

Сначала это запросы:

$sql = "SELECT p1.id, p2.name, p2.id as minor, p2.name FROM pariente p1 INNER JOIN pariente p2 ON p1.id = p2.parent_id ORDER BY p1.id";
$result = $conn->query($sql);

$sql2 = "SELECT p1.id, p1.nombre, p1.padre_id FROM pariente p1 WHERE p1.padre_id IS NULL ORDER BY p1.id";
$raices = $conn->query($sql2);

Функции:

        function make_tree($resguardo, $root){
$tree = [];
$tree = $root;
foreach ($resguardo[$root["id"]] as $node) {
add($tree, $node, $resguardo);
}
return $tree;
}

function add(&$root, &$children, $resguardo){
$root["children"][$children["minor"]] = $children;

$flag= false;
if (isset($resguardo[$children["minor"]])) {
$flag = true;
}

if ($flag == false){
return;
} else {
foreach ($resguardo[$children["minor"]] as $child) {
agregar($root["children"][$children["minor"]], $child, $resguardo);
}
}
}

function preorder2(&$root) {
if ($root) {
echo "<li>";
echo '<a href="">';
echo $root["name"];
echo "</a>";

if (array_key_exists("children", $root)) {
echo "<ul>";
foreach ($root["children"] as $c) {
preorder2($c);
}
echo "</ul>";
}
echo "</li>";
}
}

И я называю их здесь:

while( $row = mysqli_fetch_assoc($result)){
$resguardo[$row["id"]][] = $row;
}
while( $root = mysqli_fetch_assoc( $roots)){
echo '<ul>';
$tree = make_tree($resguardo, $root);
preorder2($tree);
echo "</ul>";
}

Большое спасибо вам обоим, я бы никогда не решил это без вашей помощи.

0

По вопросам рекламы [email protected]