0

0

php:树形结构的算法1

php中文网

php中文网

发布时间:2016-06-21 08:57:52

|

1286人浏览过

|

来源于php中文网

原创

       从喜悦村上转载,以前也读过此文,讲述得还是比较清楚的。

  产品分类,多级的树状结构的论坛,邮件列表等许多地方我们都会遇到这样的问题:如何存储多级结构的数据?
  
  在php的应用中,提供后台数据存储的通常是关系型数据库,它能够保存大量的数据,提供高效的数据检索和更新服务。然而关系型数据的基本形式是纵横交错的表,是一个平面的结构,如果要将多级树状结构存储在关系型数据库里就需要进行合理的翻译工作。接下来我会将自己的所见所闻和一些实用的经验和大家探讨一下。
  
  层级结构的数据保存在平面的数据库中基本上有两种常用设计方法:
  
  毗邻目录模式(adjacency list model)
  预排序遍历树算法(modified preorder tree traversal algorithm)
  我不是计算机专业的,也没有学过什么数据结构的东西,所以这两个名字都是我自己按照字面的意思翻的,如果说错了还请多多指教。
  
  这两个东西听着好像很吓人,其实非常容易理解。这里我用一个简单食品目录作为我们的示例数据。 我们的数据结构是这样的:
  
  
  food
  |
  |---fruit
  | |
  | |---red
  | | |
  | | |--cherry
  | |
  | |---yellow
  | |
  | |--banana
  |
  |---meat
  |
  |--beef
  |
  |--pork
  为了照顾那些英文一塌糊涂的php爱好者
  
  food:食物
  fruit:水果
  red:红色
  cherry:樱桃
  yellow:黄色
  banana:香蕉
  meat:肉类
  beef:牛肉
  pork:猪肉
  
  毗邻目录模式(adjacency list model)
  
  这种模式我们经常用到,很多的教程和书中也介绍过。我们通过给每个节点增加一个属性 parent 来表示这个节点的父节点从而将整个树状结构通过平面的表描述出来。根据这个原则,例子中的数据可以转化成如下的表:
  
  +-----------------------+
  | parent | name |
  +-----------------------+
  | | food |
  | food | fruit |
  | fruit | green |
  | green | pear |
  | fruit | red |
  | red | cherry |
  | fruit | yellow |
  | yellow | banana |
  | food | meat |
  | meat | beef |
  | meat | pork |
  +-----------------------+
  我们看到 pear 是green的一个子节点,green是fruit的一个子节点。而根节点'food'没有父节点。 为了简单地描述这个问题, 这个例子中只用了name来表示一个记录。 在实际的数据库中,你需要用数字的id来标示每个节点,数据库的表结构大概应该像这样:id, parent_id, name, description。有了这样的表我们就可以通过数据库保存整个多级树状结构了。
  
  显示多级树
  如果我们需要显示这样的一个多级结构需要一个递归函数。
  
    // $parent is the parent of the children we want to see
  // $level is increased when we go deeper into the tree,
  // used to display a nice indented tree
  
  function display_children($parent, $level)
  {
  // 获得一个 父节点 $parent 的所有子节点
  $result = mysql_query('select name from tree '.
  'where parent="'.$parent.'";');
  
  // 显示每个子节点
  while ($row = mysql_fetch_array($result))
  {
  // 缩进显示节点名称
  echo str_repeat(' ',$level).$row['name']."n";
  
  //再次调用这个函数显示子节点的子节点
  
  display_children($row['name'], $level+1);
  }
  }
  ?>
  对整个结构的根节点(food)使用这个函数就可以打印出整个多级树结构,由于food是根节点它的父节点是空的,所以这样调用: display_children('',0)。将显示整个树的内容:
  
  
  food
  fruit
  red
  cherry
  yellow
  banana
  meat
  beef
  pork
  如果你只想显示整个结构中的一部分,比如说水果部分,就可以这样调用:
  
  display_children('fruit',0);
  
  几乎使用同样的方法我们可以知道从根节点到任意节点的路径。比如 cherry 的路径是 "food > fruit > red"。 为了得到这样的一个路径我们需要从最深的一级"cherry"开始, 查询得到它的父节点"red"把它添加到路径中, 然后我们再查询red的父节点并把它也添加到路径中,以此类推直到最高层的"food"
  
    // $node 是那个最深的节点
  function get_path($node)
  {
  // 查询这个节点的父节点
  $result = mysql_query('select parent from tree '.
  'where name="'.$node.'";');
  $row = mysql_fetch_array($result);
  
  // 用一个数组保存路径
  $path = array();
  
  // 如果不是根节点则继续向上查询
  // (根节点没有父节点)
  if ($row['parent']!='')
  {
  // the last part of the path to $node, is the name
  // of the parent of $node
  $path[] = $row['parent'];
  
  // we should add the path to the parent of this node
  // to the path
  $path = array_merge(get_path($row['parent']), $path);
  }
  
  // return the path
  return $path;
  }
  ?>
  如果对"cherry"使用这个函数:print_r(get_path('cherry')),就会得到这样的一个数组了:
  
  
  array
  (
  [0] => food
  [1] => fruit
  [2] => red
  )
  接下来如何把它打印成你希望的格式,就是你的事情了。
  缺点:这种方法很简单,容易理解,好上手。但是也有一些缺点。主要是因为运行速度很慢,由于得到每个节点都需要进行数据库查询,数据量大的时候要进行很多查询才能完成一个树。另外由于要进行递归运算,递归的每一级都需要占用一些内存所以在空间利用上效率也比较低。
  
  现在让我们看一看另外一种不使用递归计算,更加快速的方法,这就是预排序遍历树算法(modified preorder tree traversal algorithm) 这种方法大家可能接触的比较少,初次使用也不像上面的方法容易理解,但是由于这种方法不使用递归查询算法,有更高的查询效率。
  
  我们首先将多级数据按照下面的方式画在纸上,在根节点food的左侧写上 1 然后沿着这个树继续向下 在 fruit 的左侧写上 2 然后继续前进,沿着整个树的边缘给每一个节点都标上左侧和右侧的数字。最后一个数字是标在food 右侧的 18。 在下面的这张图中你可以看到整个标好了数字的多级结构。(没有看懂?用你的手指指着数字从1数到18就明白怎么回事了。还不明白,再数一遍,注意要移动你的手指)。
  这些数字标明了各个节点之间的关系,"red"的号是3和6,它是 "food" 1-18 的子孙节点。 同样,我们可以看到 所有左值大于2和右值小于11的节点 都是"fruit" 2-11 的子孙节点



