Этой заметкой, хочу начать серию посвященную алгоритмам и приемам программирования, и решению часто возникающих программистских задач.
И начну с задачи, построения древовидного списка.
Один из наиболее встречающихся методов решения - это построение рекурсии.



Итак, разберем этот метод на примере некоей структуры, хранящейся в таблице базы данных, и имеющей поле уникального идентификатора записи (Uid) и поле родительского идентификатора (ParentId)
Рабочая заготовка функции построения массива - списка (реализация на PHP, база MySQL):

function build_tree(&$tree, $parentID = 0, $level=-1){
$sql = "SELECT *
FROM some_table
WHERE parentID = ".$parentID."
ORDER BY name";
$q = mysql_query($sql);
$level += 1;
while ($row = mysql_fetch_assoc($q)){
$tmp_i = count($tree);
$tree[] = $row;
$tree[$tmp_i]["level"] = $level;
$tree = build_tree($tree, $row["Uid"], $level);
}
return $tree;
}

В результате мы получаем массив $tree - представляющий собой развернутое дерево связанных элементов, хранящихся в некоей таблице some_table, отсортированное по наименованию (полю name). При этом в массиве хранится также уровень вложенности каждого элемента (параметр level), который вычисляется в самой процедуре.
Допущения: элементы верхнего уровня в БД имеют parentID = 0, в итоговом массиве им соответствует level = 0


Естественно, подобным образом можно построить обработку некоторого массива данных (вместо обработки таблицы БД), но для наглядности и простоты я привел пример именно с БД, к тому же это наиболее часто встречающаяся задача.

google.com bobrdobr.ru del.icio.us technorati.com linkstore.ru news2.ru rumarkz.ru memori.ru moemesto.ru

Понравился пост подпишись по RSS 

