void clear()node
- 將樹中全部的節點清除(釋放堆中的節點)
free(node)編程
- 清除 node 爲根節點的樹
- 釋放樹中的每個節點
文件:GTree.hide
#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.hthis
#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.hspa
#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
- 清除操做用於銷燬樹中的每一個節點
- 銷燬節點時須要決定是否釋放對應的內存空間
- 工廠模式可用於 "定製" 堆空間中的節點
- 只有銷燬定製節點的時候須要進行釋放
思考: 如何實現 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; }
以上內容整理於狄泰軟件學院系列課程,請你們保護原創!3d