За последние 24 часа нас посетил 17771 программист и 1655 роботов. Сейчас ищут 1237 программистов ...

И снова про деревья

Тема в разделе "PHP и базы данных", создана пользователем Vitas, 18 фев 2008.

  1. Vitas

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

    С нами с:
    7 фев 2006
    Сообщения:
    595
    Симпатии:
    0
    Адрес:
    Новосибирск, Академгородок
    Всё-таки, мысли о деревьях не дают мне покоя. :)

    Вчера пришла такая мысль: во время добавления нового узла, рекурсивно выбрать узлы и отсортировать их так, как они должны отображаться.

    Структура базы данных:
    [sql]CREATE TABLE `tree` (
    `id` int auto_increment, -- ID узла
    `pid` int, -- ID родителя
    `sort` int, -- Сортировочное поле
    `childs` int, -- Количество "непосредственных детей"
    `level` int, -- Уровень
    PRIMARY KEY (`id`)
    )[/sql]
    Здесь, поле `sort` и есть то поле, по которому происходит сортировка.

    Пересортировка дерева:
    PHP:
    1. <?
    2.  
    3. // Классический вывод дерева, только в нашем случае он возвращает массив ID'шников
    4. function get($pid = 0, $ids = array()) {
    5.     $result = mysql_query("SELECT id, childs FROM tree WHERE pid = $pid ORDER BY id");
    6.     while ($row = mysql_fetch_object($result)) {
    7.         $ids[] = $row->id;
    8.         if ($row->childs) {
    9.             $ids = array_merge($ids, get($row->id));
    10.         }
    11.     }
    12.     return $ids;
    13. }
    14.  
    15. $ids = join(", ", get());
    16. mysql_query("SET @i = 0");
    17. // Вся фишка в этом запросе, в котором мы нумеруем узлы в том порядке, в котором они должны отображаться
    18. mysql_query("UPDATE tree SET sort = (@i := @i + 1) ORDER BY FIELD(id, $ids)");
    19.  
    20. ?>
    Пересортировку необходимо делать только если мы добавляем некорневой узел.

    В итоге, чтобы вывести дерево достаточно выполнить запрос:
    [sql]SELECT * FROM tree ORDER BY sort[/sql]

    Ну как? :)

    Сильно не ругайте, я ещё даже не студент. :-Р
     
  2. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    проверять лень.
    1 и 2 - потомки 0.
    3,4 и 5,6 - соответственно потомки 1 и 2.
    7,8 9,10 11,12 13,14 - соответственно потомки.

    как будет выглядеть поле сорт для каждого и как вывести ветвь 3?
     
  3. Vitas

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

    С нами с:
    7 фев 2006
    Сообщения:
    595
    Симпатии:
    0
    Адрес:
    Новосибирск, Академгородок
    Код (Text):
    1. sort | id
    2. 1    | 1
    3. 2    | 3
    4. 3    | 7
    5. 4    | 8
    6. 5    | 4
    7. 6    | 9
    8. 7    | 10
    9. 8    | 2
    10. 9    | 5
    11. 10   | 11
    12. 11   | 12
    13. 12   | 6
    14. 13   | 13
    15. 14   | 14
    Ты чего-то такого хотел?

    Выбрать ветку 3 можно классически - рекурсивно, а можно так:
    [sql]SELECT @pid := pid, @pos := sort FROM tree WHERE id = 3;
    SELECT @next_pos := sort FROM tree WHERE pid = @pid AND id > 3 ORDER BY sort LIMIT 1;
    SELECT * FROM tree WHERE sort > @pos AND sort < @next_pos ORDER BY sort;
    -- TODO: предусмотреть обработку NULL-значений[/sql]

    Хочу добавить: цель этого алгоритма - не выбор веток, а быстрый вывод всего или части дерева.
     
  4. armadillo

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

    С нами с:
    6 апр 2007
    Сообщения:
    2.380
    Симпатии:
    0
    Адрес:
    Russia, Moscow
    часть дерева - это что?
    pid - это что?

    обрывками разговаривать и вытягивать неприятно.
     
  5. Vitas

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

    С нами с:
    7 фев 2006
    Сообщения:
    595
    Симпатии:
    0
    Адрес:
    Новосибирск, Академгородок
    pid - parent id
    Часть дерева - буквально, "кусок" дерева. Зачем жто нужна? Навеяло длиннющим деревом комментариев на Хабре, "куски" дерева нужны для пагинации.
     
  6. Vitas

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

    С нами с:
    7 фев 2006
    Сообщения:
    595
    Симпатии:
    0
    Адрес:
    Новосибирск, Академгородок
    Спрашиваете обрывками - отвечаю обрывками.