赞
踩
预告:本文是后续实现各种各样平衡二叉搜索树的铺垫。
Vector call by rank
List call by position
Hash table call by value
扩:从不可重复到可重复的扩充(下图)
方法 | 功能 | 参数 | 返回值 |
---|---|---|---|
search | 查找 | T const & val | BinNode * & 待插入位置/目标节点指针的引用 |
insert | 插入 | BinNode * 新节点指针 | |
remove | 移除 | bool 树上是否存在值为val的节点 |
看到searchIn的声明,居然全都是引用类型。
static BinNode<T> * & searchIn(BinNode<T> * & rt, BinNode<T> * & hot_node, T const & val)
列举这四个引用各自的功能——
返回值引用:插入节点时,这个引用相当于插入位置,后续我们将新节点的指针赋给到这个返回值,父节点的左右孩子之一就会连上新节点。
BinNode<T> * & rt
:如果这个不是引用,返回值返回的就是一个仅在函数内部的局部变量(即形参),后续改写这个引用值时,会发生错误。
BinNode<T> * & hot_node
:在递归中随深度不断更新这个记忆热点,也是为了方便插入算法,等到最后退出时hot存的是插入位置的父节点。
T const & val
:传递引用变量可以提速,为了不误改,前面加上const做约束。
virtual BinNode<T> * & search(T const & val)
{
return searchIn(BinTree<T>::root, hot = NULL, val); //注意,这个=NULL,如果不写,插入根节点并向上更新高度时就会报错
}
static BinNode<T> * & searchIn(BinNode<T> * & rt, BinNode<T> * & hot_node, T const & val)
{
if (!rt || rt->data == val) return rt; // 返回的是引用
hot_node = rt; //在递归中随深度不断更新
if (val < rt->data) return searchIn(rt->left, hot_node, val);
else return searchIn(rt->right, hot_node, val);
}
尾递归转迭代,略。
有了查找节点算法中“记忆热点”hot的设计,经过search()
的运行,就可以得到插入位置的父节点。或许应该记得BinTree
里写过的几个函数:insertAsLeft()
,insertAsRight()
,我们只需要将val
与hot->data
做比较即可。在这里,我们换一种写法——不浪费search
的返回值。你知道,查找一旦失败,返回值就是NULL
的引用,利用它,就无需在insert()
中判断究竟应该插入到hot的左边还是右边。
先找到插入位置,X的类型必须是引用,后续我们将新节点的指针赋给到X,hot的左右孩子之一就会连上新节点。
BinNode<T> * & X = search(val);
下面这一句话将 “父->子” “子->父” 相互关系都连接好了。
X = new BinNode(val, hot);
更新高度由于之前做的优化,检测到某处更新后与更新前高度一致则不会再上行更新,所以高度更新要给父节点更新,即updateHighAbove(hot)
,如果给了X更新,那就不会继续下去。
virtual BinNode<T> * insert(T const & val)
{
BinNode<T> * & X = search(val); //为了找到插入位置
if (!X)
{
X = new BinNode(val, hot); //这一句话将两个关系连接
// 不要忘记
BinTree<T>::size++;
updateHighAbove(hot);
}
return X;
}
insert()
的返回值是X,但返回类型是BinNode<T> *
,并不是引用,这在语法中是允许的。所返回的东西仅仅在数值上与X相同,但与X完全脱离了关系。
virtual bool remove(T const & val)
{
BinNode<T> * & X = search(val);
if (!X) //树里没有val
{
return false;
}
else
{
removeAt(X, hot);
BinTree<T>::size--;
updateHighAbove(hot);
return true;
}
}
还是想,哪一个节点替代被删节点的位置。那一定是直接后继。求中序遍历下的直接后继。
// struct BinNode中,功能:求中序遍历下的直接后继 BinNode<T> * succ() { BinNode<T> * succ_node; if (right) { succ_node = right; while (succ_node->left) succ_node = succ_node->left; } else { succ_node = this; while (succ_node != succ_node->parent->left) succ_node = succ_node->parent; succ_node = succ_node->parent; } return succ_node; }
BinNode<T> * removeAt(BinNode<T> * & X, BinNode<T> * & hot_node) //注意这个引用 { // hot_node指向要被删除的父亲 BinNode<T> * del_node; // 实际要被删除的节点 BinNode<T> * succ_node; // 实际要被删除的节点的接替者 if (!X->left) { del_node = X; succ_node = X->right; X = X->right; } else if (!X->right) { del_node = X; succ_node = X->left; X = X->left; } else // 双分支情况 { // 找到中序的直接后继 del_node = X->succ(); succ_node = del_node->right; swap(del_node->data, X->data); BinTree<T>::fromParentTo(del_node) = succ_node; } hot_node = del_node->parent; if (succ_node) succ_node->parent = hot_node; delete del_node; return succ_node; }
# pragma once # include "BinTree.h" template <typename T> void swap(T & a, T & b) { T t; t = a; a = b; b = t; } template <typename T> class BST : public BinTree<T> { public: //***********************************************************查找********************************************************* virtual BinNode<T> * & search(T const & val) { return searchIn(BinTree<T>::root, hot = NULL, val); } static BinNode<T> * & searchIn(BinNode<T> * & rt, BinNode<T> * & hot_node, T const & val) { if (!rt || rt->data == val) return rt; // 返回的是引用 hot_node = rt; //在递归中随深度不断更新 if (val < rt->data) return searchIn(rt->left, hot_node, val); else return searchIn(rt->right, hot_node, val); } //***********************************************************插入********************************************************* virtual BinNode<T> * insert(T const & val) { BinNode<T> * & X = search(val); //为了找到插入位置 if (!X) { X = new BinNode<T>(val, hot); //这一句话将两个关系连接 // 不要忘记 BinTree<T>::size++; BinTree<T>::updateHighAbove(hot); } return X; } //***********************************************************删除********************************************************* virtual bool remove(T const & val) { BinNode<T> * & X = search(val); if (!X) //树里没有val { return false; } else { removeAt(X, hot); BinTree<T>::size--; BinTree<T>::updateHighAbove(hot); return true; } } BinNode<T> * removeAt(BinNode<T> * & X, BinNode<T> * & hot_node) //注意!!!这个引用 { // hot_node指向要被删除的父亲 BinNode<T> * del_node; // 实际要被删除的节点 BinNode<T> * succ_node; // 实际要被删除的节点的接替者 if (!X->left) { del_node = X; succ_node = X->right; X = X->right; } else if (!X->right) { del_node = X; succ_node = X->left; X = X->left; } else // 双分支情况 { // 找到中序的直接后继 del_node = X->succ(); succ_node = del_node->right; swap(del_node->data, X->data); BinTree<T>::fromParentTo(del_node) = succ_node; } hot_node = del_node->parent; if (succ_node) succ_node->parent = hot_node; delete del_node; return succ_node; } //******************************************************统一重平衡算法**************************************************** // 在AVL中有极大用处 BinNode<T> * connect34(BinNode<T> *, BinNode<T> *, BinNode<T> *, BinNode<T> *, BinNode<T> *, BinNode<T> *, BinNode<T> *); BinNode<T> * rotateAt(BinNode<T> * x); protected: BinNode<T> * hot; // 命中节点的父亲 }; template <typename T> BinNode<T> * BST<T>::connect34(BinNode<T> * a, BinNode<T> * b, BinNode<T> * c, BinNode<T> * T1, BinNode<T> * T2, BinNode<T> *T3, BinNode<T> * T4) { b->left = a; b->right = c; a->left = T1; a->right = T2; c->left = T3; c->right = T4; a->parent = b; c->parent = b; if (T1) T1->parent = a; if (T2) T2->parent = a; if (T3) T3->parent = c; if (T4) T4->parent = c; a->updateHigh(); b->updateHigh(); c->updateHigh(); return b; } template <typename T> BinNode<T> * BST<T>::rotateAt(BinNode<T> * v) { BinNode<T> * p = v->parent; BinNode<T> * g = p->parent; BinNode<T> * T1, *T2, *T3, *T4, *a, *b, *c; if (p == g->left && v == p->left) { a = v; b = p; c = g; T1 = v->left; T2 = v->right; T3 = p->right; T4 = g->right; } else if (p == g->left && v == p->right) { a = p; b = v; c = g; T1 = p->left; T2 = v->left; T3 = v->right; T4 = g->right; } else if (p == g->right && v == p->left) { a = g; b = v; c = p; T1 = g->left; T2 = v->left; T3 = v->right; T4 = p->right; } else { a = g; b = p; c = v; T1 = g->left; T2 = p->left; T3 = v->left; T4 = v->right; } b->parent = g->parent; //向上链接 return connect34(a, b, c, T1, T2, T3, T4); }
谢谢观看~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。