由于学习树这一章节,查阅了很多资料,网上书上代码上,自己的别人的已然分不开了,如有侵权请留言,如同意我记录于此,也请留言区留下大名,必然感谢!
此篇参考 ----》》》传送门
懒惰删除(lazy deletion):
当一个元素要被删除时,它仍然留在树中,而是只作了个被删除的标记。·这特别是在有重复项时很流行,因为此时记录出现频率数的域可以减1;
·如果树中的实际节点数和“被删除”的节点数相同,那么树的深度预计只上升一个小的常数(由于假设2n个节点,log(2n)-log(n)=1);
算法:
·对于根基,用之前写好的二叉查找树即可;
·在原有成员上添加:BNode内的count 记录该数值的次数 、 theSize 节点数 、delSize 删除节点数 、BNode*max 与 *min 记录相关节点;
·原有成员函数改变:
·insert函数 ,要对相关成员 数值更新 ;
void insert(const Object & x, BNode * & t){ if (t == nullptr){ ++theSize; t = new BNode{ x, nullptr, nullptr }; } else if (x<t->element) insert(x, t->left); else if (x>t->element) insert(x, t->right); else ++t->count; }
·remove函数 只能对count>=1的节点进行删除,且如果删除后 该节点的 count==0,那么相应地delSize+1和theSize-1然后 若theSize<=delSize,则可以真正删除那些应该被删除的节点
void remove(const Object & x, BNode * & t){ if (t == nullptr)return; if (x<t->element) remove(x, t->left); else if (x>t->element) remove(x, t->right); else if (t->count>0 && --(t->count) == 0 && ++delSize >= --theSize){ //若count大于0,则减1;若减1后为0,则delSize加1; //若delSize>=theSize,则执行delete操作 deleteNodes(root); //真正的删除操作 delSize = 0; //delSize归零 } }
·deleteNode函数,实现真正意义上的删除,对于那些count==0的节点,要么找其右子树中未被删除的最小值,要么找其左子树中未被删除的最大值,对于找到的相当于用那个节点替换当前的即可,再递归向下删除~
void deleteNodes(BNode * & t) { if (t == nullptr) return;//空子树,do nothing if (t->count == 0) { //t需要被删除 if ((t->left != nullptr) && (t->right != nullptr)) { if (findMin(t->right)) { //t的两个子树均非空,且在它的右子树中找到了可用的最小结点 t->element = min->element; t->count = min->count; min->count = 0;//右子树中的最小结点即将被删除 deleteNodes(t->left); deleteNodes(t->right); } else if (findMax(t->left)) { t->element = max->element; t->count = max->count; max->count = 0; deleteNodes(t->left); deleteNodes(t->right); } else //t的右子树中的所有结点的count均为0,则将其置空. makeEmpty(t); } else { BNode *oldnode = t; t = t->left ? t->left : t->right; delete oldnode; oldnode = nullptr; if (t != nullptr) deleteNodes(t);//若新的t非空,继续对它执行删除操作 } } else {//t不需要被删除,继续在它的子树中查找 deleteNodes(t->left); deleteNodes(t->right); } }
·findMax和 findMin函数,找最值,这里就返回bool值,判断找到与否即可,至于那个节点,交给max和min去记录了。(这里记录我的一个错误,如果递归函数要返回值,那么每次都要向回溯返回,且如果返回值了,就不要因为回溯过程再被改变)
bool findMin(BNode *t) { if (t) { //不能写成if(t->left) return findMin(t->left); if (findMin(t->left)) return true; if (t->count>0) { min = t; return true; } return findMin(t->right); } return false; } bool findMax(BNode *t) { if (t) { if (findMax(t->right)) return true; if (t->count>0) { max = t; return true; } return findMax(t->left); } return false; }
附上效果图:
附上完整代码:
树的半可视化打印参考: 半可视化打印二叉树
//懒惰删除
template
class BSTree {
public:
BSTree() :root{ nullptr } {}
BSTree(const BSTree & rhs) {
root = clone(rhs.root);
}
~BSTree() { makeEmpty(); }
const Object & findMin() //返回最小值
{
if (!findMin(root))
std::cerr << "The tree is Empty!" << std::endl;
return min->element;
}
const Object & findMax()//返回最大值
{
if (!findMax(root))
std::cerr << "The tree is Empty!" << std::endl;
return max->element;
}
bool isEmpty() const { return root == nullptr; }
//如下函数调用私有成员函数,以多一个指针参数方便后面的递归
void makeEmpty() { makeEmpty(root); }
bool contains(const Object & x) const { return contains(x, root); }
void insert(const Object & x) { insert(x, root); }
void remove(const Object & x) { remove(x, root); }
//半可视化打印树
void printTree(ostream & out = cout) const { printTree(root, out); }
BSTree & operator = (const BSTree & rhs) {
if (this != &rhs) {
makeEmpty();
root = clone(rhs.root);
}
return *this;
}
private:
struct BNode {
Object element;
int count; //记录该值的次数
BNode * left;
BNode * right;
BNode(const Object & theElement = Obejct{}, BNode * lt = nullptr, BNode * rt = nullptr)
:element{ theElement }, left{ lt }, right{ rt } {
count = 1;//一旦新插入一个节点,那么该值次数即为1
}
};
int theSize = 0; //当前节点
int delSize = 0; //删除节点
BNode * root;
BNode *min = nullptr;//用来标记所找的那个节点
BNode *max = nullptr;
bool findMin(BNode *t) {
if (t) {
//不能写成if(t->left) return findMin(t->left);
if (findMin(t->left)) return true;
if (t->count>0) {
min = t;
return true;
}
return findMin(t->right);
}
return false;
}
bool findMax(BNode *t) {
if (t) {
if (findMax(t->right)) return true;
if (t->count>0) {
max = t;
return true;
}
return findMax(t->left);
}
return false;
}
void deleteNodes(BNode * & t) {
if (t == nullptr) return;//空子树,do nothing
if (t->count == 0) {
//t需要被删除
if ((t->left != nullptr) && (t->right != nullptr)) {
if (findMin(t->right)) {
//t的两个子树均非空,且在它的右子树中找到了可用的最小结点
t->element = min->element;
t->count = min->count;
min->count = 0;//右子树中的最小结点即将被删除
deleteNodes(t->left);
deleteNodes(t->right);
}
else if (findMax(t->left)) {
t->element = max->element;
t->count = max->count;
max->count = 0;
deleteNodes(t->left);
deleteNodes(t->right);
}
else //t的右子树中的所有结点的count均为0,则将其置空.
makeEmpty(t);
}
else {
BNode *oldnode = t;
t = t->left ? t->left : t->right;
delete oldnode;
oldnode = nullptr;
if (t != nullptr) deleteNodes(t);//若新的t非空,继续对它执行删除操作
}
}
else {//t不需要被删除,继续在它的子树中查找
deleteNodes(t->left);
deleteNodes(t->right);
}
}
//成熟的递归函数,克隆子树的内部方法;
BNode * clone(BNode * t) const {
if (t == nullptr) return nullptr;
else
return new BNode{ t->element, clone(t->left), clone(t->right) };
}
void outputTree(BNode * t, bool left, const string s, ostream & out = cout) const {
if (t->right)
outputTree(t->right, false, s + (left ? "| " : " "), out);
out << s;
out << (left ? '\\' : '/');
out << "-----";
if( t->count >= 1 )
out << t->element << "(" << t->count << ")" << endl;
else if(t->count == 0)
out << t->element << "(0)"<
left)
outputTree(t->left, true, s + (left ? " " : "| "), out);
}
void printTree(BNode * t, ostream & out = cout) const {
if (t == nullptr) return;
//如果不加const 会出现2 个重载没有this指针的合法转换
if (t->right)
outputTree(t->right, false, "", out);
out << t->element << "(" << t->count << ")" << endl;
if (t->left)
outputTree(t->left, true, "", out);
}
bool contains(const Object & x, BNode *t) const{
if (t == nullptr)return false;
if (x
element)
return contains(x, t->left);
else if (x>t->element)
return contains(x, t->right);
else if (t->count>0)
return true;
return false;
}
void makeEmpty(BNode * & t){
if (t){
makeEmpty(t->left);
makeEmpty(t->right);
delete t;
t = nullptr;
}
}
void insert(const Object & x, BNode * & t){
if (t == nullptr){
++theSize;
t = new BNode{ x, nullptr, nullptr };
}
else if (x
element)
insert(x, t->left);
else if (x>t->element)
insert(x, t->right);
else ++t->count;
}
void remove(const Object & x, BNode * & t){
if (t == nullptr)return;
if (x
element) remove(x, t->left); else if (x>t->element) remove(x, t->right); else if (t->count>0 && --(t->count) == 0 && ++delSize >= --theSize){ //若count大于0,则减1;若减1后为0,则delSize加1; //若delSize>=theSize,则执行delete操作 deleteNodes(root); //真正的删除操作 delSize = 0; //delSize归零 } } }; int main() { srand((unsigned)time(nullptr)); BSTree
t; for (int i = 0; i < 20; ++i) //随机生成20个数[0,7] t.insert(rand()%8); t.printTree(cout); cout << endl; int num; for (int i = 0; i < 18; ++i) {//随机删除18个数[0,7] num = rand() % 8; cout << num << endl; t.remove(num); t.printTree(cout); cout << endl; } getchar(); return 0; }