4 ответов в “Рекурсивный алгоритм построения дерева”
  1. wmas ответил:

    hi! Ну, уж если мы используем массив, то думаю было бы менее ресурсоемко сразу считать необходимые данные в массив и потом обрабатывать его. А так может получиться достаточно много запросов к БД, что при наших хостингах не самое лучшее решение ;) Хотя, это лишь моё имхо.

  2. admin ответил:

    wmas
    Да, всю обработку, безусловно, лучше вести в массиве, но в данном случае я преследовал цель максимально наглядно показать сам принцип, поэтому решил, что человеку маломальски знакомому с SQL будет легче воспринять такой вариант :)

  3. reggae-man ответил:

    А как сделать с ассоциативным массивом? на пример
    Array
    (
    [1] => Array
    (
    [item] => 40
    [2] => Array
    (
    [item] => 41
    [5] => Array
    (
    [item] => 43
    )

    [6] => Array
    (
    [item] => 44
    )

    )

    [3] => Array
    (
    [item] => 42
    [7] => Array
    (
    [item] => 46
    )

    )

    )

    )

  4. Хромов Максим ответил:

    Рекурсия в базе хорошо! Но что делать, если массив уже пришел целый предположительно из вне!?
    А вот как раз ничего и не остается как крутить циклы для построения дерева из массива.

    Вот Вам решение на рассмотрение одного из моих вариантов. Не стал я упрощать код - времени особо нет, но код рабочий (раз 30 апач рестартил из-за бесконечных циклов :) ). Лучше канешь сделать хороший класс - парсер, но … не сейчас.

    <?php

    echo “\n”;
    echo “Recurse Tree Demo\n”;
    //echo “Recurse Tree Demo“;

    $arr = array();
    $arr[0]['uid'] = 1;
    $arr[0]['parent'] = 0;
    $arr[0]['name'] = ‘main 1′;

    $arr[1]['uid'] = 2;
    $arr[1]['parent'] = 0;
    $arr[1]['name'] = ‘main 2′;

    $arr[2]['uid'] = 3;
    $arr[2]['parent'] = 0;
    $arr[2]['name'] = ‘main 3′;

    $arr[3]['uid'] = 4;
    $arr[3]['parent'] = 1;
    $arr[3]['name'] = ’sub 1 main 1′;

    $arr[4]['uid'] = 5;
    $arr[4]['parent'] = 1;
    $arr[4]['name'] = ’sub 2 main 1′;

    $arr[5]['uid'] = 6;
    $arr[5]['parent'] = 2;
    $arr[5]['name'] = ’sub 1 main 2′;

    $arr[6]['uid'] = 7;
    $arr[6]['parent'] = 2;
    $arr[6]['name'] = ’sub 2 main 2′;

    $arr[7]['uid'] = 8;
    $arr[7]['parent'] = 3;
    $arr[7]['name'] = ’sub 1 main 3′;

    $arr[8]['uid'] = 9;
    $arr[8]['parent'] = 8;
    $arr[8]['name'] = ’supersub 1 sub 1 main 3′;

    $arr[9]['uid'] = 11;
    $arr[9]['parent'] = 10;
    $arr[9]['name'] = ‘not found parent item’;

    echo “Result“;

    function recurseTree (&$tree, &$arr) {

    function rArr (&$tree, &$arr, $i) {
    foreach ($arr as $j => $key1){
    if ( $tree [$i] ['uid'] == $arr [$j] ['parent'] ){
    $c = count( $tree [$i] ['sub'] );
    $tree [$i] ['sub'][] = $arr [$j];
    unset($arr [$j] );
    recurseArr ($tree [$i] ['sub'], $arr);
    return true;
    }
    }
    return false;
    }

    function recurseArr (&$tree, &$arr) {
    foreach ($tree as $i => $key){
    while (rArr($tree, $arr, $i) ) ;
    }
    }

    for ($i=0; $i< count($arr); $i++){
    if ( $arr [$i] ['parent'] == 0 ){
    $tree[] = $arr [$i];
    unset( $arr [$i] );
    }
    }
    recurseArr ($tree, $arr);
    }

    $tree = array();
    recurseTree ($tree, $arr);
    echo “———————-\n”;
    echo “Tree\n”;
    echo “\n”;
    print_r ($tree);
    echo “\n”;
    echo “———————-\n”;
    echo “Arr>\n”;
    echo “\n”;
    print_r ($arr);
    echo “\n”;
    echo “———————-\n”;
    echo “\n”;

    ?>

    ========================
    результат
    ========================

    Tree

    Array
    (
    [0] => Array
    (
    [uid] => 1
    [parent] => 0
    [name] => main 1
    [sub] => Array
    (
    [0] => Array
    (
    [uid] => 4
    [parent] => 1
    [name] => sub 1 main 1
    )

    [1] => Array
    (
    [uid] => 5
    [parent] => 1
    [name] => sub 2 main 1
    )

    )

    )

    [1] => Array
    (
    [uid] => 2
    [parent] => 0
    [name] => main 2
    [sub] => Array
    (
    [0] => Array
    (
    [uid] => 6
    [parent] => 2
    [name] => sub 1 main 2
    )

    [1] => Array
    (
    [uid] => 7
    [parent] => 2
    [name] => sub 2 main 2
    )

    )

    )

    [2] => Array
    (
    [uid] => 3
    [parent] => 0
    [name] => main 3
    [sub] => Array
    (
    [0] => Array
    (
    [uid] => 8
    [parent] => 3
    [name] => sub 1 main 3
    [sub] => Array
    (
    [0] => Array
    (
    [uid] => 9
    [parent] => 8
    [name] => supersub 1 sub 1 main 3
    )

    )

    )

    )

    )

    )

    ———————-
    Arr>

    Array
    (
    [9] => Array
    (
    [uid] => 11
    [parent] => 10
    [name] => not found parent item
    )

    )
    ===================================
    Извините, если что не так! :)

Оставить комментарий