PHP面试:说说你理解的二叉树吧

理解和实现树

迄今为止,我们对数据结构的探索仅触及线性部分。无论我们使用数组、链表、栈还是队列,都是线性数据结构。我们已经看到了线性数据结构操作的复杂性,大多数时候,插入和删除的复杂度可以用O(1)来表示。搜索有点复杂,需要O(n)复杂度。唯一的例外是PHP数组,它实际上是哈希表,如果索引或键在这样的以这样的方式管理,则可以达到O(1)的复杂度。为了解决这个问题,我们可以使用分层数据结构,而不是线性数据结构。分层数据可以很好地解决线性数据结构难以解决的许多问题。

每当我们谈论家庭族谱、组织结构和网络连接图时,我们实际上都在谈论分层数据。树是一种特殊的抽象数据类型(ADT)。不同于链表,树是分层的。

树的定义和特点

树是由边连接的节点或顶点的分层集合。树不能有循环,并且只有节点和它的下降节点或子节点之间存在边。同一父级的两个子节点在它们之间不能有任何边。每个节点可以有一个父节点除非是顶部节点,也称为根节点。每棵树只能有一个根节点。每个节点可以有零个或多个子节点。在下面的图中,A是根节点,B、C和D是A的子节点。我们也可以说,A是B、C、D的父节点。B、C和D被称为兄弟姐妹,因为它们是来自同一父节点A。

image

没有任何子节点的节点称为叶子。在前面的图中,K、L、F、G、M、I和J是叶子节点。叶子节点也称为外部节点或终端节点。除根以外的节点具有至少一个子节点,称为内部节点。这里,B、C、D、E和H是内部节点。这里是一些其他常用的术语,用于描述树的数据结构:

后裔:这是一个可以通过重复的程序从父节点到达的节点。例如,M是前一个图中C的后裔。

祖先:这是一个可以通过重复方式从子节点到达父节点的节点。例如,B是L的祖先。

度:特定父节点的子节点的总数被称为它的度数。在我们的例子中,A有3度,B有1度,C有度3,D有度2。

路径:从源节点到目标节点的节点和边的序列称为两个节点之间的路径。路径的长度是路径中节点的数目。A到M之间的路径是A-C-H-M,路径的长度为4。

节点的高度:节点的高度由节点与最深节点之间的边数决定。例如,节点B的高度为2。

层次:层次代表节点的生成。如果父节点处于层次N,则其子节点将位于N+ 1层次。因此,该层次由节点和根之间的边数定义。

A在0层

B,C和D是1层

E,F,G,H,I,J是2层

K,L,M都在第3层。

树的高度:树的高度是由它的根节点的高度定义的。上图树的高度是3。

image

子树:在树结构中,每个孩子递归地形成子树。换句话说,树由许多子树组成。例如,B和E、K和L构成了一个子树,E、K和 L构成了一个子树,每个不同的阴影中都对它们进行了识别。

深度:节点的深度由节点和根节点之间的边数决定。例如,H的深度是2,L的深度是3。

森林:森林是由一组或更多的不相交的树组成。

遍历:这表示按特定顺序访问节点的过程。

键:用于搜索,表示节点的值。

使用PHP实现树

到目前为止,我们已经了解了树的不同属性。如果我们对比树和现实的例子,我们发现组织结构或族谱树可以用数表示。对于一个组织结构,有一个根节点可以是公司的CEO,其次是CXO级别的员工,其次是其他级别的员工。这里,我们不限制特定节点的任何度。这意味着一个节点可以有多个子节点。因此,下面是一个节点结构,我们可以定义节点属性、它的父节点和它的子节点:

class TreeNode
{
    public $data = null;

    public $children = [];

    public function __construct(string $data = null)
    {
        $this->data = $data;
    }

    public function addChildren(TreeNode $treeNode)
    {
        $this->children[] = $treeNode;
    }
}

我们可以看到我们声明了两个公共属性分别为数据和孩子。我们还有一个方法将孩子添加到一个特定的节点。这里,我们只是在数组末尾添加新的子节点。树是递归结构,它将帮助我们递归地构建树,并递归地遍历树。

现在,我们有了节点,让我们构建一个树结构,它将定义树的根节点,也可以遍历整个树。因此,基本树结构将是这样的:

class Tree
{
    public $root = null;

    public function __construct(TreeNode $treeNode)
    {
        $this->root = $treeNode;
    }

