二叉查找树——懒惰删除

来源:互联网 发布:php 输出文本文件乱码 编辑:程序博客网 时间:2024/05/18 21:42

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

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

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


附上效果图:



附上完整代码:

树的半可视化打印参考: 半可视化打印二叉树

//懒惰删除templateclass 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 nothingif (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;elsereturn 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 (xelement)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 (xelement)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 (xelement)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;}


原创粉丝点击