第55课 - 树中结点的清除操作

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 (通用树结构)的结点删除操作 


猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/80467703