1、树中结点的清除操作
清除操作的定义
- void clear()
将树中的所有结点清除(释放堆中的结点)
树中数据元素的清除
递归的思想(从A开始.....K != NULL,delete K)
清除操作功能的定义
- free(node)
清除node为根结点的树
释放树中的每—个结点
2、编程实验
清除树中的结点void free(GTreeNode<T>* node) { if(node != NULL) { for(node->child.move(0);!node->child.end();node->child.next()) { free(node->child.current()); } delete node; //将根结点所有孩子清除后,清除根结点 } }
3、问题
树中的结点可能来源于不同的存储空间,
如何判断堆空间中的结点并释放?
4、问题分析
-单凭内存地址很难准确判断具体的存储区域
- 只有堆空间的内存需要主动释放(delete)
-清除操作时只需要对堆中的结点进行释放
5、解决方案:工厂模式
1. 在GTreeNode中增加保护成员变量m_flag
2. 将GTreeNode中的operator new重载为保护成员函数
3. 提供工厂方法GTreeNode<T>* NewNode()
4 在工厂方法中 new新结点并将 m_flag设置为 true树结点的工厂模式示例
6、编程实验
解决方案 Factory
GTreeNode.h
#ifndef GTREENODE_H #define GTREENODE_H #include "TreeNode.h" #include "LinkList.h" namespace DTLib { template < typename T > class GTreeNode : public TreeNode<T> { protected: bool m_flag; bool operator new (unsigned int size) throw() //不能直接用new创建对象 { return Object::operator new(size); } public: LinkList< GTreeNode<T>* > child; GTreeNode<T>() { m_flag = false; } bool flag() { return m_flag; } static GTreeNode<T>* NewNode() { GTreeNode<T>* ret = new GTreeNdoe<T>(); if(ret != NULL) { ret->m_flag = true; } return ret; } }; } #endif // GTREENODE_H
GTree.h
#ifndef GTREE_H #define GTREE_H #include "Tree.h" #include"GTreeNode.h" #include"Exception.h" #include <iostream> //仅供测试使用 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; } else //仅供测试使用 { std::cout<<node->value; } } } 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 ) //没有必要查整棵树,只需父结点下的子结点当中有没有node { 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) { return NULL; } SharedPointer< Tree<T> > remove(TreeNode<T>* node) { return NULL; } GTreeNode<T>* find(const T& value) const //GTreeNode 赋值兼容原则 { 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); t.clear(); const char* s = "KLFGMIJ"; 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; } return 0; }
7、小结
清除操作用于销毁树中的每个结点
销毁结点时需要决定是否释放对应的内存空间
工厂模式可用于“定制”堆空间中的结点
只有销毁定制结点的时候需要进行释放
8、实战预告
To be continued ...
思考:
如何实现GTree (通用树结构)的结点删除操作?