За последние 24 часа нас посетили 17853 программиста и 1606 роботов. Сейчас ищут 1456 программистов ...

Построение иерархического дерева

Тема в разделе "Прочие вопросы по PHP", создана пользователем ZeiN, 31 авг 2012.

  1. ZeiN

    ZeiN Активный пользователь

    С нами с:
    12 окт 2011
    Сообщения:
    12
    Симпатии:
    0
    Здравствуйте, натолкните на мысль по реализации.
    Задача такова. Есть элементы, у которых есть массив родителей
    Код (Text):
    1.  
    2. Элемент 4
    3. (
    4.     [0] => Элемент 1
    5.     [1] => Элемент 2
    6.     [2] => Элемент 3
    7. )
    Код (Text):
    1. Элемент 6
    2. (
    3.     [0] => Элемент 1
    4.     [1] => Элемент 2
    5.     [2] => Элемент 5
    6. )
    Должно выглядеть это так:
    Код (Text):
    1. Элемент 1--Элемент 2--Элемент 3--Элемент 4
    2.                |
    3.          Элемент 5 -- Элемент N
    4.                |
    5.          Элемент 6
    Вложенность неизвестна.

    Как зная что родитель элемента 6 - элемент 5 добавить к нему потомка, ведь мы не знаем полный путь?

    Или как найти полный путь к текущему элементу?
    Заранее спасибо.
     
  2. Ke1eth

    Ke1eth Активный пользователь

    С нами с:
    16 мар 2012
    Сообщения:
    1.073
    Симпатии:
    11
    Адрес:
    заблудилса
  3. ZeiN

    ZeiN Активный пользователь

    С нами с:
    12 окт 2011
    Сообщения:
    12
    Симпатии:
    0
    А я разве что-то писал о MySQL? Причем тут Nested sets?
    Пытался обойти массив через array_walk_recursive, сравнивая текущий ключ с известным родителем, но не знаю как положить элемент в нужное место, а на сервере с php 5.4 нельзя использовать ссылки, да с вложенными массивами он не работает...

    Добавлено спустя 35 минут 55 секунд:
    Немного упрощу. Дано:
    Код (Text):
    1. $hierarchy = array(
    2.             'Элемент 1'=>array(
    3.                 'Элемент 2'=>array(),
    4.                 'Элемент 3'=>array(),
    5.             ),
    6.         );
    7. $element = 'Элемент 4';
    8. $parent = 'Элемент 3';
    Надо пройтись по массиву $hierarchy и получить такое:
    Код (Text):
    1. $hierarchy = array(
    2.             'Элемент 1'=>array(
    3.                 'Элемент 2'=>array(),
    4.                 'Элемент 3'=>array(
    5.                     'Элемент 4'=>array()
    6.                 ),
    7.             ),
    8.         );
     
  4. Tmin10

    Tmin10 Активный пользователь

    С нами с:
    21 ноя 2009
    Сообщения:
    20
    Симпатии:
    0
    Советую написать класс узла, а там дальше использовать рекурсивный поиск и добавление новых элементов.
     
  5. krow7

    krow7 Активный пользователь

    С нами с:
    12 авг 2009
    Сообщения:
    398
    Симпатии:
    0
    Адрес:
    из Азии
    По сути ваша задача к поиску элемента в дереве и добавления к нему листа, теория графов. Мне эти пары не нравились, потому что были скучными, и я ничерта не запомнил :D
    Накатал маленько, посмотрите (в листинге все объяснено и вроде бы предельно понятно :)
    Код (PHP):
    1. <?php
    2. class Element
    3. {
    4.     public $name;
    5.     public $father;
    6.     public $sons;
    7.     
    8.     public function __construct($n, $f = false)
    9.     {
    10.         $this->name = $n;
    11.         $this->father = $f;
    12.         $this->sons = array();
    13.         if($f !== false)
    14.         {
    15.             $f->addSon($this);
    16.         }
    17.     }
    18.     
    19.     public function addSon($t)
    20.     {
    21.         array_push($this->sons, $t);
    22.     }
    23. }
    24.  
    25. // функция принимает имя для поиска и стартовый элемент. обход по детям
    26. function SearchByName($sname, Element $elem)
    27. {
    28.     if($elem->name == $sname)
    29.     {
    30.         return $elem;
    31.         }
    32.     else
    33.     {
    34.         foreach($elem->sons as $val)
    35.         {
    36.             return SearchByName($sname, $val);
    37.         }
    38.     }
    39. }
    40.  
    41. /*
    42. Ситуация такая: 1 - самый главный папочка, 2, 3, 4 - его дети, причему 2 есть дети: 5 и 6, а у 3 - сынок 7.
    43. Пусть у нас есть непосредственная ссылка на главного папочку, $god
    44. Хотим заделать ребеночка элементу 7 с именем Новорожденный.
    45. */
    46. $list = array();
    47. $list['a'] = new Element('1');    // Отец Всех на Свете
    48. $list['b'] = new Element('2', $list['a']);
    49. $list['c'] = new Element('3', $list['a']);
    50. $list['d'] = new Element('4', $list['a']);
    51. $list['e'] = new Element('5', $list['b']);
    52. $list['f'] = new Element('6', $list['b']);
    53. $list['g'] = new Element('7', $list['c']);
    54. $god = $list['a'];
    55. $found = SearchByName('7', $god);
    56. $littleboy = new Element('Новорожденный', $found); 
     
  6. krow7

    krow7 Активный пользователь

    С нами с:
    12 авг 2009
    Сообщения:
    398
    Симпатии:
    0
    Адрес:
    из Азии
    Долго ковырялся с ссылками, но вроде получилось с массивами, как вы описывали в своем посте :D
    Код (PHP):
    1. <?php
    2. $content = array
    3. (
    4.     '1'    =>    array
    5.     (
    6.         '2'    =>    array
    7.         (
    8.             '7'    =>    array(),
    9.         ),
    10.         '3'    =>    array(),
    11.     ),
    12.     
    13.     '4'    =>    array
    14.     (
    15.         '5'    =>    array(),
    16.     ),
    17.     
    18.     '6'    =>    array(),
    19. );
    20. /*
    21. нулевое поколение            пусто
    22. первое поколение     1        4        6
    23. второе поколение    2 3        5
    24. третье поколение    7
    25. */
    26.  
    27. function &SearchByName($sname, &$array)
    28. {
    29.     if($array != false)
    30.     {
    31.         foreach($array as $key    =>    $val)
    32.         {
    33.             if($key == $sname)
    34.             {
    35.                 return $array[$key];
    36.             }
    37.             else
    38.             {
    39.                 return SearchByName($sname, $array[$key]);
    40.             }
    41.         }
    42.     }
    43.     else
    44.     {
    45.         return false;
    46.     }
    47. }
    48.  
    49. $found = &SearchByName('7', $content);
    50. $found['8'] = array();
    51. print_r($content);
    52.  
    Амперсанды перед функцией означают, что функция вернет ссылку на элемент. Амперсанды перед массивом - ну понятно :)
     
  7. ZeiN

    ZeiN Активный пользователь

    С нами с:
    12 окт 2011
    Сообщения:
    12
    Симпатии:
    0
    Все чуть чуть сложнее. Если бы были ссылки, все элементарно делается через array_walk_recursive, но на сервере php 5.4, где передача по ссылке уже убрана...
     
  8. Ke1eth

    Ke1eth Активный пользователь

    С нами с:
    16 мар 2012
    Сообщения:
    1.073
    Симпатии:
    11
    Адрес:
    заблудилса
    странно, но работаеть ведь:
    Код (PHP):
    1. % php --version
    2. PHP 5.4.4--pl0-gentoo (cli) (built: Jun 15 2012 11:01:47) 
    3. Copyright (c) 1997-2012 The PHP Group
    4. Zend Engine v2.4.0, Copyright (c) 1998-2012 Zend Technologies
    5.  
    6. % cat shit.php 
    7. <?php
    8. function foo(&$var) {
    9.   $var++;
    10. }
    11. $a = 5;
    12. foo($a);
    13. echo $a . "\n";
    14.  
    15. % php shit.php
    16. 6
    кто-то обманывает, ибо Call-time pass by reference это несколько другой случай :)
     
  9. sobachnik

    sobachnik Старожил

    С нами с:
    20 апр 2007
    Сообщения:
    3.380
    Симпатии:
    13
    Адрес:
    Дмитров, МО
    ZeiN, а кто вообще сказал, что ссылки отменены или что их собираются отменять? Не слышал такого. И на оф. сайте - никакой информации об этом не вижу. Вроде никто и не собирался отменять ссылки...
     
  10. ZeiN

    ZeiN Активный пользователь

    С нами с:
    12 окт 2011
    Сообщения:
    12
    Симпатии:
    0
    php сказал :)
    Код (Text):
    1. Fatal error: Call-time pass-by-reference has been removed in /path/test.php on line 11
     
  11. Ke1eth

    Ke1eth Активный пользователь

    С нами с:
    16 мар 2012
    Сообщения:
    1.073
    Симпатии:
    11
    Адрес:
    заблудилса
    как нада:
    Код (PHP):
    1. function myFunc(&$arg) { }
    2. myFunc($var);
    3.  
    как НЕ нада:
    Код (PHP):
    1. function myFunc($arg) { }
    2. myFunc(&$arg);
    3.  
    вот второй пример и есть call-time pass-by-reference.
     
  12. ZeiN

    ZeiN Активный пользователь

    С нами с:
    12 окт 2011
    Сообщения:
    12
    Симпатии:
    0
    спасибо, а то что-то я напутал.