二叉树
简单介绍
二叉树(BinaryTree),就是一棵有左右两个节点的树,这里不再具体讲二叉树的原理是什么,而是着重于二叉树的C++代码实现。不同于一般的二叉树实现,这里更突出如何实现二叉树的迭代器,以及如何串行化初始化一棵二叉树。
注意:代码中使用了 C++17 的特性 if constexpr
BinaryTree 类内的成员函数速览
size_t height() - 获取树的高度size_t size() - 获取树的节点数iterator root_node() - 获取树的根节点(迭代器)const_iterator root_node() const - 同上,常量迭代器版本iterator insert_left(iterator node, const _Ty& val) - 在节点左侧插入一个节点,如果已经存在左节点则替换值iterator insert_right(iterator node, const _Ty& val) - 在节点右侧插入一个节点,如果已经存在右节点则替换值iterator erase(iterator node) - 删除一个节点以及该节点往下的子节点preorder_iterator preorder(const iterator& itr = iterator(nullptr, nullptr)) - 获取先序遍历的迭代器preorder_const_iterator preorder_const(const iterator& itr = iterator(nullptr, nullptr)) - 获取先序遍历的常量迭代器inorder_iterator inorder(const iterator& itr = iterator(nullptr, nullptr)) - 获取中序遍历的迭代器inorder_const_iterator inorder_const(const iterator& itr = iterator(nullptr, nullptr)) - 获取中序遍历的常量迭代器postorder_iterator postorder(const iterator& itr = iterator(nullptr, nullptr)) - 获取后序遍历的迭代器postorder_const_iterator postorder_const(const iterator& itr = iterator(nullptr, nullptr)) - 获取后序遍历的常量迭代器preorder_reverse_iterator preorder_reverse(const iterator& itr = iterator(nullptr, nullptr)) - 获取先序遍历的反向迭代器preorder_reverse_const_iterator preorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) - 获取先序遍历的反向常量迭代器inorder_reverse_iterator inorder_reverse(const iterator& itr = iterator(nullptr, nullptr)) - 获取中序遍历的反向迭代器inorder_reverse_const_iterator inorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) - 获取中序遍历的反向常量迭代器postorder_reverse_iterator postorder_reverse(const iterator& itr = iterator(nullptr, nullptr)) - 获取后序遍历的反向迭代器postorder_reverse_const_iterator postorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) - 获取后序遍历的反向常量迭代器
节点的实现
想要实现一棵二叉树,首先得实现它的节点。该节点应该要具有以下特征:
- 储存了节点的值
- 可以访问左右节点
当然,一般而言,二叉树实现以上两点即可,当时为了便于后面迭代器的实现,这里还另外存储了父节点,使得子节点可以访问父节点。
template<class _Ty>
class BinaryTree
{
private:
struct BinaryTreeNode
{
_Ty val;
BinaryTreeNode* parent = nullptr;
BinaryTreeNode* left = nullptr;
BinaryTreeNode* right = nullptr;
BinaryTreeNode() { val = _Ty(); }
BinaryTreeNode(_Ty val, BinaryTreeNode* parent = nullptr) :val(val), parent(parent) {}
~BinaryTreeNode()
{
if (left) delete left;
if (right) delete right;
}
BinaryTreeNode(const BinaryTreeNode& node)
{
this->val = node.val;
if (node.left) this->left = new BinaryTreeNode(node.left);
if (node.right) this->right = new BinaryTreeNode(node.right);
}
size_t size() const
{
const size_t left_sz = left == nullptr ? 0 : left->size();
const size_t right_sz = right == nullptr ? 0 : right->size();
return 1 + left_sz + right_sz;
}
size_t height() const
{
const size_t left_height = left == nullptr ? 0 : left->height();
const size_t right_height = right == nullptr ? 0 : right->height();
return 1 + std::max(left_height, right_height);
}
};
...
}
节点的获取、插入和删除
因为我们实现的二叉树是有迭代器的,因此节点的获取、插入和删除均是借由迭代来完成。这里有一点需要注意的是:需要判断迭代器是否是该容器的。
template<class _Ty>
class BinaryTree
{
public:
iterator root_node()
{
return iterator(root, this);
}
const_iterator root_node() const
{
return const_iterator(root, this);
}
iterator insert_left(iterator node, const _Ty& val)
{
if (node.container != this) throw "WrongIterator";
if (node.now->left)
{
node.now->left->val = val;
}
else
{
node.now->left = new BinaryTreeNode(val);
node.now->left->parent = node.now;
}
return node.left();
}
iterator insert_right(iterator node, const _Ty& val)
{
if (node.container != this) throw "WrongIterator";
if (node.now->right)
{
node.now->right->val = val;
}
else
{
node.now->right = new BinaryTreeNode(val);
node.now->right->parent = node.now;
}
return node.right();
}
iterator erase(iterator node)
{
if (node.container != this) throw "WrongIterator";
if (node.now == root) throw "CanNotEraseRoot";
iterator parent = node.parent();
if (parent.now->left == node.now) parent.now->left = nullptr;
else if (parent.now->right == node.now) parent.now->right = nullptr;
delete node.now;
return parent;
}
...
}
迭代器的实现
对节点做迭代器的封装并不难,难的是如何让迭代器在先序遍历、中序遍历、后序遍历三种不同的遍历情况下取 上一个节点 和 下一个节点 (只用当前节点的状态进行推断)。这里我们只说怎么取得 下一个节点 , 上一个节点 用类似方法也可以得出如何遍历取得。
1.先序遍历
对于先序遍历,遍历的顺序是:自己 -> 左 -> 右,如下图所示:
第一步遍历
第二步遍历
第五步遍历
第三步遍历
第四步遍历
第六步遍历
NULL空节点
这里可以看出,这里遍历的起点是根节点,结束的节点是最右侧节点。假设我们的迭代器所在节点有左子节点的话,下一步遍历便是左子节点。如果没有左子节点,但是有右子节点的话,下一步遍历就是右子节点。但如果没有子节点,我们便要回退,找到一个有右节点的父节点,且该父节点的右节点不为自己的节点,这个父节点的右子节点便是下一个要遍历的节点(关于回退这一点,具体可见 第三步遍历到第四步遍历 和 第四步遍历到第五步遍历)。
{
if (now->parent)
{
if (now == now->parent->left)
now = now->parent;
else if (now == now->parent->right && now->parent->left == nullptr)
now = now->parent;
else
{
now = now->parent->left;
while (now->left || now->right)
now = now->right == nullptr ? now->left : now->right;
}
}
else
{
while (now->right)
now = now->right;
}
}
{
if (now->left)
now = now->left;
else if (now->right)
now = now->right;
else if(now->parent)
{
do
{
if (now->parent->right != nullptr && now->parent->right != now)
{
now = now->parent->right;
break;
}
else
{
now = now->parent;
}
} while (now->parent);
}
}
2.中序遍历
对于先序遍历,遍历的顺序是:左 -> 自己 -> 右,如下图所示:
第五步遍历
第三步遍历
第八步遍历
第一步遍历
第四步遍历
第七步遍历
NULL空节点
NULL空节点
第二步遍历
第六步遍历
NULL空节点
可以看出,这里遍历的起点与先序遍历不同,是从最左侧节点开始的,并且以最右侧节点为结束节点。首先,因为遍历永远从左节点开始,因为下一个节点永远不可能是自己的左子节点以及自己的左子节点所在下面的部分。假设节点有右节点,那么下一个节点就是右子节点的最左侧节点(具体见第五步遍历到第六步遍历)。假设节点没有子节点,那么就看看自己是父节点的左子节点还是右子节点,如果自己是父节点的左子节点,那么下一个节点就是自己的父节点,如果自己是父节点的右子节点,那么把节点转移到父节点这个位置上,重新做上述流程(具体见 第二步遍历到第三步遍历 和 第六步遍历到第七步遍历)。
{
if (now->left)
{
now = now->left;
while (now->right)
now = now->right;
}
else if (now->parent)
{
if (now == now->parent->right)
now = now->parent;
else
{
bool left_jump = true;
do
{
if (now == now->parent->right)
{
left_jump = false;
now = now->parent;
break;
}
now = now->parent;
} while (now->parent);
if(left_jump && now->parent == nullptr)
while (now->right)
now = now->right;
}
}
else
{
while (now->right)
now = now->right;
}
}
{
if (now->right)
{
now = now->right;
while (now->left)
now = now->left;
}
else if (now->parent && now == now->parent->left)
now = now->parent;
else if (now->parent && now == now->parent->right)
{
bool right_jump = true;
do
{
if (now->parent->left == now)
{
now = now->parent;
right_jump = false;
break;
}
now = now->parent;
} while (now->parent);
if(right_jump && now->parent == nullptr)
while (now->left)
now = now->left;
}
else
{
while (now->left)
now = now->left;
}
}
3.后序遍历
对于后序遍历,遍历的顺序是:左 -> 右 -> 自己,如下图所示:
第八步遍历
第四步遍历
第七步遍历
第二步遍历
第三步遍历
第六步遍历
NULL空节点
NULL空节点
第一步遍历
第五步遍历
NULL空节点
可以看出,这里的根节点反而是结束的节点了,最左侧的最下侧的节点才是开始的节点。这里更直接了,由于后序遍历的性质,下一个节点压根不可能是自己的子节点以及往下的部分,我们只需考虑自己在父节点中的位置即可。假设自己是父节点的左子节点,如果父节点没有右子节点,那么下一个节点就是父节点(具体见 第五步遍历到第六步遍历 及 第六步遍历到第七步遍历);如果父节点有右子节点,那么下一个节点就是父节点的右节点的最左侧的最下侧(具体见 第四步遍历到第五步遍历)。假设自己是父节点的右节点,那么下一个节点就是父节点(具体见 第一步遍历到第二步遍历 及 第三步遍历到第四步遍历)。
{
if (now->right)
now = now->right;
else if (now->left)
now = now->left;
else if (now->parent)
{
do
{
if (now->parent->left != nullptr && now->parent->right == now)
{
now = now->parent->left;
break;
}
now = now->parent;
} while (now->parent);
}
}
{
if (now->parent && now->parent->right == nullptr && now->parent->left == now)
now = now->parent;
else if (now->parent && now->parent->right == now)
now = now->parent;
else if (now->parent && now->parent->right != nullptr && now->parent->left == now)
{
now = now->parent->right;
while (now->left || now->right)
now = now->left == nullptr ? now->right : now->left;
}
else
{
while (now->left || now->right)
now = now->left == nullptr ? now->right : now->left;
}
}
迭代器的获取
在完成了的迭代器的前向和后向移动后,便可以提供多种多样的迭代器了。
template<class _Ty>
class BinaryTree
{
public:
using iterator = _IteratorBase<_Ty>;
using const_iterator = _IteratorBase<const _Ty>;
using preorder_iterator = _Iterator<_Ty, -1>;
using preorder_const_iterator = _Iterator<const _Ty, -1>;
using inorder_iterator = _Iterator<_Ty, 0>;
using inorder_const_iterator = _Iterator<const _Ty, 0>;
using postorder_iterator = _Iterator<_Ty, 1>;
using postorder_const_iterator = _Iterator<const _Ty, 1>;
using preorder_reverse_iterator = _Reverse_Iterator<preorder_iterator>;
using preorder_reverse_const_iterator = _Reverse_Iterator<preorder_const_iterator>;
using inorder_reverse_iterator = _Reverse_Iterator<inorder_iterator>;
using inorder_reverse_const_iterator = _Reverse_Iterator<inorder_const_iterator>;
using postorder_reverse_iterator = _Reverse_Iterator<postorder_iterator>;
using postorder_reverse_const_iterator = _Reverse_Iterator<postorder_const_iterator>;
preorder_iterator preorder(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return preorder_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return preorder_iterator(itr.now, this, false);
}
preorder_const_iterator preorder_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return preorder_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return preorder_const_iterator(itr.now, this, false);
}
inorder_iterator inorder(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return inorder_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return inorder_iterator(itr.now, this, false);
}
inorder_const_iterator inorder_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return inorder_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return inorder_const_iterator(itr.now, this, false);
}
postorder_iterator postorder(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return postorder_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return postorder_iterator(itr.now, this, false);
}
postorder_const_iterator postorder_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return postorder_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return postorder_const_iterator(itr.now, this, false);
}
preorder_reverse_iterator preorder_reverse(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return preorder_reverse_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return preorder_reverse_iterator(itr.now, this, false);
}
preorder_reverse_const_iterator preorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return preorder_reverse_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return preorder_reverse_const_iterator(itr.now, this, false);
}
inorder_reverse_iterator inorder_reverse(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return inorder_reverse_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return inorder_reverse_iterator(itr.now, this, false);
}
inorder_reverse_const_iterator inorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return inorder_reverse_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return inorder_reverse_const_iterator(itr.now, this, false);
}
postorder_reverse_iterator postorder_reverse(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return postorder_reverse_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return postorder_reverse_iterator(itr.now, this, false);
}
postorder_reverse_const_iterator postorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return postorder_reverse_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return postorder_reverse_const_iterator(itr.now, this, false);
}
...
}
串行初始化的实现
在各种涉及到树的题目中,我们经常能见到树的串行初始化数据,那么我们怎么自己实现串行数据初始化一棵二叉树呢?
串行初始化一个树的过程可以描述为:
- 对于串行数据,依次获取下一个节点的初始化值,如果值为nullptr,说明下一个节点为空,否则初始化下一个节点;
- 对于一颗二叉树,初始化的顺序为层序,即先将某一层初始化完毕,再初始化下一层;
- 同一层内,初始化的顺序为从左到右。
为了在 C++ 中实现数据和nullptr可以同时输入到串行化序列中。我们首先要实现一个包装类如下:
template<class _Ty>
class BinaryTree
{
private:
struct serial_initializer
{
const _Ty* val = nullptr;
serial_initializer(const void*) {}
serial_initializer(const _Ty& val)
{
this->val = &val;
}
bool isNull() const
{
return val == nullptr;
}
const _Ty& getVal() const
{
return *val;
}
};
...
}
实现这一包装类后,我们可以配合 initializer_list 完成串行序列初始化。
template<class _Ty>
class BinaryTree
{
public:
BinaryTree(std::initializer_list<serial_initializer> ini_list)
{
if (ini_list.size() == 0 || ini_list.begin()->isNull()) throw "WrongInitializer";
root = new BinaryTreeNode(ini_list.begin()->getVal());
BinaryTreeNode** all_nodes = new BinaryTreeNode * [ini_list.size()]{ nullptr };
BinaryTreeNode** nodes = all_nodes;
BinaryTreeNode** next_nodes = all_nodes + (ini_list.size() >> 1);
size_t nodes_size = 0, next_nodes_size = 0;
bool write_left = true;
nodes[0] = root;
nodes_size = 1;
size_t idx = 0;
for (auto itr = ini_list.begin() + 1; itr != ini_list.end(); ++itr)
{
if (!itr->isNull())
{
if (write_left)
{
nodes[idx]->left = new BinaryTreeNode(itr->getVal());
nodes[idx]->left->parent = nodes[idx];
next_nodes[next_nodes_size++] = nodes[idx]->left;
}
else
{
nodes[idx]->right = new BinaryTreeNode(itr->getVal());
nodes[idx]->right->parent = nodes[idx];
next_nodes[next_nodes_size++] = nodes[idx]->right;
}
}
write_left = !write_left;
if (write_left && ++idx >= nodes_size)
{
if (next_nodes_size == 0) break;
std::swap(nodes, next_nodes);
std::swap(nodes_size, next_nodes_size);
idx = 0;
next_nodes_size = 0;
}
}
delete[] all_nodes;
}
...
}
完整代码
#ifndef __YYYCZ_BINARY_TREE__
#define __YYYCZ_BINARY_TREE__
#include<initializer_list>
#include<xtr1common>
#include<utility>
#include<iterator>
namespace YYYCZ
{
template<class _Ty>
class BinaryTree
{
using _Self = BinaryTree<_Ty>;
struct serial_initializer
{
const _Ty* val = nullptr;
serial_initializer(const void*) {}
serial_initializer(const _Ty& val)
{
this->val = &val;
}
bool isNull() const
{
return val == nullptr;
}
const _Ty& getVal() const
{
return *val;
}
};
struct BinaryTreeNode
{
_Ty val;
BinaryTreeNode* parent = nullptr;
BinaryTreeNode* left = nullptr;
BinaryTreeNode* right = nullptr;
BinaryTreeNode() { val = _Ty(); }
BinaryTreeNode(_Ty val, BinaryTreeNode* parent = nullptr) :val(val), parent(parent) {}
~BinaryTreeNode()
{
if (left) delete left;
if (right) delete right;
}
BinaryTreeNode(const BinaryTreeNode& node)
{
this->val = node.val;
if (node.left) this->left = new BinaryTreeNode(node.left);
if (node.right) this->right = new BinaryTreeNode(node.right);
}
size_t size() const
{
const size_t left_sz = left == nullptr ? 0 : left->size();
const size_t right_sz = right == nullptr ? 0 : right->size();
return 1 + left_sz + right_sz;
}
size_t height() const
{
const size_t left_height = left == nullptr ? 0 : left->height();
const size_t right_height = right == nullptr ? 0 : right->height();
return 1 + std::max(left_height, right_height);
}
};
protected:
BinaryTreeNode* root = nullptr;
protected:
template<class _Val>
class _IteratorBase
{
using _Self = _IteratorBase<_Val>;
using _NoConstSelf = _IteratorBase<std::remove_const_t<_Val>>;
using _ConstSelf = _IteratorBase<const std::remove_const_t<_Val>>;
using _OtherSelf = std::conditional_t<std::is_same_v<_Self, _NoConstSelf>, _ConstSelf, _NoConstSelf>;
friend BinaryTree<std::remove_const_t<_Val>>;
protected:
BinaryTreeNode* now = nullptr;
const BinaryTree* container = nullptr;
public:
_IteratorBase(const BinaryTreeNode* root, const BinaryTree* container)noexcept :container(container)
{
now = const_cast<BinaryTreeNode*>(root);
}
operator _OtherSelf() const noexcept
{
return _OtherSelf(now);
}
_Val* operator->() const
{
return const_cast<_Val*>(&(now->val));
}
_Val& operator*() const
{
return const_cast<_Val&>(now->val);
}
bool hasParent() const
{
return now->parent != nullptr;
}
bool hasLeft() const
{
return now->left != nullptr;
}
bool hasRight() const
{
return now->right != nullptr;
}
_Self& leftMove()
{
if (now->left == nullptr) throw "NoLeft";
now = now->left;
return *this;
}
_Self& rightMove()
{
if (now->right == nullptr) throw "NoRight";
now = now->right;
return *this;
}
_Self& parentMove()
{
if (now->parent == nullptr) throw "NoParent";
now = now->parent;
return *this;
}
_Self left() const
{
auto tmp = *this;
return tmp.leftMove();
}
_Self right() const
{
auto tmp = *this;
return tmp.rightMove();
}
_Self parent() const
{
auto tmp = *this;
return tmp.parentMove();
}
bool operator==(const _Self& itr) const
{
return this->now == itr.now;
}
bool operator!=(const _Self& itr) const
{
return this->now != itr.now;
}
};
template<class _Val, int _Order>
class _Iterator
{
using _Self = _Iterator<_Val, _Order>;
public:
using _Base = _IteratorBase<_Val>;
using ValueType = _Val;
private:
BinaryTreeNode* now = nullptr;
const BinaryTree* container = nullptr;
protected:
void last()
{
if constexpr (_Order == -1)
{
if (now->parent)
{
if (now == now->parent->left)
now = now->parent;
else if (now == now->parent->right && now->parent->left == nullptr)
now = now->parent;
else
{
now = now->parent->left;
while (now->left || now->right)
now = now->right == nullptr ? now->left : now->right;
}
}
else
{
while (now->right)
now = now->right;
}
}
if constexpr (_Order == 0)
{
if (now->left)
{
now = now->left;
while (now->right)
now = now->right;
}
else if (now->parent)
{
if (now == now->parent->right)
now = now->parent;
else
{
bool left_jump = true;
do
{
if (now == now->parent->right)
{
left_jump = false;
now = now->parent;
break;
}
now = now->parent;
} while (now->parent);
if (left_jump && now->parent == nullptr)
while (now->right)
now = now->right;
}
}
else
{
while (now->right)
now = now->right;
}
}
if constexpr (_Order == 1)
{
if (now->right)
now = now->right;
else if (now->left)
now = now->left;
else if (now->parent)
{
do
{
if (now->parent->left != nullptr && now->parent->right == now)
{
now = now->parent->left;
break;
}
now = now->parent;
} while (now->parent);
}
}
}
void next()
{
if constexpr (_Order == -1)
{
if (now->left)
now = now->left;
else if (now->right)
now = now->right;
else if (now->parent)
{
do
{
if (now->parent->right != nullptr && now->parent->right != now)
{
now = now->parent->right;
break;
}
else
{
now = now->parent;
}
} while (now->parent);
}
}
if constexpr (_Order == 0)
{
if (now->right)
{
now = now->right;
while (now->left)
now = now->left;
}
else if (now->parent && now == now->parent->left)
now = now->parent;
else if (now->parent && now == now->parent->right)
{
bool right_jump = true;
do
{
if (now->parent->left == now)
{
now = now->parent;
right_jump = false;
break;
}
now = now->parent;
} while (now->parent);
if (right_jump && now->parent == nullptr)
while (now->left)
now = now->left;
}
else
{
while (now->left)
now = now->left;
}
}
if constexpr (_Order == 1)
{
if (now->parent && now->parent->right == nullptr && now->parent->left == now)
now = now->parent;
else if (now->parent && now->parent->right == now)
now = now->parent;
else if (now->parent && now->parent->right != nullptr && now->parent->left == now)
{
now = now->parent->right;
while (now->left || now->right)
now = now->left == nullptr ? now->right : now->left;
}
else
{
while (now->left || now->right)
now = now->left == nullptr ? now->right : now->left;
}
}
}
public:
_Iterator(const BinaryTreeNode* root, const BinaryTree* container, bool adjust_place = true)noexcept :container(container)
{
now = const_cast<BinaryTreeNode*>(root);
if (!adjust_place) return;
if constexpr (_Order == -1)
{
}
if constexpr (_Order == 0)
{
while (now->left)
now = now->left;
}
if constexpr (_Order == 1)
{
while (now->left || now->right)
now = now->left == nullptr ? now->right : now->left;
}
}
operator _Base() const noexcept
{
return _Base(now, container);
}
_Base generalization() const noexcept
{
return _Base(now, container);
}
ValueType* operator->() const
{
return const_cast<ValueType*>(&(now->val));
}
ValueType& operator*() const
{
return const_cast<ValueType&>(now->val);
}
_Self& operator++()
{
this->next();
return *this;
}
_Self operator++(int)
{
_Self tmp = *this;
this->next();
return tmp;
}
_Self& operator--()
{
this->last();
return *this;
}
_Self operator--(int)
{
_Self tmp = *this;
this->last();
return tmp;
}
bool operator==(const _Self& itr) const
{
return this->now == itr.now;
}
bool operator!=(const _Self& itr) const
{
return this->now != itr.now;
}
};
template<class _Itr>
class _Reverse_Iterator
{
using _Self = _Reverse_Iterator<_Itr>;
public:
using _Base = typename _Itr::_Base;
using ValueType = typename _Itr::ValueType;
private:
_Itr iter;
public:
_Reverse_Iterator(const BinaryTreeNode* root, const BinaryTree* container, bool adjust_place = true) noexcept :iter(root, container)
{
if (!adjust_place) return;
--(this->iter);
}
operator _Base() const noexcept
{
return _Base(iter);
}
_Base generalization() const noexcept
{
return _Base(iter);
}
ValueType* operator->() const
{
return iter.operator->();
}
ValueType& operator*() const
{
return iter.operator*();
}
_Self& operator++()
{
--iter;
return *this;
}
_Self operator++(int)
{
_Self tmp = *this;
--iter;
return tmp;
}
_Self& operator--()
{
++iter;
return *this;
}
_Self operator--(int)
{
_Self tmp = *this;
++iter;
return tmp;
}
bool operator==(const _Self& itr) const
{
return this->iter == itr.iter;
}
bool operator!=(const _Self& itr) const
{
return this->iter != itr.iter;
}
};
public:
using iterator = _IteratorBase<_Ty>;
using const_iterator = _IteratorBase<const _Ty>;
using preorder_iterator = _Iterator<_Ty, -1>;
using preorder_const_iterator = _Iterator<const _Ty, -1>;
using inorder_iterator = _Iterator<_Ty, 0>;
using inorder_const_iterator = _Iterator<const _Ty, 0>;
using postorder_iterator = _Iterator<_Ty, 1>;
using postorder_const_iterator = _Iterator<const _Ty, 1>;
using preorder_reverse_iterator = _Reverse_Iterator<preorder_iterator>;
using preorder_reverse_const_iterator = _Reverse_Iterator<preorder_const_iterator>;
using inorder_reverse_iterator = _Reverse_Iterator<inorder_iterator>;
using inorder_reverse_const_iterator = _Reverse_Iterator<inorder_const_iterator>;
using postorder_reverse_iterator = _Reverse_Iterator<postorder_iterator>;
using postorder_reverse_const_iterator = _Reverse_Iterator<postorder_const_iterator>;
public:
BinaryTree()
{
root = new BinaryTreeNode;
}
BinaryTree(const _Ty& val)
{
root = new BinaryTreeNode(val);
}
~BinaryTree()
{
if (root) delete root;
}
BinaryTree(const _Self& tree)
{
this->root = new BinaryTreeNode(tree.root);
}
BinaryTree(std::initializer_list<serial_initializer> ini_list)
{
if (ini_list.size() == 0 || ini_list.begin()->isNull()) throw "WrongInitializer";
root = new BinaryTreeNode(ini_list.begin()->getVal());
BinaryTreeNode** all_nodes = new BinaryTreeNode * [ini_list.size()]{ nullptr };
BinaryTreeNode** nodes = all_nodes;
BinaryTreeNode** next_nodes = all_nodes + (ini_list.size() >> 1);
size_t nodes_size = 0, next_nodes_size = 0;
bool write_left = true;
nodes[0] = root;
nodes_size = 1;
size_t idx = 0;
for (auto itr = ini_list.begin() + 1; itr != ini_list.end(); ++itr)
{
if (!itr->isNull())
{
if (write_left)
{
nodes[idx]->left = new BinaryTreeNode(itr->getVal());
nodes[idx]->left->parent = nodes[idx];
next_nodes[next_nodes_size++] = nodes[idx]->left;
}
else
{
nodes[idx]->right = new BinaryTreeNode(itr->getVal());
nodes[idx]->right->parent = nodes[idx];
next_nodes[next_nodes_size++] = nodes[idx]->right;
}
}
write_left = !write_left;
if (write_left && ++idx >= nodes_size)
{
if (next_nodes_size == 0) break;
std::swap(nodes, next_nodes);
std::swap(nodes_size, next_nodes_size);
idx = 0;
next_nodes_size = 0;
}
}
delete[] all_nodes;
}
size_t height() const
{
return root->height();
}
size_t size() const
{
return root->size();
}
iterator root_node()
{
return iterator(root, this);
}
const_iterator root_node() const
{
return const_iterator(root, this);
}
iterator insert_left(iterator node, const _Ty& val)
{
if (node.container != this) throw "WrongIterator";
if (node.now->left)
{
node.now->left->val = val;
}
else
{
node.now->left = new BinaryTreeNode(val);
node.now->left->parent = node.now;
}
return node.left();
}
iterator insert_right(iterator node, const _Ty& val)
{
if (node.container != this) throw "WrongIterator";
if (node.now->right)
{
node.now->right->val = val;
}
else
{
node.now->right = new BinaryTreeNode(val);
node.now->right->parent = node.now;
}
return node.right();
}
iterator erase(iterator node)
{
if (node.container != this) throw "WrongIterator";
if (node.now == root) throw "CanNotEraseRoot";
iterator parent = node.parent();
if (parent.now->left == node.now) parent.now->left = nullptr;
else if (parent.now->right == node.now) parent.now->right = nullptr;
delete node.now;
return parent;
}
preorder_iterator preorder(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return preorder_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return preorder_iterator(itr.now, this, false);
}
preorder_const_iterator preorder_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return preorder_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return preorder_const_iterator(itr.now, this, false);
}
inorder_iterator inorder(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return inorder_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return inorder_iterator(itr.now, this, false);
}
inorder_const_iterator inorder_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return inorder_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return inorder_const_iterator(itr.now, this, false);
}
postorder_iterator postorder(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return postorder_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return postorder_iterator(itr.now, this, false);
}
postorder_const_iterator postorder_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return postorder_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return postorder_const_iterator(itr.now, this, false);
}
preorder_reverse_iterator preorder_reverse(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return preorder_reverse_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return preorder_reverse_iterator(itr.now, this, false);
}
preorder_reverse_const_iterator preorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return preorder_reverse_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return preorder_reverse_const_iterator(itr.now, this, false);
}
inorder_reverse_iterator inorder_reverse(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return inorder_reverse_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return inorder_reverse_iterator(itr.now, this, false);
}
inorder_reverse_const_iterator inorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return inorder_reverse_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return inorder_reverse_const_iterator(itr.now, this, false);
}
postorder_reverse_iterator postorder_reverse(const iterator& itr = iterator(nullptr, nullptr))
{
if (itr.now == nullptr) return postorder_reverse_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return postorder_reverse_iterator(itr.now, this, false);
}
postorder_reverse_const_iterator postorder_reverse_const(const iterator& itr = iterator(nullptr, nullptr)) const
{
if (itr.now == nullptr) return postorder_reverse_const_iterator(root, this);
if (itr.container != this) throw "WrongIterator";
return postorder_reverse_const_iterator(itr.now, this, false);
}
};
}
#endif
测试代码
#include<iostream>
#include "BinaryTree.h"
using namespace std;
using namespace YYYCZ;
int main()
{
BinaryTree<int> tree{ 1,2,6,3,5,8,7,nullptr,4,nullptr,nullptr,9 };
BinaryTree<int> tree2{ 1 };
{
cout << "先序遍历:" << endl;
auto itr = tree.preorder();
do
{
cout << *itr << " ";
} while (++itr != tree.preorder());
cout << endl;
}
{
cout << "中序遍历:" << endl;
auto itr = tree.inorder();
do
{
cout << *itr << " ";
} while (++itr != tree.inorder());
cout << endl;
}
{
cout << "反向中序遍历:" << endl;
auto itr = tree.inorder_reverse();
do
{
cout << *itr << " ";
} while (++itr != tree.inorder_reverse());
cout << endl;
}
{
cout << "以根节点的左节点为起点的后序遍历:" << endl;
auto itr = tree.postorder(tree.root_node().left());
do
{
cout << *itr << " ";;
} while (++itr != tree.postorder());
cout << endl;
}
{
try
{
tree2.erase(tree.root_node());
}
catch (const char* msg)
{
cerr << "Error Message: " << msg << endl;
}
}
return 0;
}
|