下面是其他函数的一个详解,+表示是public函数,-表示private
函数 | 作用 |
---|---|
+ insert | 插入一个元素 |
+ empty | 二叉树是否为空 |
+ exists | 判断元素是否存在 |
+ clear | 非递归清空二叉树 |
+ erase | 清除指定根节点及其所有子节点 |
+ size | 元素数量 |
+ minmum | 最小值 |
+ maxmum | 最大值 |
+ max_length_between_node | 最大节点距离 |
+ hight | 树高度 |
- print_binary_tree | 二叉树形式打印二叉树 |
- count_node | 元素个数 |
- find | 查找 |
- maxmum | 最大节点 |
- minmum | 最小节点 |
- successor | 后继节点 |
- hight |
3.1 insert
insert
函数在二叉树的构造函数里已经用到了一次,利用数组构建一个二叉树。在那里对insert
函数所作的行为进行了讲解,所以这里只放上函数
template<typename T>
void binary_tree<T>::insert(const T& data) {
if (0 != root_) {
tree_node* fast, * slow, * ptemp;
fast = slow = ptemp = root_;
while (fast != 0) {
slow = fast;
if (data < slow->data) {
fast = slow->lchild;
}
else if (data > slow->data) {
fast = slow->rchild;
}
else {
fast = 0;
}
// else equal do nothing
}
if (data < slow->data) {
slow->lchild = new tree_node(data);
slow->lchild->parent = slow;
}
else if (data > slow->data) {
slow->rchild = new tree_node(data);
slow->rchild->parent = slow;
}
// else equal do nothing
}
else {
root_ = new tree_node(data);
}
}
3.2 empty
检查二叉树是否为空,只需要判断是否存在根节点root_
即可
// 二叉树是否为空
bool empty(void) const {
return (NULL == root_);
}
3.3 exists
exists
用来判断某个值是否存在,这个和insert
的过程很类似,根据大小来判断,直到找到该值
template<typename T>
bool binary_tree<T>::exists(const T& data) const {
bool result = false;
tree_node* ptr = root_;
while (ptr != 0 && !result) {
if (ptr->data == data) {
result = true; // 这里不再使用break来跳出循环
}
else if (ptr->data < data) {
ptr = ptr->rchild;
}
else {
ptr = ptr->lchild;
}
}
return result;
}
3.4 clear
clear
用来清空二叉树,既然用来清空二叉树,那就需要遍历。前面学习到了,遍历的3种方式中,最简单的方式就是先序遍历,所以这里就是用先序遍历的套路。
template<T>
void binary_tree<T>::clear(void) {
stack<tree_node *> node_stack;
node_stack.push(root_);
tree_node* tmp_node;
while (!node_stack.empty() ) { // 先序遍历
tmp_node = node_stack.top();
node_stack.pop();
if (tmp_node->rchild!=0) {
node_stack.push(tmp_node->rchild);
}
if (tmp_node->lchild!=0) {
node_stack.push(tmp_node->lchild);
}
delete tmp_node; // 删除节点
}
}
3.5 erase
关于这个函数,可能是作者写的时候思路太清晰,不知道这个erase
到底应该实现什么样的功能,其源代码如下
template<typename T>
void binary_tree<T>::erase(const T& data) {
tree_node* iter = find(data);
//delete iter;
}
上述的代码只找到了data
所对应的根节点的位置,但是没有删除。我们在抹除一个节点的时候,要将它的所有子节点一并抹除掉,就像下面这幅图所示
所以,这部分的代码应该和clear
类似,只不过此时的根节点是从find
函数找到的根节点开始的了
template<typename T>
void binary_tree<T>::erase(const T& data) {
tree_node* iter = find(data);
stack<tree_node *> node_stack;
node_stack.push(iter);
tree_node* tmp_node;
while (!node_stack.empty() ) { // 先序遍历
tmp_node = node_stack.top();
node_stack.pop();
if (tmp_node->rchild!=0) {
node_stack.push(tmp_node->rchild);
}
if (tmp_node->lchild!=0) {
node_stack.push(tmp_node->lchild);
}
delete tmp_node; // 删除节点
}
}
3.6 size
size
是计算元素数量的函数,内部使用count_node
函数来实现
template<typename T>
int binary_tree<T>::size(void) const {
return count_node(root_);
}
3.7 minmum
minmum
:得到元素的最小值
之前已经说过了,这棵树是按照大小顺序排好的树了,所以其最左边的节点的值就是最小值
template<typename T>
T binary_tree<T>::minmum(void) const {
const tree_node* p = root_;
while (p->lchild) {
p = p->lchild;
}
return p->data;
}
3.8 maxmum
maxmum
:和minmum
相对。最右边的值是其最大值
template<typename T>
T binary_tree<T>::maxmum(void) const {
const tree_node* p = root_;
while (p->rchild) {
p = p->rchild;
}
return p->data;
}
3.9 height
height
:树的高度
template<typename T>
int binary_tree<T>::hight(void) const {
return hight(root_);
}
其中的height(root_)
这句代码中的height
是私有函数的height
,其定义如下
template<typename T>
int binary_tree<T>::hight(const tree_node* _t) const {
if (_t == nullptr) {
return 0;
}
if (_t->lchild == nullptr && _t->rchild == nullptr) {
return 1;
}
return 1 + std::max<int>(hight(_t->lchild), hight(_t->rchild));
}
上面的代码非常巧妙地利用了递归来计算树的高度,这部分是可以被记住的,因为之前的遍历都是利用的循环,而没有用到递归。现在用了递归以后,可以更加容易理解树的高度的计算过程。
3.10 max_length_between_node
max_length_between_node
:节点之间的最大距离
还是上面那幅图的例子,看一下节点之间的距离如何计算,就像下面这幅图,节点c和节点g的距离是如何计算的?
节点距离6 = c的高度+g的高度
template<typename T>
int binary_tree<T>::max_length_between_node(void) const {
int max_length = 0;
const tree_node* ptree = root_;
list<tree_node*> listNode;
listNode.push_back(root_);
while (!listNode.empty()) {
auto pnode = listNode.front();
listNode.pop_front();
if (pnode->lchild != nullptr) {
listNode.push_back(pnode->lchild);
}
if (pnode->rchild != nullptr) {
listNode.push_back(pnode->rchild);
}
int tempBetween = hight(pnode->lchild) + hight(pnode->rchild);
max_length = std::max<int>(tempBetween, max_length);
}
return max_length;
}
上述代码,只需要给定一个根节点,便可以根据height
函数递归地找到其下面的最高的左子节点和右子节点,然后计算它们的高度之和
3.11 count_node
使用递归形式来进行计算节点数量
template<typename T>
int binary_tree<T>::count_node(const tree_node* ptree) const {
int num1, num2;
if (ptree == NULL)
return 0;
else {
num1 = count_node(ptree->lchild);
num2 = count_node(ptree->rchild);
return (num1 + num2 + 1);
}
}
3.12 find
find
函数和exists
函数基本一样
template<typename T>
typename binary_tree<T>::tree_node* binary_tree<T>::find(const T& data) {
if (root_) {
tree_node* pfind = root_;
while (pfind) {
if (pfind->data == data) {
return pfind;
}
else if (data < pfind->data) {
pfind = pfind->lchild;
}
else
pfind = pfind->rchild;
}
}
return NULL;
}
3.13 minmum和maxmum
和之前的共有函数的minmum和maxmum一样
3.14 successor
目前不知道这个函数拿来干什么用,用处不算很大
template<typename T>
typename binary_tree<T>::tree_node* binary_tree<T>::successor(tree_node* t) const {
if (t->rchild) {
return minmum(t->rchild);
}
else
{
tree_node* fast = t->parent, * slow = t;
while (fast && fast->rchild == slow) {
slow = fast;
fast = fast->parent;
}
return fast;
}
}
3.15 输出二叉树
下面的函数print_binary_tree
是用来输出二叉树的,从bt
作为根节点开始输出其子树
template<typename T>
void binary_tree<T>::print_binary_tree(ostream& out, const tree_node* bt, int depth) const {
// 用右左孩子的方式输出一颗树,先输出右孩子后输出左孩子
if (bt) {
print_binary_tree(out, bt->rchild, depth + 1);
if (depth == 0) {
out << bt->data << endl;
}
else if (depth == 1) {
out << " --" << bt->data << endl;
}
else {
int n = depth;
while (--n) {
cout << " ";
}
out << " --" << bt->data << endl;
}
print_binary_tree(out, bt->lchild, depth + 1);
}
}
上述代码中有一个有趣的句子:out << bt->data << endl
这个out
可不是cout
写错了,而是本身就是一个ostream&
类型的数据。这些ostream
类型的数据通过符号<<
连接起来向屏幕输出。
从上面的print_binary_tree
衍生的函数是从根节点开始输出整棵树的
template<typename T>
void binary_tree<T>::print(ostream& out) const {
print_binary_tree(out, root_, 0);
}
另外,涉及到输出的话一般要对<<
进行重载,这个重载<<
的代码如下
template<typename T>
ostream& operator<<(ostream& out, const binary_tree<T>& tree) {
tree.print(out);
return out;
}