石家庄平山网站推广优化,南宁市优化网站,分销pc网站,微擎可以做企业网站吗文章标题中的多个词语表达的其实是一个意思#xff0c;就是递归分类数据#xff0c;分级数据非常类似数据结构中的树状结构#xff0c;即每个节点有自己的孩子节点#xff0c;孩子结点本身也是父亲节点。这是一个递归、分层形式。可以称之为树形层级数据。层级数据结构是编…文章标题中的多个词语表达的其实是一个意思就是递归分类数据分级数据非常类似数据结构中的树状结构即每个节点有自己的孩子节点孩子结点本身也是父亲节点。这是一个递归、分层形式。可以称之为树形层级数据。层级数据结构是编程语言中非常普通的一种数据结构它代表一系列的数据每一项都有一个父亲节点(除了根节点)和其他多个孩子结点。WEB开发人员使用层级数据结构用于非常多的场景包括内容管理系统CMS、论坛主题、邮件列表还有电子商务网站的产品分类等。本文章主要介绍了使用PHP和MYSQL来管理分级数据的方法在其中将给出两种最流行的分级数据模型邻接表模型嵌套集合模型邻接表模型用于分层数据邻接表模型是一种分级数据模型其中每个节点有一个指向其父亲的指针(根节点该指针为空值)使用下面的SQL语句将建立该结构并插入测试数据123456789101112131415161718192021222324252627282930--------------------------------------------------------------表的结构category--CREATETABLEIFNOTEXISTScategory(category_idint(10)NOTNULLAUTO_INCREMENT,category_namevarchar(50)NOTNULL,parent_idint(10)DEFAULTNULL,PRIMARYKEY(category_id))ENGINEInnoDBDEFAULTCHARSETutf8AUTO_INCREMENT15;----转存表中的数据category--INSERTINTOcategory(category_id,category_name,parent_id)VALUES(1,A,NULL),(2,B,1),(3,C,1),(4,D,1),(5,E,2),(6,F,2),(7,I,4),(8,G,5),(9,H,5),(10,J,7),(11,K,10),(12,L,10);建立完成后数据库中存在了数据并且分类图是每个节点为(关键字数据库ID)。parent_id就是它的父节点的ID号这种方法非常简单因为能很容易的看清楚父子关系。使用以下的简单PHP函数代码可以很容易的输出树状路径123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657functionget_path($category_id){$conmysql_connect(localhost,root,123456);if(!$con){die(数据库连接失败: .mysql_error());}mysql_select_db(test,$con);// 查找当前节点的父节点的ID这里使用表自身与自身连接实现$sqlSELECT c1.parent_id, c2.category_name AS parent_nameFROM category AS c1LEFT JOIN category AS c2ON c1.parent_idc2.category_idWHERE c1.category_id$category_id ;//echo $sql.;//测试把SQL打印出来拿到数据库执行一下看看结果$resultmysql_query($sql);$rowmysql_fetch_array($result);//现在$row数组存了父亲节点的ID和名称信息// 将树状路径保存在数组里面$patharray();//如果父亲节点不为空(根节点)就把父节点加到路径里面if($row[parent_id]!NULL){//将父节点信息存入一个数组元素$parent[0][category_id]$row[parent_id];$parent[0][category_name]$row[parent_name];//递归的将父节点加到路径中$patharray_merge(get_path($row[parent_id]),$parent);}return$path;}//根据上面的图可以看出K的ID是11我们就用它来测试路径$pathget_path(11);echo路径数组;echo;print_r($path);echo;//将路径到根节点的路径打印出来//打印结果JIDAecho向根节点打印路径;for($icount($path)-1;$i0;$i--){echo$path[$i][category_name].;}?由此可以知道怎样找到一个叶子节点(没有孩子的节点)到根节点的路径下面来看怎样从根节点往下来遍历层级结构通过节点的层级关系来打印所有的节点123456789101112131415161718192021222324252627functiondisplay_children($category_id,$level){$conmysql_connect(localhost,root,123456);if(!$con){die(数据库连接失败: .mysql_error());}mysql_select_db(test,$con);// 获得当前节点的所有孩子节点(直接孩子没有孙子)$resultmysql_query(SELECT * FROM category WHERE parent_id$category_id);// 遍历孩子节点打印节点while($rowmysql_fetch_array($result)){// 根据层级按照缩进格式打印节点的名字// 这里只是打印你可以将以下代码改成其他比如把节点信息存储起来echostr_repeat(--,$level).$row[category_name].;// 递归的打印所有的孩子节点display_children($row[category_id],$level1);}}//根节点是A:1我们就用它来打印所有的节点display_children(1,0);?然而邻接表模型(每个节点存储父亲节点信息)有它的劣势首先使用数据库的查询语句很难直接实现它需要借助PHP代码实现。SQL语句需要你知道节点位于哪一个层级。并且每个树层是使用SQL的自我表连接实现的这意味着树的每一层处理都会降低数据库的性能。删除节点的过程也会导致一些问题如果只删除了某个节点它却有孩子结果是它的孩子成了孤儿(就是没有父亲了)真正的体现就是这些孩子节点从树中相当于“消失了”。嵌套集合模型用于树形分层结构数据嵌套集合模型也叫做先根遍历树算法也是一种处理树形层级数据的方法。代替节点间的父子关系层级使用嵌套的容器的集合来表示其中每个节点具有两个值一个left一个right。决定left和right的值的过程是从左到右进行的首先给left赋值让后向下遍历节点的孩子们最后才能得到节点的right的值。SQL语句如下所示123456CREATETABLEcategory(category_idINT(10)AUTO_INCREMENTPRIMARYKEY,category_nameVARCHAR(50)NOTNULL,lftINT(10)NOTNULL,rgtINT(10)NOTNULL);现在可以用一句SQL查询得到整个树的节点SELECT * FROM category WHERE lft BETWEEN 1 AND 14 ORDER BY lft ASC在本SQL中的两个数字值1和14就是根节点的left和right值。类似的如果想得到某个节点的所有孩子节点只需要将该SQL语句的1和14替换成本节点的left和right值就可以了。例如如果想得到所有男人的衣服可以用下面的SQL语句SELECT * FROM category WHERE lft BETWEEN 2 AND 7 ORDER BY lft ASC想找到一条到某个节点的路径用一条SQL语句就可以搞定SELECT * FROM category WHERE lft 9 AND rgt 10 ORDER BY lft ASC请仔细观察一下一些叶子节点到根节点的路径。就会发现所有的祖先都有更小的左值和更大的右值。本例子中一条到裙子分类的路径被取出。观察一下裙子的所有left值都小于9right值都大于10其他的非祖先节点都不满足该要求。尽管嵌套集合模型更加复杂并且有些难以理解它有非常多的优势。它不需要依赖其他资源(比如PHP代码)也不需要递归。同时数据库查询语句非常的简单大多数用一条SQL语句就可以搞定。这些特性都能够显著的增加应用程序的性能使得它能够用可接受的速度来处理复杂的层级结构。然而万事皆无完美更新该层级结构(增加或删除节点)却更加的复杂并且可能会非常慢。增加一个节点到层级结构的方法将一个节点插入到层级数据中需要整个树很多节点的left和right值的更新。例如如果你想将一个男士运动鞋的分类插入到男性衣服的短裤后面。那么所有你必须将大于6的所有left和right值都增加2。为什么呢因为短裤的right值是6那你就必须将你的新分类的left和right值设定为7和8当然以下两条SQL就可以解决UPDATE category SET rgtrgt2 WHERE rgt6UPDATE category SET lftlft2 WHERE lft6现在树中间已经有空隙用来插入新分类了用一条SQL插入该节点INSERT INTO category (category_name,lft,rgt) VALUES (Sneakers,7,8)树形层级数据中删除一个节点的方法在层级集合模型中删除一个节点的方法比在邻接表中相同的操作稍微难一些。不同的操作的复杂程度是不同的比如删除一个叶子节点和一个带孩子节点就很不同。要删除一个叶子节点先将所有left和right大于该节点left和right值的节点的left和right减去2然后再删除该节点。以下使用SQL实现该过程UPDATE category SET lftlft-2 WHERE lft5UPDATE category SET rgtrgt-2 WHERE rgt6DELETE FROM category WHERE lft5AND rgt6该例子中短裤节点被删除了。如果要删除的节点有孩子节点的话删除过程会多一个步骤:比如我们删除男性衣服分类的时候UPDATE category SET lftlft-1, rgtrgt-1 WHERE lft2 AND rgt7UPDATE category SET lftlft-2 WHERE lft7UPDATE category SET rgtrgt-2 WHERE rgt7DELETE FROM category WHERE lft2AND rgt7哪种模型对于处理树形分层数据更好哪种情况更好呢看情况。如果需要一个更加灵活的模型更容易更新就用邻接表模型吧。如果分类构成了一棵复杂的数并且更新不需要很频繁用嵌套集合模型肯定是上上之选。本文内容翻译自访问其中原文中的代码有些问题本人添加了测试数据并改正了代码。