数据结构与算法学习之路13--二叉树(上)

208 阅读3分钟

树是一种非线性的数据结构,它类比于实际生活中的树。在树结构中每个元素称为一个节点,有一个根节点,之后是子节点,那些没有子节点的结点我们称为叶子结点。
树有几个概念:

  • 节点的高度:节点到叶子节点的最长路径所包含的边数
  • 节点的深度:根节点到节点的路径所包含的边数
  • 节点的层数:节点的深度+1(根节点的层数是1)
  • 树的高度:等于根节点的高度

目前我们实际中用的比较多的是二叉树。

二叉树相关概念

  • 每个结点最多有两个子节点,分别为左子节点和右子节点
  • 有一种二叉树,除了叶子节点外,每个节点都有左右两个子节点,这种二叉树叫做满二叉树
  • 有一种二叉树,叶子节点都在最底下两层,最后一层叶子节都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大,这种二叉树叫做完全二叉树。

上图中的2为满二叉树,3为完全二叉树

二叉树的存储

链式存储

采用链式存储如下图所示。每个节点都有三个字段,分别对应数据以及左右两个节点的指针。只要拎住根节点,就可以通过左右子节点的指针,把整棵树都串起来。这种存储方式我们比较常用。

顺序存储

顺序存储是基于数组的,如下图所示。如果节点 X 存储在数组中下标为 i 的位置,下标为 2 * i 的位置存储的就是左子节点,下标为 2 * i + 1 的位置存储的就是右子节点。反过来,下标为 i/2 的位置存储就是它的父节点。通过这种方式,我们只要知道根节点存储的位置(一般情况下,为了方便计算子节点,根节点会存储在下标为 1 的位置),这样就可以通过下标计算,把整棵树都串起来。

二叉树的遍历

通常我们把二叉树的遍历分为三种情况:

  • 前序遍历。对于树中的任意节点来说,先打印这个节点,然后再打印它的左子树,最后打印它的右子树
  • 中序遍历。对于树中的任意节点来说,先打印它的左子树,然后再打印它本身,最后打印它的右子树。
  • 后序遍历。对于树中的任意节点来说,先打印它的左子树,然后再打印它的右子树,最后打印这个节点本身。 具体如下图所示
    从图中可以分析出树的遍历是一个递归的过程。

代码实现(php)

<?php

class Node
{
    public $value;
    public $left;
    public $right;
}

class Tree
{
    /**
     * 前序遍历
     * @param $root
     */
    public function preOrder($root)
    {
        if ($root != null) {
            echo $root->value . " ";        // 根
            if ($root->left != null) {
                $this->preOrder($root->left);     //递归遍历左树
            }
            if ($root->right != null) {
                $this->preOrder($root->right);    //递归遍历右树
            }
        }
    }

    /***
     * 中序遍历
     * @param $root
     */
    public function midOrder($root)
    {
        if ($root != null) {
            if ($root->left != null) {
                $this->midOrder($root->left);  // 递归遍历左树
            }
            echo $root->value . " ";
            if ($root->right != null) {
                $this->midOrder($root->right); // 递归遍历右树
            }
        }
    }

    /***
     * 后序遍历
     * @param $root
     */
    public function endOrder($root)
    {
        if ($root != null) {
            if ($root->left != null) {
                $this->endOrder($root->left);  // 递归遍历左树
            }
            if ($root->right != null) {
                $this->endOrder($root->right); // 递归遍历右树
            }
            echo $root->value . " ";
        }
    }
}