树的操作

Posted 勇士后卫头盔哥

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树的操作相关的知识,希望对你有一定的参考价值。

树的清除操作


树这种数据结构可以看做是一种容器,树的清除操作就是将树中的所有结点清除,也就是释放堆中的结点,如上图所示,假设我们要将树中数据元素清除,可以先将根结点里面的每一棵子树给清除掉,最后再将根节点清除即可,在清除子树的时候又用到清除树的操作所以这是一个递归调用的过程,出口就是树只有一个根节点且没有子树,公式定义如下

代码实现

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;//从堆空间释放
    

存在问题

可以看出上面的代码存在一定的局限,假设我们的树是在栈,全局数据区中申请的,那么使用detele删除树结点是不合理的,树中的结点可能来源于不同的存储空间,如何判断堆空间中的结点并释放呢,单凭内存地址很难准确判断具体的存储区域,我们在new一个对象的时候做一个标记,在释放的时候根据标记判断是否需要释放,工厂模式来解决这个问题

1.在GTreeNode中增加保护成员变量m_flag
2.将GTreeNode中的operator new重载为保护成员的函数
3.提供工厂方法GTreeNode<T>* NewNode()
4.在工厂方法中new新结点并将m_flag设置为true

代码改进:

namespace CGSLib

   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;
      bool flag()//返回标志位
      
         return m_flag;
      
      GTreeNode()//构造函数
      
          m_flag= false;
      
      static GTreeNode<T>* NewNode()//创建新结点
      
          GTreeNode<T>* ret = new GTreeNode<T>();
          /*如果是从堆空间申请成功的则加上标志位*/
          if(ret != NULL)
          
              ret->m_flag = true;
          
          return ret;
      
   ;

树的删除操作


设计原则

当需要从函数中返回堆中的对象时,使用智能指针作为函数的返回值

如果我们只是想将某个结点删除并不想清除整个树的操作,我们就有了新的需求,就是树的删除操作,删除操作有基于数据元素值的操作和基于结点的操作,删除操作成员函数的设计要点在于将被删除结点所代表的子树进行删除,返回一颗堆空间中的树,具体返回值指向树的智能指针对象,如下图是删除流程所示

删除部分代码

void  remove(GTreeNode<T> *node,GTree<T>*& ret)

    ret = new GTree<T>();//新建一个树对象
    /*不成功则抛出异常*/
    if(ret==NULL)
    
        THROW_EXCEPTION(NoEnougMemoryException,"No memory to create new tree...");
    
    else
       
        /*如果该节点为根节点*/
        if(root()==node)
        
           this->m_root = NULL;
        
        /*该节点不为根节点*/
        else
        
            LinkList<GTreeNode<T>*>& child  =   dynamic_cast<GTreeNode<T>*>(node->parent)->child;//找出父节点的子链表
            child.remove(child.find(node));//从该子链表中删除该结点
            node->parent = NULL;//设置该结点的父节为空
        
    
    ret->m_root = node;//设置该结点为根节点

根据值结点删除

SharedPointer< Tree<T> > remove(const T& value)

    GTree<T>* ret = NULL;
    GTreeNode<T>* node = find(value);//根据值找到要删除的结点
    if(node == NULL)
    
        THROW_EXCEPTION(InvalidParamterException,"can not find");
    
    else
    
        remove(node,ret);//删除结点
    
    return ret;//

根据结点删除

SharedPointer< Tree<T> > remove(TreeNode<T>* node)

    GTree<T> *ret = NULL;
    node = find(node);//根据值结点到要删除的结点
    if(node == NULL)
    
       THROW_EXCEPTION(InvalidParamterException,"can not find");
    
    else
    
        remove(dynamic_cast<GTreeNode<T>*>(node),ret);//删除操作
    
    return ret;

实战演示

int main()

  GTree<char> t;
  GTreeNode<char> *node = NULL;
  GTreeNode<char> root;
  t.insert('A',NULL);
  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);


  SharedPointer< Tree<char> > p =  t.remove(t.find('D'));//删除为D结点的树
  char*s = "KLFGMIJ";

  for(int i=0;i<7;i++)
  
      TreeNode<char>* node = p->find(s[i]);
      while(node!=NULL)
      
          cout<<node->value<<" ";
          node = node->parent;
      
      cout<<endl;
  

  return 1;

以上是关于树的操作的主要内容,如果未能解决你的问题,请参考以下文章

树4二叉树的遍历

二叉搜索树的思想,以及增删查改的实现

第2节 二叉树的基本操作(递归实现)

Python 二叉树的创建和遍历、重建

二叉树的遍历

leetcode——另一个树的子树