清除操作的定义
void clear()
- 将树中所有的结点清除(释放堆中的结点)
树中数据元素的清除
清除操作功能的定义
free(node)
- 清除 node 为根结点的树
- 释放树中的每一个结点
编程实验:清除树中的结点
文件:GTree.h
#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>
{
public:
bool insert(TreeNode<T> *node) override
{
bool ret = true;
if (node != nullptr)
{
if (this->m_root == nullptr)
{
node->parent = nullptr;
this->m_root = node;
}
else
{
GTreeNode<T> *np = find(node->parent);
if (np != nullptr)
{
GTreeNode<T> *n = dynamic_cast<GTreeNode<T>*>(node);
if (np->child.find(n) < 0)
{
np->child.insert(n);
}
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "Invalid partent tree node ...");
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter node cannot be NULL ...");
}
return ret;
}
bool insert(const T &value, TreeNode<T> *parent) override
{
bool ret = true;
GTreeNode<T> *node = new GTreeNode<T>();
if (node != nullptr)
{
node->value = value;
node->parent = parent;
insert(node);
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to create node ...");
}
return ret;
}
SharedPointer<Tree<T>> remove(const T &value) override
{
return nullptr;
}
SharedPointer<Tree<T>> remove(TreeNode<T> *node) override
{
return nullptr;
}
GTreeNode<T>* find(const T &value) const override
{
return find(root(), value);
}
GTreeNode<T>* find(TreeNode<T> *node) const override
{
return find(root(), dynamic_cast<GTreeNode<T>*>(node));
}
GTreeNode<T>* root() const override
{
return dynamic_cast<GTreeNode<T>*>(this->m_root);
}
int degree() const override
{
return 0;
}
int count() const override
{
return 0;
}
int height() const override
{
return 0;
}
void clear() override
{
free(root());
this->m_root = nullptr;
}
~GTree()
{
clear();
}
protected:
GTreeNode<T> *find(GTreeNode<T>* node, const T &value) const
{
GTreeNode<T> *ret = nullptr;
if (node != nullptr)
{
if (node->value == value)
{
return node;
}
else
{
for (node->child.move(0); !node->child.end() && (ret == nullptr); node->child.next())
{
ret = find(node->child.current(), value);
}
}
}
return ret;
}
GTreeNode<T> *find(GTreeNode<T>* node, GTreeNode<T> *obj) const
{
GTreeNode<T> *ret = nullptr;
if (node == obj)
{
return node;
}
else
{
if (node != nullptr)
{
for (node->child.move(0); !node->child.end() && (ret == nullptr); node->child.next())
{
ret = find(node->child.current(), obj);
}
}
}
return ret;
}
void free(GTreeNode<T> *node)
{
if (node != nullptr)
{
for (node->child.move(0); !node->child.end(); node->child.next())
{
free(node->child.current());
}
delete node;
}
}
};
}
#endif // GTREE_H
问题
树中的结点可能来源于不同的存储空间,如何判断堆空间中的结点并释放?
void func()
{
GTree<char> t;
GTreeNode<char> root;
root.value = 'A';
root.parent = nullptr;
t.insert(&root); // 栈空间结点
t.insert('B', t.find('A')); // 堆空间结点
t.clear(); // 注意:非堆空间中结点不应被释放!!
}
问题分析
- 单凭内存地址很难准确判断具体的存储区域
- 只有堆空间的内存需要主动释放 (delete)
- 清除操作时只需要对堆中的结点进行释放
解决方案:工厂模式
- 在 GTreeNode 中增加保护成员变量 m_flag
- 将 GTreeNode 中的 operator new 重载为保护成员(禁止类外部 new 结点)
- 提供工厂方法
GTreeNode<T> *NewNode()
- 在工厂方法中 new 新结点并将 m_flag 设置为 true
树结点的工厂模式示例
GtreeNode<int> *hn = GTreeNode<int>::NewNode();
GTreeNode<int> sn;
if (hn->flag()) // true
{
delete hn;
}
hn = &sn;
if (hn->flag()) // false
{
delete hn;
}
编程实验
文件:GTreeNode.h
#ifndef GTREENODE_H
#define GTREENODE_H
#include "TreeNode.h"
#include "LinkList.h"
namespace DTLib
{
template <typename T>
class GTreeNode : public TreeNode<T>
{
public:
LinkList<GTreeNode<T>*> child;
bool flag()
{
return m_flag;
}
static GTreeNode<T>* NewNode()
{
GTreeNode<T> *ret = new GTreeNode<T>();
if (ret != nullptr)
{
ret->m_flag = true;
}
return ret;
}
protected:
bool m_flag = false;
void *operator new (unsigned int size) noexcept(true)
{
return Object::operator new(size);
}
};
}
#endif // GTREENODE_H
文件:GTree.h
#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>
{
public:
bool insert(TreeNode<T> *node) override
{
bool ret = true;
if (node != nullptr)
{
if (this->m_root == nullptr)
{
node->parent = nullptr;
this->m_root = node;
}
else
{
GTreeNode<T> *np = find(node->parent);
if (np != nullptr)
{
GTreeNode<T> *n = dynamic_cast<GTreeNode<T>*>(node);
if (np->child.find(n) < 0)
{
np->child.insert(n);
}
}
else
{
THROW_EXCEPTION(InvalidOpertionExcetion, "Invalid partent tree node ...");
}
}
}
else
{
THROW_EXCEPTION(InvalidParameterExcetion, "Parameter node cannot be NULL ...");
}
return ret;
}
bool insert(const T &value, TreeNode<T> *parent) override
{
bool ret = true;
GTreeNode<T> *node = GTreeNode<T>::NewNode();
if (node != nullptr)
{
node->value = value;
node->parent = parent;
insert(node);
}
else
{
THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to create node ...");
}
return ret;
}
SharedPointer<Tree<T>> remove(const T &value) override
{
return nullptr;
}
SharedPointer<Tree<T>> remove(TreeNode<T> *node) override
{
return nullptr;
}
GTreeNode<T>* find(const T &value) const override
{
return find(root(), value);
}
GTreeNode<T>* find(TreeNode<T> *node) const override
{
return find(root(), dynamic_cast<GTreeNode<T>*>(node));
}
GTreeNode<T>* root() const override
{
return dynamic_cast<GTreeNode<T>*>(this->m_root);
}
int degree() const override
{
return 0;
}
int count() const override
{
return 0;
}
int height() const override
{
return 0;
}
void clear() override
{
free(root());
this->m_root = nullptr;
}
~GTree()
{
clear();
}
protected:
GTreeNode<T> *find(GTreeNode<T>* node, const T &value) const
{
GTreeNode<T> *ret = nullptr;
if (node != nullptr)
{
if (node->value == value)
{
return node;
}
else
{
for (node->child.move(0); !node->child.end() && (ret == nullptr); node->child.next())
{
ret = find(node->child.current(), value);
}
}
}
return ret;
}
GTreeNode<T> *find(GTreeNode<T>* node, GTreeNode<T> *obj) const
{
GTreeNode<T> *ret = nullptr;
if (node == obj)
{
return node;
}
else
{
if (node != nullptr)
{
for (node->child.move(0); !node->child.end() && (ret == nullptr); node->child.next())
{
ret = find(node->child.current(), obj);
}
}
}
return ret;
}
void free(GTreeNode<T> *node)
{
if (node != nullptr)
{
for (node->child.move(0); !node->child.end(); node->child.next())
{
free(node->child.current());
}
if (node->flag())
{
delete node;
}
}
}
};
}
#endif // GTREE_H
小结
- 清除操作用于销毁树中的每个结点
- 销毁结点时需要决定是否释放对应的内存空间
- 工厂模式可用于 "定制" 堆空间中的结点
- 只有销毁定制结点的时候需要进行释放
To be continued
思考: 如何实现 GTree (通用树结构) 的结点删除操作?
SharedPointer<Tree<T>> remove(const T &value) override
{
GTreeNode<T> *ret = NULL;
// ...
return ret;
}
SharedPointer<Tree<T>> remove(TreeNode<T> *node) override
{
GTreeNode<T> *ret = NULL;
// ...
return ret;
}
以上内容整理于狄泰软件学院系列课程,请大家保护原创!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。