1、树中结点的删除操作
删除的方式
-基于数据元素值的删除
SharedPointer< Tree<T> > remove(const T& value)
-基于结点的删除
SharedPointer< Tree<T> > remove(TreeNode<T>* node)
删除操作成员函数的设计要点
-将被删结点所代表的子树进行删除
-删除函数返回—棵堆空间中的树
-具体返回值为 指向树的智能指针对象 树中结点的删除
返回智能指针对象就能对待删除子树不用时进行自动释放堆空间
实用的设计原则
当需要从函数中返回堆中的对象时,使用智能
指针(SharedPointer)作为函数的返回值。
下面举个例子帮助理解
- int* func()
- {
- return new int;
- }
- int main()
- {
- int* p = func(); //那么在main函数里要不要释放p所指堆空间???
- return 0;
- }
站在main函数角度,不应该释放,毕竟我们曾在C/C++课程学过谁申请应该谁释放,
然而在这里func函数提供四个字节就返回了,哪有机会释放
那么我们可以用智能指针解决该问题
- SharedPointer<int> func()
- {
- return new int;
- }
- int main()
- {
- SharedPointer<int> p = func(); //在main函数结束时自动释放堆空间
- return 0;
- }
删除操作功能的定义
- void remove(GTreeNode<T>* node, GTree<T>*& ret) -->返回一个引用作为指针别名
将node为根结点的子树从原来的树中删除
ret作为子树返回(ret指向堆空间中的树对象)
删除功能函数的实现
2、编程实验
树结点的删除操作 remove#ifndef GTREE_H #define GTREE_H #include "Tree.h" #include"GTreeNode.h" #include"Exception.h" namespace DTLib { template < typename T > class GTree : public Tree<T> { protected: GTreeNode<T>* find(GTreeNode<T>* node,const T& value) const { GTreeNode<T>* ret = NULL; if(node != NULL) { if(node->value == value) { return node; } else { for(node->child.move(0);!node->child.end() && (ret == NULL);node->child.next()) //在node子树中查找 { ret = find(node->child.current(),value); //child里数据元素类型是GTreeNode<T>* } } } return ret; } GTreeNode<T>* find(GTreeNode<T>* node,GTreeNode<T>* obj) const { GTreeNode<T>* ret = NULL; if(node == obj) { return node; } else { if(node != NULL) { for(node->child.move(0);!node->child.end() && (ret == NULL);node->child.next()) { ret = find(node->child.current(),obj); } } } return ret; } void free(GTreeNode<T>* node) { if(node != NULL) { for(node->child.move(0);!node->child.end();node->child.next()) { free(node->child.current()); } if(node->flag()) { delete node; } } } void remove(GTreeNode<T>* node,GTree<T>*& ret) { ret = new GTree<T>(); if(ret == NULL) { THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create new tree ..."); } else { if( root() == node) //待删结点就是根结点 { this->m_root = NULL; } else { LinkList< GTreeNode<T>* >& child = dynamic_cast< GTreeNode<T>* >(node->parent)->child; //child引用指向待删除结点父结点的链表 child.remove(child.find(node)); //在父结点的链表中 将指向(结点的指针)待删孩子 的结点删除 node->parent = NULL; //此子树彻底地离开了树,并没有清除释放 } ret->m_root = node; } } public: bool insert(TreeNode<T>* node) { bool ret = true; if(node != NULL) { if(this->m_root == NULL) { node->parent = NULL; this->m_root = node; } else { GTreeNode<T>* np = find(node->parent); if( np != NULL ) { GTreeNode<T>* n = dynamic_cast<GTreeNode<T>*>(node); if( np->child.find(n) < 0 ) { np->child.insert(n); } } else { THROW_EXCEPTION(InvalidOperationException,"Invalid parent tree node ..."); } } } else { THROW_EXCEPTION(InvalidParameterException,"Parameter node cannot be NULL ..."); } return ret; } bool insert(const T& value,TreeNode<T>* parent) { bool ret = true; GTreeNode<T>* node = GTreeNode<T>::NewNode(); if(node) { node->value = value; node->parent = parent; insert(node); } else { THROW_EXCEPTION(NoEnoughMemoryException,"No memory to create new tree node ..."); } return ret; } SharedPointer< Tree<T> > remove(const T& value) { GTree<T>* ret = NULL; GTreeNode<T>* node = find(value); if(node == NULL) { THROW_EXCEPTION(InvalidParameterException,"Can not find the node via parameter value ..."); } else { remove(node,ret); } return ret; } SharedPointer< Tree<T> > remove(TreeNode<T>* node) { GTree<T>* ret = NULL; node = find(node); if(node == NULL) { THROW_EXCEPTION(InvalidParameterException,"Parameter node is invalid ..."); } else { remove(dynamic_cast<GTreeNode<T>*>(node),ret); } return NULL; } GTreeNode<T>* find(const T& value) const { return find(root(),value); } GTreeNode<T>* find(TreeNode<T>* node) const { return find(root(),dynamic_cast< GTreeNode<T>* >(node)); } GTreeNode<T>* root() const { return dynamic_cast< GTreeNode<T>* >(this->m_root); } int degree() const { return 0; } int count() const { return 0; } int height() const { return 0; } void clear() { free(root()); this->m_root = NULL; } ~GTree() { clear(); } }; } #endif // GTREE_H
main.cpp
#include <iostream> #include"GTree.h" using namespace std; using namespace DTLib; int main() { GTree<char> t; GTreeNode<char>* node = NULL; GTreeNode<char> root; root.value = 'A'; root.parent = NULL; t.insert(&root); //将局部对象作为根结点插入 node = t.find('A'); t.insert('B',node); t.insert('C',node); t.insert('D',node); node = t.find('B'); t.insert('E',node); t.insert('F',node); node = t.find('E'); t.insert('K',node); t.insert('L',node); node = t.find('C'); t.insert('G',node); node = t.find('D'); t.insert('H',node); t.insert('I',node); t.insert('J',node); node = t.find('H'); t.insert('M',node); const char* s = "KLFGMIJ"; t.remove(t.find('B')); for(int i=0;i<7;i++) { TreeNode<char>* node = t.find(s[i]); while(node != NULL) { cout<<node->value<<" "; node = node->parent; } cout<<endl; } SharedPointer< Tree<char> > p = t.remove('D'); for(int i=0;i<7;i++) { TreeNode<char>* node = p->find(s[i]); while(node != NULL) { cout<<node->value<<" "; node = node->parent; } cout<<endl; } return 0;
3、小结
删除操作各目标结点所代表的子树移除
删除操作必须完善处理父结点和子结点的关系
删除操作的返回值为指向树的智能指针对象
函数中返回堆中的对象时,使用智能指针作为返回值
4、实战预告
To be continued ...
思考:
如何实现GTree (通用树结构)的属性操作函数?