php实现父子评论,关于php:将一系列父子关系转换为层次树?

s?

我感觉涉及到递归,但是我还没有足够清醒地思考它。

这需要一个非常基本的递归函数来将子/父对解析为树结构,并需要另一个递归函数来将其打印出来。只有一个函数就足够了,但是为了清楚起见,这里有两个(可以在此答案的末尾找到一个组合函数)。

首先初始化子对/父对对的数组:

$tree = array(

'H' => 'G',

'F' => 'G',

'G' => 'D',

'E' => 'D',

'A' => 'E',

'B' => 'C',

'C' => 'E',

'D' => null

);

然后将数组解析为分层树结构的函数:

function parseTree($tree, $root = null) {

$return = array();

# Traverse the tree and search for direct children of the root    foreach($tree as $child => $parent) {

# A direct child is found        if($parent == $root) {

# Remove item from tree (we don't need to traverse this again)            unset($tree[$child]);

# Append the child into result array and parse its children            $return[] = array(

'name' => $child,

'children' => parseTree($tree, $child)

);

}

}

return empty($return) ? null : $return;

}

和遍历该树以打印出无序列表的函数:

function printTree($tree) {

if(!is_null($tree) && count($tree) > 0) {

echo '

';

foreach($tree as $node) {

echo '

'.$node['name'];

printTree($node['children']);

echo '

';

}

echo '

';

}

}

以及实际用法:

$result = parseTree($tree);

printTree($result);

这是$result的内容:

Array(

[0] => Array(

[name] => D

[children] => Array(

[0] => Array(

[name] => G

[children] => Array(

[0] => Array(

[name] => H

[children] => NULL

)

[1] => Array(

[name] => F

[children] => NULL

)

)

)

[1] => Array(

[name] => E

[children] => Array(

[0] => Array(

[name] => A

[children] => NULL

)

[1] => Array(

[name] => C

[children] => Array(

[0] => Array(

[name] => B

[children] => NULL

)

)

)

)

)

)

)

)

如果需要更高的效率,可以将这些功能合并为一个,并减少迭代次数:

function parseAndPrintTree($root, $tree) {

$return = array();

if(!is_null($tree) && count($tree) > 0) {

echo '

';

foreach($tree as $child => $parent) {

if($parent == $root) {

unset($tree[$child]);

echo '

'.$child;

parseAndPrintTree($child, $tree);

echo '

';

}

}

echo '

';

}

}

您只会在这样小的数据集上保存8次迭代,但在较大的数据集上可能会有所作为。

塔图如何更改printTree函数以不直接回显树html,而是将所有输出html保存到变量中并返回?谢谢

嗨,我认为函数声明必须为parseAndPrintTree($ tree,$ root = null),递归调用应为parseAndPrintTree($ child,$ tree);最好的祝福

生成树的另一个功能(不涉及递归,而是使用引用):

$array = array('H' => 'G', 'F' => 'G', ..., 'D' => null);

function to_tree($array)

{

$flat = array();

$tree = array();

foreach ($array as $child => $parent) {

if (!isset($flat[$child])) {

$flat[$child] = array();

}

if (!empty($parent)) {

$flat[$parent][$child] =& $flat[$child];

} else {

$tree[$child] =& $flat[$child];

}

}

return $tree;

}

返回这样的层次结构数组:

Array(

[D] => Array(

[G] => Array(

[H] => Array()

[F] => Array()

)

...

)

)

使用递归功能可以轻松地将其打印为HTML列表。

+1-非常聪明。尽管我发现递归解决方案更合乎逻辑。但我确实更喜欢您函数的输出格式。

@Eric更合乎逻辑吗?我不敢苟同。递归没有逻辑性; OTOH在解析递归函数/调用时存在严重的认知开销。如果没有显式的堆栈分配,则ID每天都会在递归上进行迭代。

将$tree中的平面结构转换为层次结构的另一种更简化的方法。只需一个临时数组即可公开它:

好。

// add children to parents

$flat = array(); # temporary arrayforeach ($tree as $name => $parent)

{

$flat[$name]['name'] = $name; # self    if (NULL === $parent)

{

# no parent, is root element, assign it to $tree        $tree = &$flat[$name];

}

else

{

# has parent, add self as child        $flat[$parent]['children'][] = &$flat[$name];

}

}

