前情提要:
我们首先谈一谈什么是二叉树。
二叉树,是一种特殊的树结构。而树结构,就是由一个主干和多个枝干组成的结构。我们平时在公司的职位就是一种典型的树结构,老板是根,员工是叶子,中间的管理人员是组成树的枝干,把这棵树翻转过来,我们就可以得到一张表示树的示例图:
树有一个非常有意思的点:树的子树还是一棵树
拿我们的李组长举例子:
李组长带领的打工仔甲、“你”和隔壁老王,又组成了一棵树。那么现在问题来了,“你”算不算一棵树呢?
答案是肯定的。不过“你”是一颗特殊的树。
下面介绍的二叉树,也是一种特殊的树,它有以下特点:每个结点最多只能有两棵子树,且有左右之分 。
二叉树定义:
二叉树是n个有限元素的集合或者为空、或者由一个称为根(root)的元素及两个不相交的、被分别称为左子树和右子树的二叉树组成。是有序树。当集合为空时,称该二叉树为空二叉树。在二叉树中,一个元素也称作一个结点。
二叉树性质:
(1) 在二叉树的第i层上至多有2 ^(i-1)个节点(i>=1)
(2) 深度为k的二叉树最大节点数为2^k-1个节点(k>=1)
- 一颗深度为k且有2k-1个节点的二叉树称为 满二叉树
- 可以对 满二叉树 进行连续编号,约定编号从根节点起,自上而下,自左至右
- 深度为k的,有n个节点的二叉树,当且仅当其每一个节点斗鱼深度为k的满二叉树中编号 从1至n的节点一一对应时,称之为 完全二叉树
(3) 对任意一颗二叉树T,如果其终端节点为n0,度为2的节点数为n2,则n0=n2+1
(4) 具有n个节点的完全二叉树(其深度为 floor(log2(n))+1)的节点按层序编号,对任意节点i(1<=i<=n) i>1时,其双亲节点为floor(i/2)
【注】:floor 为向下取整
二叉树的三种遍历
现在有一颗二叉树如下图:
我们规定以下三种方式来遍历这一棵二叉树:
先(根)序遍历、中(根)序遍历、后(根)序遍历
我们用先(根)序遍历举例子,顾名思义,先根,就是先访问根节点,然后访问其左孩子节点、右孩子节点。
图中用先序遍历结果就是:老板 、张组长、 打工仔乙 、李组长、 你 、隔壁老王
中序后序遍历如法炮制即可~
二叉树的数据结构以及简单操作(递归)的C++实现
简单回顾了二叉树的基本概念以后,我们试着实现一下二叉树的数据结构,以及用用最容易理解的递归来实践一下二叉树的最简单操作。
这里用智能指针shared_ptr优化了leetCode最常见的二叉树数据结构版本。
头文件:
#ifndef _TREE_H_
#define _TREE_H_
#include <memory>
#include <vector>
#include <iostream>
/*************************************************
class :二叉树节点
brief :Definition for a binary tree node.( -- leetCode)
author :zhoufang
date 2021/11/22
**************************************************/
namespace BinaryTree {
//二叉树的智能指针版本
struct TreeNode {
int val; //当前节点的值
std::shared_ptr<TreeNode> left; //左孩子节点
std::shared_ptr<TreeNode> right; //右孩子节点
/* 重载的三个构造函数*/
TreeNode() :val(0), left(nullptr), right(nullptr) {}
TreeNode(int val) :val(val), left(nullptr), right(nullptr) {}
TreeNode(int val, std::shared_ptr<TreeNode> left, std::shared_ptr<TreeNode> right) : val(val), left(left), right(right) {}
};
using TreeNodePtr = std::shared_ptr<TreeNode>;
/**
* @brief 显示二叉树当前节点值
* @param root 二叉树根节点
*/
void disPlayBiTree(const TreeNodePtr& root);
/**
* @brief 递归先序创建二叉树
* @param root 二叉树根节点
* @return 是否成功创建二叉树
*/
bool createBinaryTree(TreeNodePtr& root);
//bool createBinaryTree(TreeNodePtr &root,const std::vector<int>& vals);
/**
* @brief (递归)先序遍历二叉树
* @param root 二叉树根节点
*/
void preOrderTraverse(const TreeNodePtr& root);
/**
* @brief (递归)中序遍历二叉树
* @param root 二叉树根节点
*/
void inOrderTraverse(const TreeNodePtr& root);
/**
* @brief (递归)后序遍历二叉树
* @param root 二叉树根节点
*/
void postOrderTraverse(const TreeNodePtr& root);
}
#endif//!_TREE_H_if
cpp:
#include <stack>
#include "Tree.h"
using namespace std;
void BinaryTree::disPlayBiTree(const TreeNodePtr& root)
{
if(!root)return;
cout << root->val;
}
bool BinaryTree::createBinaryTree(BinaryTree::TreeNodePtr& root)
{
int value;
cin >> value;
if (value == 0)
{
root = nullptr;
}
else
{
root->val = value;
BinaryTree::createBinaryTree(root->left = std::make_shared<BinaryTree::TreeNode>());
BinaryTree::createBinaryTree(root->right = std::make_shared<BinaryTree::TreeNode>());
}
return true;
}
void BinaryTree::preOrderTraverse(const BinaryTree::TreeNodePtr& root)
{
if (root)//根节点存在
{
//打印根节点存储值
disPlayBiTree(root);
//先序遍历左子树
BinaryTree::preOrderTraverse(root->left);
//先序遍历右子树
BinaryTree::preOrderTraverse(root->right);
}
}
void BinaryTree::inOrderTraverse(const TreeNodePtr& root)
{
if (root)//根节点存在
{
//中序遍历左子树
BinaryTree::inOrderTraverse(root->left);
//打印根节点存储值
disPlayBiTree(root);
//中序遍历右子树
BinaryTree::inOrderTraverse(root->right);
}
}
void BinaryTree::postOrderTraverse(const TreeNodePtr& root)
{
if (root)//根节点存在
{
//后序遍历左子树
BinaryTree::postOrderTraverse(root->left);
//后序遍历右子树
BinaryTree::postOrderTraverse(root->right);
//打印根节点存储值
disPlayBiTree(root);
}
}