php和mysql处理树状_分级_无限分类_分层数据的方法_PHP和MySQL处理树状、分级、无限分类、分层数据的方法...

文章标题中的多个词语表达的其实是一个意思,就是递归分类数据,分级数据非常类似数据结构中的树状结构,即每个节点有自己的孩子节点,孩子结点本身也是父亲节点。这是一个递归、分层形式。可以称之为树形层级数据。

层级数据结构是编程语言中非常普通的一种数据结构,它代表一系列的数据每一项都有一个父亲节点(除了根节点)和其他多个孩子结点。WEB开发人员使用层级数据结构用于非常多的场景,包括内容管理系统CMS、论坛主题、邮件列表,还有电子商务网站的产品分类等。

本文章主要介绍了使用PHP和MYSQL来管理分级数据的方法,在其中将给出两种最流行的分级数据模型:

邻接表模型

嵌套集合模型

邻接表模型用于分层数据

邻接表模型是一种分级数据模型,其中每个节点有一个指向其父亲的指针(根节点该指针为空值),使用下面的SQL语句将建立该结构并插入测试数据:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

--

表的结构

`

category

`

--

CREATE

TABLE

IF

NOT

EXISTS

`

category

`

(

`

category_id

`

int

(

10

)

NOT

NULL

AUTO_INCREMENT

,

`

category_name

`

varchar

(

50

)

NOT

NULL

,

`

parent_id

`

int

(

10

)

DEFAULT

NULL

,

PRIMARY

KEY

(

`

category_id

`

)

)

ENGINE

=

InnoDB

DEFAULT

CHARSET

=

utf8

AUTO_INCREMENT

=

15

;

--

--

转存表中的数据

`

category

`

--

INSERT

INTO

`

category

`

