二叉查找树——懒惰删除

由于学习树这一章节,查阅了很多资料,网上书上代码上,自己的别人的已然分不开了,如有侵权请留言,如同意我记录于此,也请留言区留下大名,必然感谢!

此篇参考 ----》》》传送门

懒惰删除(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);
	}
}

·findMaxfindMin函数,找最值,这里就返回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; } 
           
         
        
        
       
       
      
      
     
     


  • 7
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值