unset($flat);

这就是将层次结构放入多维数组的全部步骤:

好。

Array

(

[children] => Array

(

[0] => Array

(

[children] => Array

(

[0] => Array

(

[name] => H

)

[1] => Array

(

[name] => F

)

)

[name] => G

)

[1] => Array

(

[name] => E

[children] => Array

(

[0] => Array

(

[name] => A

)

[1] => Array

(

[children] => Array

(

[0] => Array

(

[name] => B

)

)

[name] => C

)

)

)

)

[name] => D

)

如果要避免递归,则输出的重要性就不那么重要了(对于大型结构而言可能是一个负担)。

好。

我一直想解决输出数组的UL / LI"难题"。难题是,每个项目都不知道孩子是否会跟进或需要关闭多少个前面的元素。在另一个答案中,我已经通过使用RecursiveIteratorIterator并查找getDepth()和我自己编写的Iterator提供的其他元信息来解决该问题:将嵌套集合模型放入

中,但隐藏"闭合"子树。该答案还表明,使用迭代器可以使您非常灵活。

好。

但是,这是一个预先排序的列表,因此不适合您的示例。另外,我一直想为一种标准的树形结构以及HTML的

元素解决此问题。

好。

我提出的基本概念如下:

好。

TreeNode-将每个元素抽象为简单的TreeNode类型,可以提供其值(例如Name)以及是否具有子元素。

TreeNodesIterator-一个能够遍历这些TreeNodes的集合(数组)的RecursiveIterator。这非常简单,因为TreeNode类型已经知道它是否有子级以及哪些子级。

RecursiveListIterator-一个RecursiveIteratorIterator,具有在任何RecursiveIterator上递归地迭代时所需的所有事件:

beginIteration / endIteration-主列表的开始和结束。

beginElement / endElement-每个元素的开始和结束。

beginChildren / endChildren-每个子级列表的开始和结束。

此RecursiveListIterator仅以函数调用的形式提供这些事件。子列表(在列表中很常见)在其父元素内打开和关闭。因此,在相应的endChildren事件之后触发endElement事件。可以对其进行更改或使其可配置,以扩大此类的使用范围。然后将事件作为对装饰器对象的函数调用进行分发,以使事情分开。

好。

ListDecorator-一个"装饰器"类,它只是RecursiveListIterator事件的接收者。

我从主要的输出逻辑开始。采取现在分层的$tree数组,最终代码如下所示:

好。

$root = new TreeNode($tree);

$it = new TreeNodesIterator(array($root));

$rit = new RecursiveListIterator($it);

$decor = new ListDecorator($rit);

$rit->addDecorator($decor);

foreach($rit as $item)

