1、 清除操作的定义:将树中的所有结点清除(释放堆中的结点)
void clear()
- 树中数据元素的清除
- 清除操作功能的定义
— free(node):清除 node 为根结点的树,释放树中的每一个结点
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;
}
}
void clear()
{
free(root());
this->m_root = nullptr;
}
#include <iostream>
#include "GTree.h"
using namespace std;
using namespace XiebsLib;
int main()
{
GTree<char> t;
GTreeNode<char>* node = nullptr;
GTreeNode<char> root;
root.value = 'A';
root.parent = nullptr;
t.insert(&root);
// t.insert('A', nullptr);
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('G');
t.insert('N', 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 = "KLFNMIJ";
for(int i = 0; i < 7; i++)
{
TreeNode<char>* node = t.find(s[i]);
while( node != nullptr )
{
cout << node->value << " ";
node = node->parent;
}
cout << endl;
}
return 0;
}
如果我们把根结点定义在栈上,程序的运行没有问题,但是在调用 clear()
函数时,我们会把根结点给 delete 掉,这样做是不对的,你不知道什么时候程序会崩溃掉。
- 问题分析:
1、单凭内存地址很难准确判断具体的存储区域
2、只有堆空间的内存需要主动释放(delete)
3、清除操作时只需要对堆中的结点进行释放
解决方案:工厂模式
1、在 GTreeNode 中增加保护成员变量 m_flag
2、将 GTreeNode 中的 operator new 重载为保护成员函数(防止在外部定义堆对象,我们统一把堆对象的生成放在内部)
3、提供工厂方法 GTreeNode<T>* NewNode()
4、在工厂方法中 new 新结点并将 m_flag 设置为 true
GTreeNode.h
#ifndef GTREENODE_H
#define GTREENODE_H
#include "LinkList.h"
#include "TreeNode.h"
namespace XiebsLib
{
template <typename T>
class GTreeNode : public TreeNode<T>
{
protected:
bool m_flag;
void* operator new(unsigned int size)throw()
{
return Object::operator new(size);
}
public:
LinkList<GTreeNode<T>*> child;
GTreeNode()
{
m_flag = false;
}
bool flag()
{
return m_flag;
}
static GTreeNode<T>* NewNode()
{
GTreeNode<T>* ret = new GTreeNode<T>;
if(ret != nullptr)
{
ret->m_flag = true;
}
return ret;
}
};
}
#endif // GTREENODE_H
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;
}
else
{
cout << node->value << endl;
}
}
}
bool insert(const T& value, TreeNode<T>* parent)
{
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 memory to create new tree node");
}
return ret;
}
- 小结
1、清除操作 用于销毁树中的每个结点
2、销毁结点时需要决定是否释放对应的内存空间
3、工厂模式可用于定制堆空间中的结点
4、只有销毁定制结点的时候需要进行释放