php实现无限级分类(递归方法)_PHP
相信很多学php的很多小伙伴都会尝试做一个网上商城作为提升自己技术的一种途径。各种对商品分类,商品名之类的操作应该是得心应手,那么就可以尝试下无限级分类列表的制作了。
到网上一搜php无限极分类,很多,但好多都是一个,并且,写的很乱,代码很多,让我们怎么学习嘛,那些都不靠谱,还是自己捣鼓捣鼓无限极分类了。
什么是无限级分类?
无限级分类是一种分类技巧,例如部门组织,文章分类,学科分类等常用到无限级分类,将其简单理解成分类就好了。其实我们仔细想一下,生活中的分类简直太多了,衣服可以分为男装和女装,也可以分为上衣和裤子,也可以根据年龄段分类。分类无处不在,分类显得“无限”。我这里就不说无限分类的必要性了。
无限级分类原理简介
无限分类看似"高大上",实际上原理是非常简单的 。无限分类不仅仅需要代码的巧妙性,也要依托数据库设计的合理性。要满足无限级分类,数据库需要有两个必须的字段,id,pid。id用来标识自身,而pid则是用来表明父级id。也就是说,每个分类记录不仅描述了自身,还描述了与其关心最为紧密的另一个id。看似复杂的事情被这样一个小技巧解决了。
闲话不多说,该展现本文的实例了。
作为一个狂热海贼迷,这篇的实例我就以《海贼王》人物组织做案例。
数据库准备:
建表onepiece:
create table onepiece( id int auto_increment, pid int not null, name varchar(225) not null, primary key(id) );
插入测试数据:
insert onepiece values (1,0,'海军'), (2,0,'海贼'), (3,0,'革命军'), (4,1,'青雉'), (5,1,'赤犬'), (6,1,'黄猿'), (7,2,'四皇'), (8,2,'七武海'), (9,2,'草帽海贼团'), (10,9,'索隆'), (11,7,'香克斯'), (12,8,'多弗朗明哥'), (13,8,'克洛克达尔');
这里还是科普下海贼王里面的设定:世界分为三大阵营:海军,海贼,革命军。海军有大将:青雉,赤犬,黄猿。海贼有:四皇,七武海,草帽海贼团。四皇有香克斯,七武海有多弗朗明哥,克洛克达尔,草帽海贼团有索隆。(打个广告:海贼王真的很好看)。
最终目的:
我们今天制作的是两种形式的无限级分类形式,一种是下拉列表式,一种则是导航Link式的。直接上效果图了:
下拉列表式
导航Link式
实例代码:
我封装了一个Unlimited类,用来调用diaplayList()展现下拉列表形式,调用diaplayLink展现导航Link分类。也可以增加(addNodes())和删除(deleteNodes)分类。
<?php class Unlimited{ protected $mysqli; public function __construct($config){ $this->mysqli=new mysqli($config['host'],$config['user'],$config['pwd']); $this->mysqli->select_db($config['db']); $this->mysqli->set_charset('utf8'); if ($this->mysqli->connect_errno) { echo $this->mysqli->connect_error; } } private function getList($pid=0,&$result=array(),$spac=0){ $spac=$spac+2; $sql="select * from onepiece where pid={$pid}"; $rs=$this->mysqli->query($sql); while($row=$rs->fetch_assoc()) { $row['name']=str_repeat('  ',$spac).$row['name']; $result[]=$row; $this->getList($row['id'],$result,$spac); } return $result; } /** * 展现下拉列表式分类 * @return [type] */ public function displayList(){ $rs=$this->getList(); $str="<select name='cate'>"; foreach ($rs as $key => $val) { $str.="<option >{$val['name']}</option>"; } $str.="</select>"; return $str; } private function getLink($cid,&$result=array()){ $sql="select * from onepiece where id={$cid}"; $rs=$this->mysqli->query($sql); if($row=$rs->fetch_assoc()){ $result[]=$row; $this->getLink($row['pid'],$result); } return array_reverse($result); } /** * 展现导航Link * @param [type] $cid [description] * @return [type] [description] */ public function displayLink($cid){ $rs=$this->getLink($cid); $str=''; foreach ($rs as $val) { $str.="<a href=''>{$val['name']}</a>>"; } return $str; } /** * 增加分类 * @param [type] $pid 父类id * @param [type] $name 本类名 */ public function addNodes($pid,$name){ $sql="insert into onepiece values('',{$pid},'".$name."')"; if($this->mysqli->query($sql)){ return true; } } /** * 删除分类 * @param [type] $id 本类id * @return [type] */ public function deleteNodes($id){ $sql="select * from onepiece where pid ={$id}"; $rs=$this->mysqli->query($sql); if($row=$rs->fetch_assoc()){ $mes="还有子元素,请勿删除"; }else{ $sql="delete from onepiece where id={$id}"; if($this->mysqli->query($sql)){ $mes="删除成功"; } } return $mes; } }
类中函数主要采取了递归函数的方法,如果理解深刻理解递归函数,其余的部分也就水到渠成了。我会在后面的部分详细介绍实现递归函数的三种方法。
我们再来看一个实例:
首先建立分类信息表:
CREATE TABLE IF NOT EXISTS `category` ( `categoryId` smallint(5) unsigned NOT NULL AUTO_INCREMENT, `parentId` smallint(5) unsigned NOT NULL DEFAULT '0', `categoryName` varchar(50) NOT NULL, PRIMARY KEY (`categoryId`) ) ;
插入若干数据:
INSERT INTO `category` (`categoryId`, `parentId`, `categoryName`) VALUES (1, 0, 'php'), (2, 0, 'java'), (3, 0, 'c/c++'), (4, 1, 'php基础'), (5, 1, 'php开源资料'), (6, 1, 'php框架'), (7, 2, 'java Se'), (8, 2, 'java EE'), (9, 2, 'java Me'), (10, 3, 'c/c++基础编程'), (11, 3, 'c/c++系统开发'), (12, 3, 'c嵌入式编程'), (13, 3, 'c++应用开发'), (14, 13, 'c++桌面应用开发'), (15, 13, 'c++游戏开发');
下面是php代码:
<?php /* php无限极分类 */ //获取某分类的直接子分类 function getSons($categorys,$catId=0){ $sons=array(); foreach($categorys as $item){ if($item['parentId']==$catId) $sons[]=$item; } return $sons; } //获取某个分类的所有子分类 function getSubs($categorys,$catId=0,$level=1){ $subs=array(); foreach($categorys as $item){ if($item['parentId']==$catId){ $item['level']=$level; $subs[]=$item; $subs=array_merge($subs,getSubs($categorys,$item['categoryId'],$level+1)); } } return $subs; } //获取某个分类的所有父分类 //方法一,递归 function getParents($categorys,$catId){ $tree=array(); foreach($categorys as $item){ if($item['categoryId']==$catId){ if($item['parentId']>0) $tree=array_merge($tree,getParents($categorys,$item['parentId'])); $tree[]=$item; break; } } return $tree; } //方法二,迭代 function getParents2($categorys,$catId){ $tree=array(); while($catId != 0){ foreach($categorys as $item){ if($item['categoryId']==$catId){ $tree[]=$item; $catId=$item['parentId']; break; } } } return $tree; } //测试 部分 $pdo=new PDO('mysql:host=localhost;dbname=test','root','8888'); $stmt=$pdo->query("select * from category order by categoryId"); $categorys=$stmt->fetchAll(PDO::FETCH_ASSOC); $result=getSons($categorys,1); foreach($result as $item) echo $item['categoryName'].'<br>'; echo '<hr>'; $result=getSubs($categorys,0); foreach($result as $item) echo str_repeat(' ',$item['level']).$item['categoryName'].'<br>'; echo '<hr>'; $result=getParents($categorys,7); foreach($result as $item) echo $item['categoryName'].' >> '; echo '<hr>'; $result=getParents2($categorys,15); foreach($result as $item) echo $item['categoryName'].' >> '; ?>
看下最终结果吧
虽然本文介绍的是使用递归来实现的无限级分类,但实际上,并不推荐大家这么做,大家知道分类多了,递归效率也就低了,本文这里仅仅是为了让大家更好的理解递归才这么做的。

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