    public function traverse(TreeNode $treeNode, int $level = 0)
    {
        if ($treeNode) {
            echo str_repeat('-', $level) . $treeNode->data . PHP_EOL;

            foreach ($treeNode->children as $child) {
                $this->traverse($child, $level + 1);
            }
        }
    }
}

前面的代码显示了一个简单的树类,我们可以存储根节点引用,也可以从任意节点遍历树。在遍历部分中,我们访问每个子节点,然后立即递归调用遍历方法来获取当前节点的子节点。我们通过一个level,在节点名称的开头打印出一个破折号(-),这样我们就可以很容易地理解子级数据。

require './TreeNode.php';

$ceo = new TreeNode('ceo');

$tree = new Tree($ceo);

$cfo = new TreeNode('cfo');
$cto = new TreeNode('cto');
$cmo = new TreeNode('cmo');
$coo = new TreeNode('coo');

$ceo->addChildren($cfo);
$ceo->addChildren($cto);
$ceo->addChildren($cmo);
$ceo->addChildren($coo);

$seniorArchitect = new TreeNode("Senior Architect");
$softwareEngineer = new TreeNode("SoftwareEngineer");

$userInterfaceDesigner = new TreeNode("userInterface Designer");
$qualityAssuranceEngineer = new TreeNode("qualityAssurance Engineer");


$cto->addChildren($seniorArchitect);
$seniorArchitect->addChildren($softwareEngineer);

$cto->addChildren($userInterfaceDesigner);
$cto->addChildren($qualityAssuranceEngineer);

$tree->traverse($tree->root);

最后输出的结果类似这样,完整的代码可以在这里看到

image

不同类型的树

在代码世界中有很多不同类型的树,我们一起来看下。

二叉树

二叉树是一种基本的树结构,二叉树的每个节点最多有两个孩子。

image

二叉搜索树

二叉搜索树(BST)是一种特殊类型的二叉树,其中节点以排序的方式存储,即在任何给定的点上,节点值必须大于或等于左子节点值,小于右子节点值。每个节点都必须满足这个属性,这就是二叉搜索树。二叉搜索树算法总是优于线性搜索,它的时间复杂度是O(n),我们将在以后的内容详细解释。

image

自平衡二叉树

自平衡二叉搜索树或高度平衡二叉搜索树是一种特殊类型的二叉搜索树,它试图通过自动调整来尽量保持树的高度或层次尽可能小。下图左侧的展示了二叉搜索树,右边的是自平衡二叉搜索树:

image

高度平衡的二叉树总是更好的选择,因为它比常规BST有助于更快地搜索操作。自平衡或高度平衡二叉搜索树有不同的实现。一些常见到的如下:

  • AA树

  • AVL树

  • 红黑树

  • 替罪羊树

  • 八叉树

  • 2-3树

  • Treap

我们将在后续的内容介绍他们,敬请期待吧。

更多内容

PHP基础数据结构专题系列目录地址:https://github.com/... 主要使用PHP语法总结基础的数据结构和算法。还有我们日常PHP开发中容易忽略的基础知识和现代PHP开发中关于规范、部署、优化的一些实战性建议,同时还有对Javascript语言特点的深入研究。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,794评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,050评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,587评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,861评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,901评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,898评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,832评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,617评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,077评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,349评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,483评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,199评论 5 341
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,824评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,442评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,632评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,474评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,393评论 2 352

推荐阅读更多精彩内容

  • 树的概述 树是一种非常常用的数据结构,树与前面介绍的线性表,栈,队列等线性结构不同,树是一种非线性结构 1.树的定...
    Jack921阅读 4,447评论 1 31
  • 基于树实现的数据结构,具有两个核心特征: 逻辑结构:数据元素之间具有层次关系; 数据运算:操作方法具有Log级的平...
    yhthu阅读 4,270评论 1 5
  • 她想过很多种与他相见的方式,却没想到是最草率的那一种。他知道她喜欢睡觉时听着音乐,他知道她不喜欢别人大声说话,他知...
    阿金的工作室阅读 238评论 0 0
  • 我是樊登读书江江,今天是我坚持写原创文章【54】篇 今天第一天按照闹钟的约定6:00醒来,早上起床后我有空腹喝水的...
    jcl小江江阅读 363评论 0 1
  • 山本无忧,因雪白头 水本无愁,因风起皱 花还是那桔梗花,茶还是那盏清茶 只是谁陪你喝茶,谁又能陪你插花 春暖花开,...
    包秀娟阅读 194评论 0 0