Three ways to classify infinite poles (iterations, recursion, references)

Source: Internet
Author: User
There are two ways to classify a generic tree structure:

    • One is the adjacency list, which is the form of the Id,parent ID.

    • The other is nested set, which is the form of left and right values.

The left and right values form query more efficient, no recursion, etc., recommended use, but there is no PID form simple and intuitive, and some old database similar areas and other structural design has been pid This form (seemingly also have the algorithm can be converted, do not do in-depth understanding), so ...

All of the following are the forms of the adjacency list, and the data table format is similar to that of Id,pid,name.

In general, the data are all read from the database, and then assemble the array to achieve, of course, each recursive can query the database, but it will cause the database pressure, and is not easy to encapsulate into methods, not recommended.

For now, there are three ways to implement the Select drop-down menu display style:

1, the first is the most common, the same is the lowest efficiency of the recursive method: is the constant foreach loop recursion.


function GetTreeOptions3 ($list, $pid = 0) {    $options = [];    foreach ($list as $key + $value) {        if ($value [' id '] = = $pid) {//See if it is a child element, or recursively continue querying            $options [$value [' id ']] = $ value[' name '];            Unset ($list [$key]);//Destroy queried, reduce the number of queries at the next recursive            $optionsTmp = $this->gettreeoptions3 ($list, $value [' id ']);//recursion            if (!empty ($OPTIONSTMP)) {                $options = Array_merge ($options, $OPTIONSTMP);    }}} return $options;}


2, the second is the use of the stack, the recursive calculation of the stack, the efficiency is better than the last, but also quite slow. The process is to reverse the array first, then take the top-level array into the stack, start the while loop, first out of the stack to find out if there are no child nodes, if there are child nodes, then this child node into the stack, the next time loop will look at the child nodes, and so on:


function GetTreeOptions2 ($list, $pid = 0) {    $tree = [];    if (!empty ($list)) {        //Reverses the array first, because the top        $list = Array_reverse ($list) is prioritized at the end of the stack;        First remove the top-level to press into the array $stack, and will be removed in the $list        $stack = [];        foreach ($list as $key = + $value) {            if ($value [' pid '] = = $pid) {                Array_push ($stack, $value);                Unset ($list [$key]);            }        while (count ($stack)) {            //First remove the first item from the stack            $info = Array_pop ($stack);            Query the remaining $list that the PID is equal to its ID, which is to find its child node            foreach ($list as $key + $child) {                if ($child [pid] = = $info [' id ']) {
  //If there are child nodes in the stack, the while loop continues to find child nodes of subordinate                    Array_push ($stack,  $child);                    Unset ($list [$key]);                }            Assemble into a drop-down menu format            $tree [$info [' id ']] = $info [' name '];        }    }    return $tree;}


3, using the reference to deal with, this is really ingenious, and the most efficient, can refer to here:


Mr./*** is similar to the following form of data * [*  ' id ' =>1,*  ' pid ' =>0,*  ' items ' =>[*      ' id ' =>2,*      ' pid ' = ' 1 ' *       ..... *  ]*]*/function gettree ($list, $pid = 0) {    $tree = [];    if (!empty ($list)) {        //modify first to list with ID as subscript        $newList = [];        foreach ($list as $k = + $v) {            $newList [$v [' id ']] = $v;        }        Then start assembling into a special format        foreach ($newList as $value) {            if ($pid = = $value [' pid ']) {//First remove top                $tree [] = & $newList [ $value [' id '];            } ElseIf (Isset ($newList [$value [' pid ']]) {//re-determine if the non-top PID is present, if present, then add a field under the array where the PID is located under items, to store itself in                $newList [$ value[' pid ']][' items ' [] = & $newList [$value [' ID '];}            }    }    return $tree;}


Then recursively generate the Select drop-down menu required, due to the special format above, resulting in recursive very fast:


function Formattree ($tree) {    $options = [];    if (!empty ($tree)) {        foreach ($tree as $key = + $value) {            $options [$value [' id ']] = $value [' name '];            if (Isset ($value [' Items '])) {//query whether there are child nodes                $optionsTmp = $this->formattree ($value [' Items ']);                if (!empty ($OPTIONSTMP)) {                    $options = Array_merge ($options, $OPTIONSTMP);    }}} return $options;}


The above three kinds, for the small amount of data, it does not matter which kind, but for the large amount of data is very obvious, with 4,000 regional data test results efficiency comparison:

    • The first method (recursion) takes time: About 8.9441471099854

    • The second method (iteration) takes time: About 6.7250330448151

    • The third method (citation) takes time: About 0.028863906860352

I go, this gap, the third method is really counter-heaven. But again, this is only a one-time read more data, when the amount of data is very small, not necessarily the most efficient, but also by lazy loading and other ways to achieve.

By the way, encapsulate a class, you can add some padding or something. For more details, you can view the following classes:


  1 <?php 2/** 3 * parent_id type tree structure related 4 * There is no need to write static methods, static method parameters too many, so it is more appropriate to modify parameters in the constructor with an instance 5 * need to first remove all the data, and then re-plan the array with this method,  Other ways to query the database on the edge fetch 6 * Test the first method is much faster, it is recommended to use 7 * @author Vishun <nadirvishun@gmail.com> 8 */9 class Tree 11  {12/** 13 * icon */public $icon = ' └ '; 16/** 17 * Fill * */public $blank = ' &nbsp;&nbsp;&nbsp; '; 20/** 21 * Default ID field name * * * $idName = ' id '; 24/** 25 * Default PID field name */Public $pidName = ' pid '; 28/** 29 * Default Name Field name */Public $titleName = ' name '; 32/** 33 * Default child element Field name * */Public $childrenName = ' items '; 36 37/** 38 * constructor that overrides the default field value of * @param array $config */construct ($config = []) 4 2 {!empty ($config)) {$config as $name + = $value) {$thi s-> $name = $value; 46} 47} 48} 49 50/** 51 * method to generate a drop-down menu available Tree List 52 * Tested 4,000 area data time is about 0.02, much faster than the other two methods 53 * The process is to first generate a special tree structure by reference method,  And then through the recursive return to resolve this particular structure of the * @param array $list * @param int $pid * @param int $level * * @return Array         +/-Public function gettreeoptions ($list, $pid = 0, $level = 0) 60 {61//Mr. Cheng is a special size tree 62 $tree = $this->gettree ($list, $pid); 63//re-assemble into select required form $this->formattree ($tree, $level); 65} 66 67/** 68 * The style required to assemble a drop-down menu by recursive parsing of a particular tree structure * @param array $tree A special specification of arrays * @param int $l EVEL * @return Array * * * protected function Formattree ($tree, $level = 0) [$optio NS = [];             if (!empty ($tree)) {$blankStr = Str_repeat ($this->blank, $level). $this->icon; 78  if ($level = = 0) {//For the first time no icons and spaces are required $blankStr = ";") Bayi foreach ($tree as $key = $Value) {$options [$value [$this->idname]] = $blankStr. $value [$this->titlename]; 83 if (Isset ($value [$this->childrenname])) {//query If there are child nodes of $optionsTmp = $this->formattree ($value [$this->childrenname], $level + 1); if (!empty ($OPTIONSTMP)) {$options = Array_merge ($options, $OPTIONSTMP) ; * * * * * * * * * * $options; 92} 93 94/** 95 * Generate a tree structure similar to the sowing format 96 * Using the reference & to Achieve, refer to: http://blog.csdn.net/gxdvip/article/details/2443      4801 * [98 * ' ID ' =>1, * ' pid ' =>0,100 * ' items ' =>[101 * ' id ' =>2,102 * ' pid ' = ' 1 ' 103 * ...     104 *]105 *]106 * @param array $list 107 * @param int $pid 108 * @return array109 */110  protected function Gettree ($list, $pid = 0) 111 {$tree = [];113       if (!empty ($list)) {114//first modified to a list with ID as subscript $newList = [];116 foreach ($list as             $k = $v) {117 $newList [$v [$this->idname]] = $v; 118}119//Then start assembling into special format 120                     foreach ($newList as $value) {121 if ($pid = = $value [$this->pidname]) {122 $tree [] = & $newList [$value [$this->idname]];123} elseif (Isset ($newList [$value] [$this->pidname] ]) {124 $newList [$value [$this->pidname]][$this->childrenname][] = & $newList [$value [$this-&G t;idname]];125}126}127}128 return $tree; 129}130 131/**132 * The second method, using the access stack iteration to achieve 133 * tested 4,000 area data time is about 6.5s, slower 134 * @param $list 135 * @param int $pid 136 * @param int         $level 137 * @return array138 */139 public Function getTreeOptions2 ($list, $pid = 0, $level = 0) 140 {141  $tree = [];142       if (!empty ($list)) {143 144//Reverses the array first, since the upper 145 is limited by the late stack $list = Array_reverse ($list); 146 First remove the top-level to press into the array $stack, and delete the 147 in the $list $stack = [];148 foreach ($list as $key + = $valu E) {149 if ($value [$this->pidname] = = $pid) {Array_push ($stack, [' data '] = $             Value, ' level ' = $level]);//record the hierarchy to make it easy to fill the space 151 unset ($list [$key]); 152}153 }154 while (count ($stack)) {155//First out of stack 156 $info = Array_pop ($stack); 1                     57//Query the remaining $list the PID is equal to its ID, which is to find its child node 158 foreach ($list as $key + $child) {159 if ($child [$this->pidname] = = $info [' Data '] [$this->idname]) {160//If a child node is in the stack, WHI The Le Loop continues to look for child nodes of subordinate 161 Array_push ($stack, [' data ' = ' $child, ' level ' = ' + ' $info [' level '] + 1]); 16                       2  Unset ($list [$key]); 163}164}165//assemble into drop-down menu format 166 $bla Nkstr = Str_repeat ($this->blank, $info [' Level ']).                 $this->icon;167 if ($info [' level '] = = 0) {//first time without icons and spaces 168 $blankStr = '; 169 }170 $tree [$info [' Data '] [$this->idname]] = $blankStr.      $info [' Data '] [$this->titlename];171}172}173 return $tree; 174}175 176/**177 * The third normal list to drop-down menu available Tree list 178 * Tested 4,000 area data time is about 8.7s, slowest 179 * @param array $list original array @param int $pid start PID1 Bayi * @param int $level start level 182 * @return array183 */184 public Function getTreeOptions3 ($list, $pid = 0 , $level = 0) 185 {186 $options = [];187 if (!empty ($list)) {188 $blankStr = str_repeat ($th Is->blank, $level).     $this->icon;189 if ($level = = 0) {//first time without icons and spaces $blankStr = '; 191        }192 foreach ($list as $key = = $value) {193 if ($value [$this->pidname] = = $pid)                     {194 $options [$value [$this->idname]] = $blankStr. $value [$this->titlename];195 Unset ($list [$key]);//Destroy queried, reduce the number of queries for the next recursive 196 $optionsTmp = $this->gettreeoptions3 ($list, $value [$  This->idname], $level + 1);//Recursive 197 if (!empty ($OPTIONSTMP)) {198 $options =         Array_merge ($options, $OPTIONSTMP); 199}200}201}202}203 return $options; 204}205}


View Code

The above record, if reproduced please indicate the source address

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.