PHP速学教程(入门到精通)
PHP速学教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

39

2026.02.06

java多线程方法汇总
java多线程方法汇总

本专题整合了java多线程面试题、实现函数、执行并发相关内容,阅读专题下面的文章了解更多详细内容。

17

2026.02.06

1688阿里巴巴货源平台入口与批发采购指南
1688阿里巴巴货源平台入口与批发采购指南

本专题整理了1688阿里巴巴批发进货平台的最新入口地址与在线采购指南,帮助用户快速找到官方网站入口,了解如何进行批发采购、货源选择以及厂家直销等功能,提升采购效率与平台使用体验。

289

2026.02.06

快手网页版入口与电脑端使用指南 快手官方短视频观看入口
快手网页版入口与电脑端使用指南 快手官方短视频观看入口

本专题汇总了快手网页版的最新入口地址和电脑版使用方法,详细提供快手官网直接访问链接、网页端操作教程,以及如何无需下载安装直接观看短视频的方式,帮助用户轻松浏览和观看快手短视频内容。

150

2026.02.06

C# 多线程与异步编程
C# 多线程与异步编程

本专题深入讲解 C# 中多线程与异步编程的核心概念与实战技巧,包括线程池管理、Task 类的使用、async/await 异步编程模式、并发控制与线程同步、死锁与竞态条件的解决方案。通过实际项目,帮助开发者掌握 如何在 C# 中构建高并发、低延迟的异步系统,提升应用性能和响应速度。

11

2026.02.06

Python 微服务架构与 FastAPI 框架
Python 微服务架构与 FastAPI 框架

本专题系统讲解 Python 微服务架构设计与 FastAPI 框架应用,涵盖 FastAPI 的快速开发、路由与依赖注入、数据模型验证、API 文档自动生成、OAuth2 与 JWT 身份验证、异步支持、部署与扩展等。通过实际案例,帮助学习者掌握 使用 FastAPI 构建高效、可扩展的微服务应用,提高服务响应速度与系统可维护性。

7

2026.02.06

JavaScript 异步编程与事件驱动架构
JavaScript 异步编程与事件驱动架构

本专题深入讲解 JavaScript 异步编程与事件驱动架构,涵盖 Promise、async/await、事件循环机制、回调函数、任务队列与微任务队列、以及如何设计高效的异步应用架构。通过多个实际示例,帮助开发者掌握 如何处理复杂异步操作,并利用事件驱动设计模式构建高效、响应式应用。

11

2026.02.06

java连接字符串方法汇总
java连接字符串方法汇总

本专题整合了java连接字符串教程合集,阅读专题下面的文章了解更多详细操作。

47

2026.02.05

java中fail含义
java中fail含义

本专题整合了java中fail的含义、作用相关内容,阅读专题下面的文章了解更多详细内容。

29

2026.02.05

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Swoft2.x速学之http api篇课程
Swoft2.x速学之http api篇课程

共16课时 | 1.0万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号