递归实现二叉树
学习数据结构就不得不提到树这个概念,通常学习都是从简单的开始,所以我们也就先从最简单的入手,实现一棵简单的二叉树。并且分别实现前中后序的三种遍历。
提到二叉树,我们首先需要了解二叉树的结构,多的我就不说了,一棵树上有着很多的节点,而每一个节点都有着“自身的值data”,“左子树”,“右子树”;所以我们需要这样来定义一个节点的结构,并将其初始化(通过初始化列表):
template<class T>
struct BinaryTreeNode
{
T _data;
BinaryTreeNode<T>* _left;
BinaryTreeNode<T>* _right;
BinaryTreeNode(const T& x)
: _data(x)
, _left(NULL)
, _right(NULL)
{}
};
二叉树的递归实现
二叉树使用递归实现,那么我们将一个类的基本成员函数用递归实现(①构造函数、②拷贝构造函数、③赋值运算符重载(除外)、④析构函数)。
其中为了方便定义,将节点重命名为Node
①构造函数:
BinaryTree(T* a, size_t size, const T& invalid = T())
{
assert(a);
size_t index = 0;
_root = _CreateTree(a, size, invalid, index);
}
Node* _CreateTree(T* a, size_t size, const T& invalid, size_t& index)
{
if (index < size && a[index] != invalid)
{
Node* root = new Node(a[index]);
root->_left = _CreateTree(a, size, invalid, ++index);
root->_right = _CreateTree(a, size, invalid, ++index);
return root;
}
return NULL;
}
一棵树,递归去实现,我们最需要的是知道如何实现这棵树。对于二叉树的定义我就不多解释了,但是你要根据树的结构去好好想一下,递归是如何实现的。一棵二叉树,从根节点开始,它会不断的向下走,走完了左边,它会再去走右边,而我们需要做的是将这个划分为子问题去想。
以上面的这颗简单的二叉树为例,你从1这个根节点往下走,走到2,再以2为根节点往下走,走到3,再往下走没有节点了,那就返回,然后回到根节点,依次往上回,一直回到1这个根节点,完后再往右走,走到4,然后再往左走,接着将5当做根节点往下走,最后走到7返回,返回到4,然后再往右走,走完后再退回到根节点1,最终完成递归。
当然,我们还要以代码作为解释,首先我们是通过数组建立的树,所以参数里面会传上一个数组和大小,当然,我们肯定需要知道如何判断是否到达叶子节点对吧,所以我们再设置一个不合理的值用来标记是否到达叶子节点,是否还要往下递归。
当然,再代码中你们还会看到一个叫做index的变量,这是干嘛的呢?其实就是用来标记数组的,相当于数组的下标,这样可以方便我们去使用这个数组,当然,很重要的一点就是递归使用它你需要传引用,毕竟它是不断在往下走的,你不能用完就重置,这样就达不到遍历数组的目的了。
②拷贝构造函数:
BinaryTree(const BinaryTree<T>& t)
{
_root = _Copy(t._root);
}
Node* _Copy(Node* root)
{
if (root == NULL)
{
return NULL;
}
Node* NewNode = new Node(root->_data);
NewNode->_left = _Copy(