(

`

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函数代码可以很容易的输出树状路径:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

function

get_path

(

$category_id

)

{

$con

=

mysql_connect

(

"localhost"

,

"root"

,

"123456"

)

;

if

(

!

$con

)

{

die

(

'数据库连接失败: '

.

mysql_error

(

)

)

;

}

mysql_select_db

(

'test'

,

$con

)

;

// 查找当前节点的父节点的ID,这里使用表自身与自身连接实现

$sql

=

"

SELECT c1.parent_id, c2.category_name AS parent_name

FROM category AS c1

LEFT JOIN category AS c2

ON c1.parent_id=c2.category_id

WHERE c1.category_id='$category_id' "

;

//echo $sql."
";//测试把SQL打印出来,拿到数据库执行一下看看结果

$result

=

mysql_query

(

$sql

)

;

$row

=

mysql_fetch_array

(

$result

)

;

//现在$row数组存了父亲节点的ID和名称信息

// 将树状路径保存在数组里面

$path

=

array

(

)

;

//如果父亲节点不为空(根节点),就把父节点加到路径里面

if

(

$row

[

'parent_id'

]

!=

NULL

)

{

//将父节点信息存入一个数组元素

$parent

[

0

]

[

'category_id'

]

=

$row

[

'parent_id'

]

;

$parent

[

0

]

[

'category_name'

]

=

$row

[

'parent_name'

]

;

//递归的将父节点加到路径中

$path

=

array_merge

(

get_path

(

$row

[

'parent_id'

]

)

,

$parent

)

;

}

return

$path

;

}

//根据上面的图可以看出,K的ID是11,我们就用它来测试路径

$path

=

get_path

(

11

)

;

echo

"

路径数组:

"

;

echo

"

"

;

print_r

(

$path

)

;

echo

"

"

;

//将路径到根节点的路径打印出来

//打印结果:J>I>D>A>

echo

"

向根节点打印路径:

"

;

for

(

$i

=

count

(

$path

)

-

1

;

$i

>=

0

;

$i

--

)

{

echo

$path

[

$i

]

[

'category_name'

]

.

'>'

;

}

?>

由此可以知道怎样找到一个叶子节点(没有孩子的节点)到根节点的路径,下面来看怎样从根节点往下来遍历层级结构,通过节点的层级关系来打印所有的节点:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

function

display_children

(

$category_id

,

$level

)

{

$con

=

mysql_connect

(

"localhost"

,

"root"

,

"123456"

)

;

if

(

!

$con

)

{

die

(

'数据库连接失败: '

.

mysql_error

(

)

)

;

}

mysql_select_db

(

'test'

,

$con

)

;

// 获得当前节点的所有孩子节点(直接孩子,没有孙子)

$result

=

mysql_query

(

"SELECT * FROM category WHERE parent_id='$category_id'"

)

;

// 遍历孩子节点,打印节点

while

(

$row

=

mysql_fetch_array

(

$result

)

)

{

// 根据层级,按照缩进格式打印节点的名字

// 这里只是打印,你可以将以下代码改成其他,比如把节点信息存储起来

echo

str_repeat

(

'--'

,

$level

)

.

$row

[

'category_name'

]

.

"
"

;

// 递归的打印所有的孩子节点

display_children

(

$row

[

'category_id'

]

,

$level

+

1

)

;

}

}

//根节点是A:1我们就用它来打印所有的节点

display_children

(

1

,

0

)

;

?>

然而,邻接表模型(每个节点存储父亲节点信息)有它的劣势,首先使用数据库的查询语句很难直接实现它,需要借助PHP代码实现。SQL语句需要你知道节点位于哪一个层级。并且每个树层是使用SQL的自我表连接实现的,这意味着树的每一层处理都会降低数据库的性能。

删除节点的过程也会导致一些问题,如果只删除了某个节点它却有孩子,结果是它的孩子成了孤儿(就是没有父亲了),真正的体现就是,这些孩子节点从树中相当于“消失了”。

嵌套集合模型用于树形分层结构数据

嵌套集合模型,也叫做先根遍历树算法,也是一种处理树形层级数据的方法。代替节点间的父子关系,层级使用嵌套的容器的集合来表示,其中每个节点具有两个值,一个left,一个right。

决定left和right的值的过程是从左到右进行的,首先给left赋值,让后向下遍历节点的孩子们,最后才能得到节点的right的值。SQL语句如下所示:

1

2

3

4

5

6

CREATE

TABLE

category

(

category_id

INT

(

10

)

AUTO_INCREMENT

PRIMARY

KEY

,

category_name

VARCHAR

(

50

)

NOT

NULL

,

lft

INT

(

10

)

NOT

NULL

,

rgt

INT

(

10

)

NOT

NULL

)

;

现在可以用一句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值都小于9,right值都大于10,其他的非祖先节点都不满足该要求。

尽管嵌套集合模型更加复杂并且有些难以理解,它有非常多的优势。它不需要依赖其他资源(比如PHP代码),也不需要递归。同时,数据库查询语句非常的简单,大多数用一条SQL语句就可以搞定。这些特性都能够显著的增加应用程序的性能,使得它能够用可接受的速度来处理复杂的层级结构。

然而万事皆无完美,更新该层级结构(增加或删除节点)却更加的复杂,并且可能会非常慢。

增加一个节点到层级结构的方法:

将一个节点插入到层级数据中,需要整个树很多节点的left和right值的更新。例如,如果你想将一个男士运动鞋的分类插入到男性衣服的短裤后面。那么所有你必须将大于6的所有left和right值都增加2。为什么呢?因为短裤的right值是6,那你就必须将你的新分类的left和right值设定为7和8,当然,以下两条SQL就可以解决:

UPDATE category SET rgt=rgt+2 WHERE rgt>6

UPDATE category SET lft=lft+2 WHERE lft>6

现在树中间已经有空隙用来插入新分类了,用一条SQL插入该节点:

INSERT INTO category (category_name,lft,rgt) VALUES (

'Sneakers'

,

'7'

,

'8'

)

树形层级数据中删除一个节点的方法:

在层级集合模型中删除一个节点的方法,比在邻接表中相同的操作稍微难一些。不同的操作的复杂程度是不同的,比如删除一个叶子节点和一个带孩子节点就很不同。

要删除一个叶子节点,先将所有left和right大于该节点left和right值的节点的left和right减去2,然后再删除该节点。以下使用SQL实现该过程:

UPDATE category SET lft=lft-2 WHERE lft>5

UPDATE category SET rgt=rgt-2 WHERE rgt>6

DELETE FROM category WHERE lft=

'5'

AND rgt=

'6'

该例子中短裤节点被删除了。

如果要删除的节点有孩子节点的话,删除过程会多一个步骤:

比如我们删除男性衣服分类的时候:

UPDATE category SET lft=lft-1, rgt=rgt-1 WHERE lft>2 AND rgt<7

UPDATE category SET lft=lft-2 WHERE lft>7

UPDATE category SET rgt=rgt-2 WHERE rgt>7

DELETE FROM category WHERE lft=

'2'

AND rgt=

'7'

哪种模型对于处理树形分层数据更好?

哪种情况更好呢,看情况。如果需要一个更加灵活的模型,更容易更新,就用邻接表模型吧。如果分类构成了一棵复杂的数,并且更新不需要很频繁,用嵌套集合模型肯定是上上之选。

本文内容翻译自:访问,其中原文中的代码有些问题,本人添加了测试数据并改正了代码。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/397725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode 70. Climbing Stairs

You are climbing a stair case. It takes n steps to reach to the top. Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top? 一开始想用排列组合的方式&#xff0c;但是公式不太好些&#xff0c;后来想用递归的方式&#x…

04 java 基础:数据类型

java 数据类型&#xff1a;基本类型与引用类型 基本类型&#xff1a;数值型&#xff0c;其中数值型分为整型、浮点型&#xff0c;整型包括 byte、short 、int、long &#xff0c;默认为 int 类型。浮点类型分为单精度、双精度&#xff0c;分为 float、double &#xff0c;默认为…

Git 远程仓库分支管理

目录 目录速查表关联远程代码仓库克隆远程仓库 分支管理创建分支 切换分支合并分支删除分支解决冲突速查表 指令作用git branch查看分支git branch newBranchName创建分支git checkout branchName切换分支giit checkout -b newBranchName创建切换分支git merge branchName合并分…

call,apply

1.call要逐个传入参数 2apply方法的必须 function curry(fn){var argsArray.prototype.slice.call(arguments,1);return function(){var innerArgsArray.prototype.slice.call(arguments);var finalArgsargs.concat(innerArgs);console.log(finalArgs);return fn(finalArgs);//…

2018美团CodeM编程大赛 Round A Problem 2 下棋 【贪心】

应该一眼看出来是贪心题&#xff0c;然后想最优解是什么。正确的贪心策略是【原棋盘上每个位置的棋子】都往最近的左边【目标棋盘上棋子】移动&#xff0c;如果左边没有棋子了那就闲置最后处理&#xff0c;如果目标棋盘在该位置上也有棋子&#xff0c;那就算距离为0&#xff08…

idea清理svn信息_IntelliJ IDEA SVN的账号修改 信息清除

来到编译器的setting设置 搜索subversion 点击subversion 找到下面的clear auth...按钮,点击一下 就可以了…如果我们不小心输入svn账号错误的话,后面就一直提示认证失败,不能checkout代码. 这个是因为svn把你输入的账号进行了缓存. 如果我们想重新输入新的账号,必须要清除缓存…

同步手绘板——json

JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于ECMAScript的一个子集。 JSON采用完全独立于语言的文本格式&#xff0c;但是也使用了类似于C语言家族的习惯&#xff08;包括C、C、C#、Java、JavaScript、Perl、Python等&#xff09;。这些特性使JSON成为…

[HNOI2008]玩具装箱TOY

洛谷题目连接:[HNOI2008]玩具装箱TOY 题目描述 P教授要去看奥运&#xff0c;但是他舍不下他的玩具&#xff0c;于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩&#xff0c;其可以将任意物品变成一堆&#xff0c;再放到一种特殊的一维容器中。P教授有编号为1...N的…

C语言-结构体内存对齐

C语言结构体对齐也是老生常谈的话题了。基本上是面试题的必考题。内容虽然很基础&#xff0c;但一不小心就会弄错。写出一个struct&#xff0c;然后sizeof&#xff0c;你会不会经常对结果感到奇怪&#xff1f;sizeof的结果往往都比你声明的变量总长度要大&#xff0c;这是怎么回…

nginx 二进制包安装mysql_二进制安装mysql5.7

下载地址&#xff1a;https://downloads.mysql.com/archives/community/[rootlocalhost soft]# lsmysql-5.7.17-linux-glibc2.5-x86_64.tar.gz nginx-1.12.2 nginx-1.12.2.tar.gz[rootlocalhost soft]#1.详细描安装的过程1.1关闭防火墙systemctl stop firewalld.service #停止f…

.NET 类型(Types)的那些事

引言 您是.Net工程师&#xff1f;那 .NetFramework中的类型您知道有三大类吗&#xff1f;&#xff08;除了引用类型和值类型&#xff0c;还有&#xff1f;&#xff09; 引用类型一定在“堆”上&#xff0c;值类型一定在“栈”上&#xff1f; 那引用类型在内存中的布局细节您又知…

几种去除数组中重复元素的方法、数组去重

工作中遇到的一个问题&#xff0c;就是去除数组中重复的元素&#xff0c;记录一下几种有效的方法&#xff1a; 第一种思路&#xff1a;遍历要删除的数组arr, 把元素分别放入另一个数组tmp中&#xff0c;在判断该元素在arr中不存在才允许放入tmp中。 <!DOCTYPE html> <…

MongoDB学习使用

一、什么是MongoDB&#xff1f; MongoDB是一个高性能&#xff0c;开源&#xff0c;无模式的文档型数据库&#xff0c;是当前NoSql数据库中比较热门的一种。它在许多场景下可用于替代传统的关系型数据库或键/值存储方式&#xff0c; NoSql&#xff0c;全称是 Not Only Sql,指的是…

域账号更改密码之后代理需要重新配置

在使用域账号的时候&#xff0c;如果需要配置账户和密码&#xff0c;那么最好记录下来&#xff0c;否则将来找不到就很尴尬了。 我遇到的问题是&#xff0c;因为在另外一台电脑配置了域账号&#xff0c;用来联网&#xff0c;提供网络给visual studio 1.Firefox 这个代理的账号…

wcf精通1-15

随笔- 197 文章- 0 评论- 3407 十五天精通WCF——第一天 三种Binding让你KO80%的业务 转眼wcf技术已经出现很多年了&#xff0c;也在.net界混的风生水起&#xff0c;同时.net也是一个高度封装的框架&#xff0c;作为在wcf食物链最顶端的我们所能做的任务已经简单的不能再简单…

python如何实现共享报表系统_使用python来实现报表自动化-阿里云开发者社区

xlwt 常用功能xlrd 常用功能xlutils 常用功能xlwt写Excel时公式的应用xlwt写入特定目录(路径设置)xlwt Python语言中&#xff0c;写入Excel文件的扩展工具。可以实现指定表单、指定单元格的写入。支持excel03版到excel2013版。使用时请确保已经安装python环境。百度百科xlrd Py…

去除inline-block元素间间距的N种方法

这篇文章发布于 2012年04月24日&#xff0c;星期二&#xff0c;22:38&#xff0c;归类于 css相关。 阅读 147771 次, 今日 52 次 by zhangxinxu from http://www.zhangxinxu.com 本文地址&#xff1a;http://www.zhangxinxu.com/wordpress/?p2357 一、现象描述 真正意义上的in…

Docker深入浅出2

Docker系统架构 Docker使用客户端-服务端&#xff08;c/s&#xff09;架构模式&#xff0c;使用远程api来管理和创建Docker容器。 docker容器通过Docker镜像来创建。 容器与镜像的关系类似于面向对象编程中的对象与类的关系 Docker面向对象容器对象镜像类加速器配置&#xff1a…

mysql安装包下载密码_MySQL解压包的安装与下载的图文教程

这篇文章主要为大家详细介绍了mysql解压包的安装基础教程&#xff0c;具有一定的参考价值&#xff0c;感兴趣的小伙伴们可以参考一下由于换了新电脑&#xff0c;所以的环境都要到新电脑去配置。突然发现mysql的配置忘了&#xff0c;然后百度又重新来一遍。特地写一篇文章记录一…

php 扒取网页数据

扒取方法 public function index(){$url http://www.dytt8.net/;// $url Public/txt/movies.txt;$content file_get_contents($url);$content iconv("gb2312", "utf-8//IGNORE",$content);$reg "|<div class\"co_content2\">(.*…