{

$inset = $decor->inset(1);

printf("%s%s

", $inset, $item->getName());

}

首先,让我们看一下ListDecorator,它只是包装

元素,并决定如何输出列表结构:

好。

class ListDecorator

{

private $iterator;

public function __construct(RecursiveListIterator $iterator)

{

$this->iterator = $iterator;

}

public function inset($add = 0)

{

return str_repeat('  ', $this->iterator->getDepth()*2+$add);

}

构造函数采用正在处理的列表迭代器。 inset只是一个帮助函数,用于使输出缩进。其余只是每个事件的输出函数:

好。

public function beginElement()

{

printf("%s

", $this->inset());

}

public function endElement()

{

printf("%s

", $this->inset());

}

public function beginChildren()

{

printf("%s

", $this->inset(-1));

}

public function endChildren()

{

printf("%s

", $this->inset(-1));

}

public function beginIteration()

{

printf("%s

", $this->inset());

}

public function endIteration()

{

printf("%s

", $this->inset());

}

}

考虑到这些输出函数,这是主要的输出总结/循环,我将逐步进行介绍:

好。

$root = new TreeNode($tree);

创建根TreeNode,该根将用于在以下情况下开始迭代:

好。

$it = new TreeNodesIterator(array($root));

此TreeNodesIterator是RecursiveIterator,它允许在单个$root节点上进行递归迭代。它作为数组传递,因为该类需要迭代一些内容,并允许与一组子元素(也是TreeNode元素的数组)一起重用。

好。

$rit = new RecursiveListIterator($it);

此RecursiveListIterator是提供上述事件的RecursiveIteratorIterator。要使用它,只需提供一个ListDecorator(上面的类)并分配给addDecorator:

好。

$decor = new ListDecorator($rit);

$rit->addDecorator($decor);

然后,将所有内容设置为仅foreach并输出每个节点:

好。

foreach($rit as $item)

{

$inset = $decor->inset(1);

printf("%s%s

", $inset, $item->getName());

}

如本示例所示,整个输出逻辑封装在ListDecorator类和单个foreach中。整个递归遍历已完全封装到提供堆栈过程的SPL递归迭代器中,这意味着在内部不执行任何递归函数调用。

好。

基于事件的ListDecorator允许您专门修改输出并为同一数据结构提供多种类型的列表。甚至有可能更改输入,因为数组数据已封装到TreeNode中。

好。

完整的代码示例:

好。

命名空间My;

$ tree = array('H'=>'G','F'=>'G','G'=>'D','E'=>'D','A'=>'E', 'B'=>'C','C'=>'E','D'=> null);

//将孩子添加到父母

$ flat = array(); #临时数组

foreach($ tree作为$ name => $ parent)

{

$ flat [$ name] ['name'] = $ name; #自我

如果(NULL === $ parent)

{

#没有父级,是根元素,将其分配给$ tree

$ tree =&$ flat [$ name];

}

其他

{

#有父母,将自己添加为孩子

$ flat [$ parent] ['children'] [] =&$ flat [$ name];

}

}

未设置($ flat);

TreeNode类

{

受保护的$ data;

公共功能__construct(array $ element)

{

如果(!isset($ element ['name']))

抛出新的InvalidArgumentException('Element无名字。');

if(isset($ element ['children'])&&!is_array($ element ['children']))

抛出新的InvalidArgumentException('元素具有无效的子代。');

$ this-> data = $ element;

}

公共函数getName()

{

返回$ this-> data ['name'];

}

公共函数hasChildren()

{

返回isset($ this-> data ['children'])&& count($ this-> data ['children']);

}

/ **

* @return子TreeNode元素数组

* /

公共功能getChildren()

{

$ children = $ this-> hasChildren()吗? $ this-> data ['children']:array();

$ class = get_call_class();

foreach($ children as&$ element)

{

$ element =新的$ class($ element);

}

unset($ element);

返回$ children;

}

}

TreeNodesIterator类实现 recursiveIterator

{

私有$ nodes;

公共功能__construct(array $ nodes)

{

$ this-> nodes = new  ArrayIterator($ nodes);

}

公共函数getInnerIterator()

{

返回$ this-> nodes;

}

公共功能getChildren()

{

返回新的TreeNodesIterator($ this-> nodes-> current()-> getChildren());

}

公共函数hasChildren()

{

返回$ this-> nodes-> current()-> hasChildren();

}

公共函数rewind()

{

$ this-> nodes-> rewind();

}

公共函数valid()

{

返回$ this-> nodes-> valid();

}

公共函数current()

{

返回$ this-> nodes-> current();

}

公共功能键()

{

返回$ this-> nodes-> key();

}

公共功能next()

{

返回$ this-> nodes-> next();

}

}

RecursiveListIterator类扩展 recursiveIteratorIterator

{

私人元素

/ **

* @var ListDecorator

* /

私人装饰工;

公共功能addDecorator(ListDecorator $ decorator)

{

$ this-> decorator = $ decorator;

}

公共函数__construct($ iterator,$ mode =  recursiveIteratorIterator :: SELF_FIRST,$ flags = 0)

{

父母:: __ construct($ iterator,$ mode,$ flags);

}

私有函数事件($ name)

{

//事件调试代码:printf(" ---%'.- 20s ---(深度:%d,元素:%d) n",$ name,$ this-> getDepth(),@ $ this- > elements [$ this-> getDepth()]);

$ callback = array($ this-> decorator,$ name);

is_callable($ callback)&& call_user_func($ callback);

}

公共函数beginElement()

{

$ this-> event('beginElement');

}

公共函数beginChildren()

{

$ this-> event('beginChildren');

}

公共函数endChildren()

{

$ this-> testEndElement();

$ this-> event('endChildren');

}

私有函数testEndElement($ depthOffset = 0)

{

$ depth = $ this-> getDepth()+ $ depthOffset;

isset($ this-> elements [$ depth])|| $ this-> elements [$ depth] = 0;

$ this-> elements [$ depth] && $ this-> event('endElement');

}

公共功能nextElement()

{

$ this-> testEndElement();

$ this-> event('{nextElement}');

$ this-> event('beginElement');

$ this-> elements [$ this-> getDepth()] = 1;

}

公共函数beginIteration()

{

$ this-> event('beginIteration');

}

公共函数endIteration()

{

$ this-> testEndElement();

$ this-> event('endIteration');

}

}

ListDecorator类

{

私人$ iterator;

公共函数__construct(RecursiveListIterator $ iterator)

{

$ this-> iterator = $ iterator;

}

公共函数插入($ add = 0)

{

return str_repeat('',$ this-> iterator-> getDepth()* 2 + $ add);

}

公共函数beginElement()

{

printf("%s

n",$ this-> inset(1));

}

公共功能endElement()

{

printf("%s

n",$ this-> inset(1));

}

公共函数beginChildren()

{

printf("%s

n",$ this-> inset());

}

公共函数endChildren()

{

printf("%s

n",$ this-> inset());

}

公共函数beginIteration()

{

printf("%s

n",$ this-> inset());

}

公共函数endIteration()

{

printf("%s

n",$ this-> inset());

}

}

$ root = new TreeNode($ tree);

$ it =新的TreeNodesIterator(array($ root));

$ rit =新的RecursiveListIterator($ it);

$ decor =新的ListDecorator($ rit);

$ rit-> addDecorator($ decor);

foreach($ rit作为$ item)

{

$ inset = $ decor-> inset(2);

printf("%s%s  n",$ inset,$ item-> getName());

}

code> pre>

输出:

[cc lang="php"]

D

G

H

F

E

A

C

B

演示(PHP 5.2变体)

好。

一个可能的变体是迭代器,它迭代任何RecursiveIterator并为可能发生的所有事件提供迭代。然后,在foreach循环内的一个switch / case可以处理事件。

好。

有关:

好。

使用RecursiveArrayIterator的嵌套列表

RecursiveIteratorIterator类

好。

好。

此解决方案的设计精良-与前面的示例相比,"简化方式"到底有多精确-似乎是针对同一问题的过度设计的解决方案

@Andre:按封装IIRC的等级划分。在另一个相关的答案中,我有一个完全未封装的代码片段,该片段非常小,因此可能会根据POV进行"更简化"。

@hakre如何修改" ListDecorator"类以将ID添加到从树数组中获取的LI?

@Gangesh:使用节点访问者最容易。 ^^开个玩笑,直截了当是扩展装饰器并编辑beginElement(),获取内部迭代器(有关示例,请参见inset()方法)以及具有id属性的工作。

@hakre谢谢。虐待尝试。

好吧,首先,我将键值对的直接数组转换为层次结构数组

function convertToHeiarchical(array $input) {

$parents = array();

$root = array();

$children = array();

foreach ($input as $item) {

$parents[$item['id']] = &$item;

if ($item['parent_id']) {

if (!isset($children[$item['parent_id']])) {

$children[$item['parent_id']] = array();

}

$children[$item['parent_id']][] = &$item;

} else {

$root = $item['id'];

}

}

foreach ($parents as $id => &$item) {

if (isset($children[$id])) {

$item['children'] = $children[$id];

} else {

$item['children'] = array();

}

}

return $parents[$root];

}

这样可以将具有parent_id和id的平面数组转换为分层数组:

$item = array(

'id' => 'A',

'blah' => 'blah',

'children' => array(

array(

'id' => 'B',

'blah' => 'blah',

'children' => array(

array(

'id' => 'C',

'blah' => 'blah',

'children' => array(),

),

),

'id' => 'D',

'blah' => 'blah',

'children' => array(

array(

'id' => 'E',

'blah' => 'blah',

'children' => array(),

),

),

),

),

);

然后,只需创建一个渲染函数:

function renderItem($item) {

$out ="Your OUtput For Each Item Here";

$out .="

";

foreach ($item['children'] as $child) {

$out .="

".renderItem($child)."

";

}

$out .="

";

return $out;

}

尽管亚历山大·康斯坦丁诺夫的解决方案乍看似乎并不容易理解,但它既是天才,又在性能上成倍地提高了性能,但应该将其选为最佳答案。

感谢队友,我以您为基准进行了比较,以比较本文中介绍的两种解决方案。

我有一棵必须转换的6个级别的@ 250k扁平树,我正在寻找一种更好的方法来避免递归迭代。

递归与参考:

// Generate a 6 level flat tree

$root = null;

$lvl1 = 13;

$lvl2 = 11;

$lvl3 = 7;

$lvl4 = 5;

$lvl5 = 3;

$lvl6 = 1;

$flatTree = [];

for ($i = 1; $i <= 450000; $i++) {

if ($i % 3 == 0)  { $lvl5 = $i; $flatTree[$lvl6] = $lvl5; continue; }

if ($i % 5 == 0)  { $lvl4 = $i; $flatTree[$lvl5] = $lvl4; continue; }

if ($i % 7 == 0)  { $lvl3 = $i; $flatTree[$lvl3] = $lvl2; continue; }

if ($i % 11 == 0) { $lvl2 = $i; $flatTree[$lvl2] = $lvl1; continue; }

if ($i % 13 == 0) { $lvl1 = $i; $flatTree[$lvl1] = $root; continue; }

$lvl6 = $i;

}

echo 'Array count: ', count($flatTree), PHP_EOL;

// Reference function

function treeByReference($flatTree)

{

$flat = [];

$tree = [];

foreach ($flatTree as $child => $parent) {

if (!isset($flat[$child])) {

$flat[$child] = [];

}

if (!empty($parent)) {

$flat[$parent][$child] =& $flat[$child];

} else {

$tree[$child] =& $flat[$child];

}

}

return $tree;

}

// Recursion function

function treeByRecursion($flatTree, $root = null)

{

$return = [];

foreach($flatTree as $child => $parent) {

if ($parent == $root) {

unset($flatTree[$child]);

$return[$child] = treeByRecursion($flatTree, $child);

}

}

return $return ?: [];

}

// Benchmark reference

$t1 = microtime(true);

$tree = treeByReference($flatTree);

echo 'Reference: ', (microtime(true) - $t1), PHP_EOL;

// Benchmark recursion

$t2 = microtime(true);

$tree = treeByRecursion($flatTree);

echo 'Recursion: ', (microtime(true) - $t2), PHP_EOL;

输出说明一切:

Array count: 255493

Reference: 0.3259289264679 (less than 0.4s)

Recursion: 6604.9865279198 (almost 2h)

这是我想出的:

$arr = array(

'H' => 'G',

'F' => 'G',

'G' => 'D',

'E' => 'D',

'A' => 'E',

'B' => 'C',

'C' => 'E',

'D' => null );

$nested = parentChild($arr);

print_r($nested);

function parentChild(&$arr, $parent = false) {

if( !$parent) { //initial call

$rootKey = array_search( null, $arr);

return array($rootKey => parentChild($arr, $rootKey));

}else { // recursing through

$keys = array_keys($arr, $parent);

$piece = array();

if($keys) { // found children, so handle them

if( !is_array($keys) ) { // only one child

$piece = parentChild($arr, $keys);

}else{ // multiple children

foreach( $keys as $key ){

$piece[$key] = parentChild($arr, $key);

}

}

}else {

return $parent; //return the main tag (no kids)

}

return $piece; // return the array built via recursion

}

}

输出:

Array

(

[D] => Array

(

[G] => Array

(

[H] => H

[F] => F

)

[E] => Array

(

[A] => A

[C] => Array

(

[B] => B

)

)

)

)

好吧,要解析为UL和LI,就像这样:

$array = array (

'H' => 'G'

'F' => 'G'

'G' => 'D'

'E' => 'D'

'A' => 'E'

'B' => 'C'

'C' => 'E'

'D' => 'NULL'

);

recurse_uls ($array, 'NULL');

function recurse_uls ($array, $parent)

{

echo '

';

foreach ($array as $c => $p)  {

if ($p != $parent) continue;

echo '

'.$c.'

';

recurse_uls ($array, $c);

}

echo '

';

}

但是我很乐意看到一个不需要您如此频繁地遍历数组的解决方案...

如何创建动态树视图和菜单

步骤1:首先,我们将在mysql数据库中创建treeview表。该表包含四个column.id是任务ID,名称是任务名称。

-

-- Table structure for table `treeview_items`

--

CREATE TABLE IF NOT EXISTS `treeview_items` (

`id` int(11) NOT NULL AUTO_INCREMENT,

`name` varchar(200) NOT NULL,

`title` varchar(200) NOT NULL,

`parent_id` varchar(11) NOT NULL,

PRIMARY KEY (`id`)

) ENGINE=InnoDB  DEFAULT CHARSET=latin1 AUTO_INCREMENT=7 ;

--

-- Dumping data for table `treeview_items`

--

INSERT INTO `treeview_items` (`id`, `name`, `title`, `parent_id`) VALUES

(1, 'task1', 'task1title', '2'),

(2, 'task2', 'task2title', '0'),

(3, 'task3', 'task1title3', '0'),

(4, 'task4', 'task2title4', '3'),

(5, 'task4', 'task1title4', '3'),

(6, 'task5', 'task2title5', '5');

步骤2:树视图递归方法

我在树下创建了createTreeView()方法,如果当前任务ID大于上一个任务ID,则该方法将调用递归。

function createTreeView($array, $currentParent, $currLevel = 0, $prevLevel = -1) {

foreach ($array as $categoryId => $category) {

if ($currentParent == $category['parent_id']) {

if ($currLevel > $prevLevel) echo" ";

if ($currLevel == $prevLevel) echo"

";

echo '

'.$category['name'].' ';

if ($currLevel > $prevLevel) { $prevLevel = $currLevel; }

$currLevel++;

createTreeView ($array, $categoryId, $currLevel, $prevLevel);

$currLevel--;

}

}

if ($currLevel == $prevLevel) echo"

";

}

步骤3:创建索引文件以显示树视图。

这是treeview示例的主文件,在这里,我们将使用必需的参数调用createTreeView()方法。

mysql_connect('localhost', 'root');

mysql_select_db('test');

$qry="SELECT * FROM treeview_items";

$result=mysql_query($qry);

$arrayCategories = array();

while($row = mysql_fetch_assoc($result)){

$arrayCategories[$row['id']] = array("parent_id" => $row['parent_id'],"name" =>

$row['name']);

}

?>

if(mysql_num_rows($result)!=0)

{

?>

createTreeView($arrayCategories, 0); ?>

}

?>

步骤4:建立CSS档案style.css

在这里,我们将编写所有与CSS相关的类,当前我正在使用订单列表创建树形视图。您还可以在此处更改图像路径。

img { border: none; }

input, select, textarea, th, td { font-size: 1em; }

/* CSS Tree menu styles */

ol.tree

{

padding: 0 0 0 30px;

width: 300px;

}

li

{

position: relative;

margin-left: -15px;

list-style: none;

}

li.file

{

margin-left: -1px !important;

}

li.file a

{

background: url(document.png) 0 0 no-repeat;

color: #fff;            padding-left: 21px;

text-decoration: none;

display: block;

}

li.file a[href *= '.pdf']   { background: url(document.png) 0 0 no-repeat; }

li.file a[href *= '.html']  { background: url(document.png) 0 0 no-repeat; }

li.file a[href $= '.css']   { background: url(document.png) 0 0 no-repeat; }

li.file a[href $= '.js']        { background: url(document.png) 0 0 no-repeat; }

li input

{

position: absolute;

left: 0;

margin-left: 0;

opacity: 0;

z-index: 2;

cursor: pointer;

height: 1em;

width: 1em;

top: 0;

}

li input + ol

{

background: url(toggle-small-expand.png) 40px 0 no-repeat;

margin: -0.938em 0 0 -44px; /* 15px */

height: 1em;

}

li input + ol > li { display: none; margin-left: -14px !important; padding-left: 1px; }

li label

{

background: url(folder-horizontal.png) 15px 1px no-repeat;

cursor: pointer;

display: block;

padding-left: 37px;

}

li input:checked + ol

{

background: url(toggle-small.png) 40px 5px no-repeat;

margin: -1.25em 0 0 -44px; /* 20px */

padding: 1.563em 0 0 80px;

height: auto;

}

li input:checked + ol > li { display: block; margin: 0 0 0.125em;  /* 2px */}

li input:checked + ol > li:last-child { margin: 0 0 0.063em; /* 1px */ }

更多细节

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值