[Php]
<? Php
/**
* Infinite level (subject to the tail node description algorithm restrictions, see tree_parse comments) recursive menu
* Author: selfimip
* Blog: http://blog.csdn.net/lgg201
* Mail: lgg860911@yahoo.com.cn
*/
Define ('max _ NODES ', 3);/* Maximum number of subnodes */
Define ('max _ NODE_INDEX ', MAX_NODES-1);/* maximum index value of the subnode */
Define ('name _ FMT ', 'name-% 08d');/* node content output format string */
/* Tree node data structure */
Define ('K _ id', 'id ');
Define ('K _ name', 'name ');
Define ('K _ CHILD ', 'Children ');
/* Assembled Characters Used for output construction */
Define ('prefix _ top', 'taobao');/* ID of the first node in the first layer */
Define ('prefix _ BOTTOM ', 'taobao');/* identifier of the last subnode of each parent node */
Define ('prefix _ middle', 'delimiter');/* all nodes that are not in the preceding two conditions */
Define ('prefix _ line', 'hangzhou');/* LINE Character of the ancestor node */
Define ('space', '');/* blank placeholder (no link character is displayed for all end nodes )*/
Define ('wide _ space', str_repeat (SPACE, 4);/* WIDE blank placeholder, in order to make the hierarchy of the tree clear */
/**
* Data_build
* Construct a node
* @ Param mixed $ id node id
* @ Param mixed $ is_leaf whether the leaf is
* @ Access public
* @ Return void
*/
Function node_build ($ id, $ is_leaf = FALSE ){
Return array (
K_ID => $ id,
K_NAME => sprintf (NAME_FMT, $ id ),
K_CHILD => $ is_leaf? NULL: array (),
);
}
/**
* Tree_build
* Construct a tree (the number of subnodes of each node in the tree is determined by MAX_NODES)
* @ Param mixed $ tree reference to be returned by datas
* @ Param mixed $ id start ID
* @ Param mixed $ level tree level
* @ Access public
* @ Return void
*/
Function tree_build (& $ datas, & $ id, $ level ){
If ($ level <1) return;
$ Is_leaf = $ level = 1;
$ I =-1;
$ Next_level = $ level-1;
While (++ $ I <MAX_NODES ){
$ Data = node_build ($ id ++, $ is_leaf );
If (! $ Is_leaf)
Tree_build ($ data [K_CHILD], $ id, $ next_level );
Array_push ($ datas, $ data );
}
}
/**
* Node_str
* Output the information of a node.
* @ Param mixed $ string of the returned result (reference to pass the value)
* @ Param mixed $ data node data
* @ Access public
* @ Return void
*/
Function node_str (& $ string, $ data ){
$ String. = sprintf ('% s [% d]', $ data [K_NAME], $ data [K_ID]);
}
/**
* Node_sign
* Outputs the flag of a node.
* @ Param mixed $ string of the returned result (reference to pass the value)
* @ Param mixed $ level current depth
* @ Param mixed $ I index (subscript) of the current node in the parent node)
* @ Access public
* @ Return void
*/
Function node_sign (& $ string, $ level, $ I ){
Switch ($ I ){
Case 0:
$ String. = $ level = 0? PREFIX_TOP: PREFIX_MIDDLE;
Break;
Case MAX_NODE_INDEX:
$ String. = PREFIX_BOTTOM;
Break;
Default:
$ String. = PREFIX_MIDDLE;
Break;
}
}
/**
* Node_prefix
* Output the prefix of a node.
* @ Param mixed $ string of the returned result (reference to pass the value)
* @ Param mixed $ level current depth
* @ Param mixed $ is_last indicates whether all ancestor nodes of the current node (inclusive) are marked as the end node.
* @ Access public
* @ Return void
*/
Function node_prefix (& $ string, $ level, $ is_last ){
If ($ level> 0 ){
$ I = 0;
/* Prefix format: "parent line" ["wide margin" "parent line"...] "wide margin "*/
$ String. = ($ is_last & 1 <($ level-$ I )? SPACE: PREFIX_LINE );
While (++ $ I <$ level)
$ String. = WIDE_SPACE. ($ is_last & 1 <($ level-$ I )? SPACE: PREFIX_LINE );
$ String. = WIDE_SPACE;
}
}
/**
* Node_out
* Output a node
* @ Param mixed $ string of the returned result (reference to pass the value)
* @ Param mixed $ data node data to be processed
* @ Param mixed $ level node depth
* @ Param mixed $ index (subscript) of the I node in the parent node)
* @ Param mixed $ is_last indicates whether all ancestor nodes of the current node (inclusive) are marked as the end node.
* @ Access public
* @ Return void
*/
Function node_out (& $ string, $ data, $ level, $ I, $ is_last ){
/* Handle prefix strings: the connector of the ancestor and blank space */
Node_prefix ($ string, $ level, $ is_last );
/* Process the identifier of the current node */
Node_sign ($ string, $ level, $ I );
/* Process the data information of the current node */
Node_str ($ string, $ data );
/* Append line */
$ String. = "\ n ";
}
/**
* Tree_parse
* Output a tree
* 1. Because $ is_last of the integer type is used as the marker of the ancestor's tail node, the depth of PHP_INT_MAX is supported at most.
* 2. If you need to extend it, correct the Data Type of $ is_last and the verification method.
* @ Param mixed $ string of the returned result (reference to pass the value)
* @ Param mixed $ the tree data to be processed by datas
* @ Param int $ level current processing depth
* @ Param int $ is_last indicates whether all the ancestors of the current depth are marked with the last node.
* @ Access public
* @ Return void
*/
Function tree_parse (& $ string, $ datas, $ level = 0, $ is_last = 0 ){
If (! Is_array ($ datas) | count ($ datas) <1) return;
$ Max_index = count ($ datas)-1;
/* Process all nodes in the current layer */
Foreach ($ datas as $ I =>$ data ){
/* Whether the current node and all its ancestors are marked with the last node */
$ Tmp_is_last = $ is_last <1 | 1 & $ I ==$ max_index;
/* Output current node */
Node_out ($ string, $ data, $ level, $ I, $ tmp_is_last );
/* If there are subnodes, recursive subnodes */
If (is_array ($ data [K_CHILD]) &! Emptyempty ($ data [K_CHILD])
Tree_parse ($ string, $ data [K_CHILD], $ level + 1, $ tmp_is_last );
}
}
/* Calculate the actual number of nodes */
Function n_node ($ n, $ s ){
$ Sum = 0;
While ($ n> 0)
$ Sum + = pow ($ s, $ n --);
Return $ sum;
}
/* Calculate the ruage time */
Function ru_time ($ info, $ type ){
Return floatval (sprintf ('% d. % d', $ info [$ type.'. TV _sec '], $ info [$ type.'. TV _usec ']);
}
/* Output resource usage */
Function resource_usage ($ lv, $ nodes, $ cb, $ ce, $ mb, $ me, $ rb, $ re ){
Printf ("\ nresource usage [level: % d, node number: % d]: \ n % 20 s % 0.6fs \ n % 20 s % 0.6fs \ n % 20 s % 0.6fs \ n % 20 s % d byte \ n ",
$ Lv, $ nodes,
'Clock time: ', $ ce-$ cb,
'System cpu: ', ru_time ($ re, 'ru _ stime')-ru_time ($ rb, 'ru _ stime '),
'User cpu: ', ru_time ($ re, 'ru _ utime')-ru_time ($ rb, 'ru _ utime '),
'Memory usage: ', $ me-$ mb );
}
/* Usage */
Function usage ($ cmd ){
Printf ("usage: \ n % s <tree deepth> \ n", $ cmd );
Exit;
}
/* Test the entry function */
Function run (){
Global $ argc, $ argv;
If ($ argc! = 2 | intval ($ argv [1]) <1)
Usage ($ argv [0]);
$ Datas = array ();
$ Id = 1;
$ String = '';
$ Level = intval ($ argv [1]);
/* Initial construction of the test tree */
Tree_build ($ datas, $ id, $ level );
$ Clock_begin = microtime (TRUE );
$ Memory_begin = memory_get_usage ();
$ Rusage_begin = getrusage ();
/* Resolution tree */
Tree_parse ($ string, $ datas );
$ Rusage_end = getrusage ();
$ Memory_end = memory_get_usage ();
$ Clock_end = microtime (TRUE );
/* Output result */
Echo $ string. "\ n ";
Resource_usage ($ level, n_node ($ level, MAX_NODES ),
$ Clock_begin, $ clock_end,
$ Memory_begin, $ memory_end,
$ Rusage_begin, $ rusage_end );
}
/* Execute the entry function */
Run ();
/*
* Local variables:
* Tab-width: 4
* C-basic-offset: 4
* Indent-tabs-mode: t
* End:
*/