C++函數的遞歸深度受到限制,超過此限制會導致堆疊溢位錯誤。限制值因係統和編譯器而異,通常在1000到10000之間。解決方法包括:1.尾遞歸最佳化;2.尾呼叫;3.迭代實作。

是的,C++Lambda表達式可以透過使用std::function支援遞歸:使用std::function捕捉Lambda表達式的參考。透過捕獲的引用,Lambda表達式可以遞歸呼叫自身。

遞歸演算法透過函數自呼叫解決結構化的問題,優點是簡潔易懂,缺點是效率較低且可能發生堆疊溢位;非遞歸演算法透過明確管理堆疊資料結構避免遞歸,優點是效率更高且避免堆疊溢出,缺點是程式碼可能更複雜。選擇遞歸或非遞歸取決於問題和實現的特定限制。

給定兩個字串str_1和str_2。目標是使用遞歸過程計算字串str1中子字串str2的出現次數。遞歸函數是在其定義中呼叫自身的函數。如果str1是"Iknowthatyouknowthatiknow",str2是"know"出現次數為-3讓我們透過範例來理解。例如輸入str1="TPisTPareTPamTP",str2="TP";輸出Countofoccurrencesofasubstringrecursi

我們以整數數組Arr[]作為輸入。目標是使用遞歸方法在陣列中找到最大和最小的元素。由於我們使用遞歸,我們將遍歷整個數組,直到達到長度=1,然後返回A[0],這形成了基本情況。否則,將當前元素與當前最小或最大值進行比較,並透過遞歸更新其值以供後續元素使用。讓我們來看看這個的各種輸入輸出場景−輸入 −Arr={12,67,99,76,32};輸出 −數組中的最大值:99解釋 &mi

如何使用Vue表單處理實作表單的遞歸巢狀引言:隨著前端資料處理和表單處理的複雜性不斷增加,我們需要透過一種靈活的方式來處理複雜的表單。 Vue作為一種流行的JavaScript框架,為我們提供了許多強大的工具和特性來處理表單的遞歸巢狀。本文將向大家介紹如何使用Vue來處理這種複雜的表單,並附上程式碼範例。一、表單的遞歸巢狀在某些場景下,我們可能需要處理遞迴巢狀的

Python是一門易學易用的程式語言,然而在使用Python編寫遞歸函數時,可能會遇到遞歸深度過大的錯誤,這時就需要解決這個問題。本文將為您介紹如何解決Python的最大遞歸深度錯誤。 1.了解遞歸深度遞歸深度是指遞歸函數嵌套的層數。在Python預設情況下,遞迴深度的限制是1000,如果遞歸的層數超過這個限制,系統就會報錯。這種報錯通常稱為「最大遞歸深度錯誤

尾遞歸最佳化(TRO)可提高特定遞歸呼叫的效率。它將尾遞歸呼叫轉換為跳轉指令,並將上下文狀態保存在暫存器中,而不是堆疊上,從而消除對堆疊的額外呼叫和返回操作,提高演算法效率。利用TRO,我們可以針對尾遞歸函數(例如階乘計算)進行最佳化,透過將tail遞歸呼叫替換為goto語句,編譯器會將goto跳轉移化為TRO,最佳化遞歸演算法的執行。
