數據結構(十三)——樹

數據結構(十三)——樹

1、樹的簡介

一、樹的簡介

樹是一種非線性的數據結構,是由n(n >=0)個結點組成的有限集合。
若是n==0,樹爲空樹。
若是n>0,
樹有一個特定的結點,根結點
根結點只有直接後繼,沒有直接前驅。
除根結點之外的其餘結點劃分爲m(m>=0)個互不相交的有限集合,T0,T1,T2,...,Tm-1,每一個結合是一棵樹,稱爲根結點的子樹。
樹的示例以下:
數據結構(十三)——樹node

二、樹的度

樹的結點包含一個數據和多個指向子樹的分支
結點擁有的子樹的數量爲結點的度,度爲0的結點是葉結點,度不爲0的結點爲分支結點,樹的度定義爲樹的全部結點中度的最大值。
數據結構(十三)——樹數據結構

三、樹的前驅和後繼

結點的直接後繼稱爲結點的孩子,結點稱爲孩子的雙親。
結點的孩子的孩子稱爲結點的孫子,結點稱爲子孫的祖先。
同一個雙親的孩子之間互稱兄弟。
數據結構(十三)——樹ide

四、樹中結點的層次

數據結構(十三)——樹
樹中根結點爲第1層,根結點的孩子爲第2層,依次類推。
樹中結點的最大層次稱爲樹的深度或高度函數

五、樹的有序性

若是樹中結點的各子樹從左向右是有序的,子樹間不能互換位置,則稱該樹爲有序樹,不然爲無序樹。
數據結構(十三)——樹this

六、森林

森林是由n棵互不相交的樹組成的集合。
三棵樹組成的森林以下:
數據結構(十三)——樹設計

2、樹的抽象實現

一、樹的抽象實現

樹在程序中表現爲一種特殊的數據類型。
樹的抽象實現以下:3d

template <typename T>
  class Tree:public Object
  {
  protected:
    TreeNode<T>* m_root;//根結點
  public:
    Tree(){m_root = NULL;}
    //插入結點
    virtual bool insert(TreeNode<T>* node) = 0;
    virtual bool insert(const T& value, TreeNode<T>* parent) = 0;
    //刪除結點
    virtual SharedPointer< Tree<T> > remove(const T& value) = 0;
    virtual SharedPointer< Tree<T> > remove(TreeNode<T>* node) = 0;
    //查找結點
    virtual TreeNode<T>* find(const T& value)const = 0;
    virtual TreeNode<T>* find(TreeNode<T>* node)const = 0;
    //根結點訪問函數
    virtual TreeNode<T>* root()const = 0;
    //樹的度訪問函數
    virtual int degree()const = 0;
    //樹的高度訪問函數
    virtual int height()const = 0;
    //樹的結點數目訪問函數
    virtual int count()const = 0;
    //清空樹
    virtual void clear() = 0;
  };

二、樹結點的抽象實現

樹中的結點表現爲一種特殊的數據類型。
結點的抽象實現以下:指針

template <typename T>
  class TreeNode:public Object
  {
  public:
    T value;
    TreeNode<T>* parent;
    TreeNode()
    {
      parent = NULL;
    }
    virtual ~TreeNode() = 0;
  };
  template <typename T>
  TreeNode<T>::~TreeNode()
  {
  }

3、樹的操做

一、樹和樹結點的存儲結構實現

GTreeNode可以包含任意多個指向後繼結點的指針。code

template <typename T>
  class GTreeNode:public TreeNode<T>
  {
  protected:
    LinkedList<GTreeNode<T>*> m_children;
  };
GTree爲通用樹結構,每一個結點能夠存在多個後繼結點。
  template <typename T>
  class GTree:public Tree<T>
  {
  public:
  };

數據結構(十三)——樹
每一個樹結點包含指向前驅結點的指針,優勢在於能夠將非線性的樹轉化爲線性的結構。
數據結構(十三)——樹blog

二、樹中結點的查找

A、基於數據元素值的查找
定義在任意一個結點爲根結點的樹中查找指定數據元素值所在的結點的函數。
數據結構(十三)——樹

GTreeNode<T>* find(GTreeNode<T>* node, const T& value)const
    {
      GTreeNode<T>* ret = NULL;
      if(node != NULL)
      {
          //若是根結點的就是目標結點
          if(node->value == value)
          {
              ret =  node;
          }
          else
          {
              //遍歷根節點的子結點
              for(node->m_children.move(0); !node->m_children.end() && (ret == NULL); node->m_children.next())
              {
                  //對每一個子子結點進行查找
                  ret = find(node->m_children.current(), value);
              }
          }
      }
      return ret;
    }

    //查找結點
    virtual GTreeNode<T>* find(const T& value)const
    {
      return find(root(), value);
    }

B、基於樹中結點的查找
定義在任意一個結點爲根結點的樹中查找指定結點的函數
數據結構(十三)——樹

GTreeNode<T>* find(GTreeNode<T>* node, GTreeNode<T>* obj)const
    {
      GTreeNode<T>* ret = NULL;
      //根結點爲目標結點
      if(node == obj)
      {
          ret =  node;
      }
      else
      {
          if(node != NULL)
          {
              //遍歷子結點
              for(node->m_children.move(0); !node->m_children.end() && (ret == NULL); node->m_children.next())
              {
                  ret = find(node->m_children.current(), obj);
              }
          }
      }
      return ret;
    }

    virtual GTreeNode<T>* find(TreeNode<T>* node)const
    {
      return find(root(), dynamic_cast<GTreeNode<T>*>(node));
    }

三、樹中結點的插入

樹是非線性的數據結構,沒法採用下標的方式定位數據元素,因爲每一個結點的都有一個惟一的前驅結點(父結點),所以必須找到前驅結點才能找到插入的位置。
A、插入結點
插入結點的流程
數據結構(十三)——樹

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->m_children.find(n) < 0)
                  {
                      ret = np->m_children.insert(n);
                  }
              }
              else
              {
                  THROW_EXCEPTION(InvalidOperationException, "Invalid node...");
              }
          }
      }
      else
      {
          THROW_EXCEPTION(InvalidParameterException, "Parameter is invalid...");
      }
      return ret;
    }

B、插入數據元素
插入數據元素到樹中的流程以下:
數據結構(十三)——樹

bool insert(const T& value, TreeNode<T>* parent)
    {
      bool ret = true;
      GTreeNode<T>* node = GTreeNode<T>::NewNode();
      if(node != NULL)
      {
          node->value = value;
          node->parent = parent;
          insert(node);
      }
      else
      {
          THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
      }
      return ret;
    }

四、樹中結點的清除

樹的清空操做須要將樹中全部的結點清除,並釋放分配在堆中的結點。
定義清除樹中每一個結點的函數
數據結構(十三)——樹
若是樹中的結點可能分配在棧上和堆上,須要將堆空間的結點進行釋放。
根據內存地址不能準確判斷結點所在的存儲空間,清除時存儲在棧上的結點並不須要釋放,只須要釋放存儲在堆空間的結點。
使用工廠模式對分配在堆空間的結點進行定製。
A、GTreeNode類中增長保護的堆空間標識成員m_flag
B、重載GTreeNode的operrator new操做符,聲明爲保護
C、提供工廠方法NewNode(),在工廠方法中建立堆空間的結點,並將m_flag標識置爲true。

template <typename T>
  class GTreeNode:public TreeNode<T>
  {
  protected:
    bool m_flag;//堆空間標識
    //重載new操做符,聲明爲保護
    void* operator new(unsigned int size)throw()
    {
      return Object::operator new(size);
    }

  public:
    LinkedList<GTreeNode<T>*> m_children;
    GTreeNode()
    {
      //棧上分配的空間標識爲false
      m_flag = false;
    }
    //工廠方法,建立堆空間的結點
    static GTreeNode<T>* NewNode()
    {
      GTreeNode<T>* ret = new GTreeNode<T>();
      if(ret != NULL)
      {
          //堆空間的結點標識爲true
          ret->m_flag = true;
      }
      return ret;
    }
    //堆空間結點標識訪問函數
    bool flag()const
    {
      return m_flag;
    }
  };
結點的釋放:
    void free(GTreeNode<T>* node)
    {
      if(node != NULL)
      {
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              free(node->m_children.current());
          }
          //若是結點存儲在堆空間
          if(node->flag())
             delete node;//釋放
      }
    }
清空樹:
    void clear()
    {
        free(root());
        this->m_root = NULL;
    }

五、樹中結點的刪除

刪除函數的設計要點:
將被刪除結點的子樹進行刪除;
刪除函數返回一顆堆空間的樹;
具體返回值爲指向樹的智能指針;
具體的結點刪除功能函數以下:
將node爲根結點的子樹從原來的樹中刪除,ret做爲子樹返回
數據結構(十三)——樹

void remove(GTreeNode<T>* node, GTree<T>*& ret)
    {
      ret = new GTree<T>();
      if(ret != NULL)
      {
          //若是刪除的結點是根結點
          if(root() == node)
          {
              this->m_root = NULL;
          }
          else
          {
              //獲取刪除結點的父結點的子結點鏈表
              LinkedList<GTreeNode<T>*>& child = dynamic_cast<GTreeNode<T>*>(node->parent)->m_children;
              //從鏈表中刪除結點
              child.remove(child.find(node));
              //結點的父結點置NULL
              node->parent = NULL;
          }
          //將刪除結點賦值給建立的樹ret的根結點
          ret->m_root = node;
      }
      else
      {
          THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
      }
    }

A、基於刪除數據元素值刪除結點

SharedPointer<Tree<T>> remove(const T& value)
    {
      GTree<T>* ret = NULL;
      //找到結點
      GTreeNode<T>* node = find(value);
      if(node != NULL)
      {
          remove(node, ret);
      }
      else
      {
          THROW_EXCEPTION(InvalidParameterException, "Parameter invalid...");
      }
      return ret;
    }

B、基於結點刪除

SharedPointer<Tree<T>> remove(TreeNode<T>* node)
    {
      GTree<T>* ret = NULL;
      node = find(node);
      if(node != NULL)
      {
          remove(dynamic_cast<GTreeNode<T>*>(node), ret);
      }
      else
      {
          THROW_EXCEPTION(InvalidParameterException, "Parameter invalid...");
      }
      return ret;
    }

六、樹中結點的屬性操做

A、樹中結點的數量
以node爲結點的子樹的結點數量,遞歸模型以下:
數據結構(十三)——樹

int count(GTreeNode<T>* node) const
    {
      int ret = 0;
      if(node != NULL)
      {
          ret = 1;//根結點
          //遍歷根節點的子結點
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              ret += count(node->m_children.current());
          }
      }
      return ret;
    }
    //樹的結點數目訪問函數
    int count()const
    {
        count(root());
    }

B、樹的度
結點node爲根的樹的度的功能函數的遞歸模型以下:
數據結構(十三)——樹

int degree(GTreeNode<T>* node) const
    {
      int ret = 0;
      if(node != NULL)
      {
          //結點的子結點的數量
          ret = node->m_children.length();
          //遍歷子結點
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              int d = degree(node->m_children.current());
              if(ret < d)
              {
                  ret = d;
              }
          }
      }
      return ret;
    }

    //樹的度訪問函數
    int degree()const
    {
        return degree(root());
    }

C、樹的高度
結點node爲根的樹的高度的功能函數的遞歸模型以下:
數據結構(十三)——樹

int height(GTreeNode<T>* node)const
    {
      int ret = 0;
      if(node != NULL)
      {
          //遍歷子結點
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              //當前結點的高度
              int h = height(node->m_children.current());
              if(ret < h)
              {
                  ret = h;
              }
          }
          ret = ret + 1;
      }
      return ret;
    }
    //樹的高度訪問函數
    int height()const
    {
        height(root());
    }

七、樹中結點的遍歷

樹是一種非線性的數據結構,遍歷樹中結點能夠採用遊標的方式。
A、在樹中定義一個遊標(GTreeNode<T>* node)
B、遍歷開始前將遊標指向根結點
C、獲取遊標指向的數據元素
D、經過結點中的m_children成員移動遊標
數據結構(十三)——樹
將根結點壓入隊列中

bool begin()
    {
      bool ret = (root() != NULL);
      if(ret)
      {
          //清空隊列
          m_queue.clear();
          //根節點加入隊列
          m_queue.add(root());
      }
      return ret;
    }

判斷隊列是否爲空

bool end()
    {
        return (m_queue.length() == 0);
    }

隊頭元素彈出,將隊頭元素的孩子壓入隊列中

bool next()
    {
      bool ret = (m_queue.length() > 0);
      if(ret)
      {
          GTreeNode<T>* node = m_queue.front();
          m_queue.remove();//隊頭元素出隊
          //將隊頭元素的子結點入隊
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              m_queue.add(node->m_children.current());
          }
      }
      return ret;
    }

訪問隊頭元素指向的數據元素

T current()
    {
      if(!end())
      {
          return m_queue.front()->value;
      }
      else
      {
          THROW_EXCEPTION(InvalidOperationException, "No value at current Node...");
        }
    }

4、通用樹結構的實現

一、通用樹節點的實現

template <typename T>
  class GTreeNode:public TreeNode<T>
  {
  protected:
    bool m_flag;//堆空間標識
    //重載new操做符,聲明爲保護
    void* operator new(unsigned int size)throw()
    {
      return Object::operator new(size);
    }
    GTreeNode(const GTreeNode<T>& other);
    GTreeNode<T>& operator = (const GTreeNode<T>& other);

  public:
    LinkedList<GTreeNode<T>*> m_children;
    GTreeNode()
    {
      //棧上分配的空間標識爲false
      m_flag = false;
    }
    //工廠方法,建立堆空間的結點
    static GTreeNode<T>* NewNode()
    {
      GTreeNode<T>* ret = new GTreeNode<T>();
      if(ret != NULL)
      {
          //堆空間的結點標識爲true
          ret->m_flag = true;
      }
      return ret;
    }
    //堆空間結點標識訪問函數
    bool flag()const
    {
      return m_flag;
    }
  };

二、通用樹的實現

template <typename T>
  class GTree:public Tree<T>
  {
  protected:
    LinkedQueue<GTreeNode<T>*> m_queue;
    GTree(const GTree<T>& other);
    GTree<T>& operator=(const GTree<T>& other);
    GTreeNode<T>* find(GTreeNode<T>* node, const T& value)const
    {
      GTreeNode<T>* ret = NULL;
      if(node != NULL)
      {
          //若是根結點的就是目標結點
          if(node->value == value)
          {
              ret =  node;
          }
          else
          {
              //遍歷根節點的子結點
              for(node->m_children.move(0); !node->m_children.end() && (ret == NULL); node->m_children.next())
              {
                  //對每一個子子結點進行查找
                  ret = find(node->m_children.current(), value);
              }
          }
      }
      return ret;
    }
    GTreeNode<T>* find(GTreeNode<T>* node, GTreeNode<T>* obj)const
    {
      GTreeNode<T>* ret = NULL;
      //根結點爲目標結點
      if(node == obj)
      {
          ret =  node;
      }
      else
      {
          if(node != NULL)
          {
              //遍歷子結點
              for(node->m_children.move(0); !node->m_children.end() && (ret == NULL); node->m_children.next())
              {
                  ret = find(node->m_children.current(), obj);
              }
          }
      }
      return ret;
    }

    void free(GTreeNode<T>* node)
    {
      if(node != NULL)
      {
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              free(node->m_children.current());
          }
          //若是結點存儲在堆空間
          if(node->flag())
             delete node;//釋放
      }
    }

    void remove(GTreeNode<T>* node, GTree<T>*& ret)
    {
      ret = new GTree<T>();
      if(ret != NULL)
      {
          //若是刪除的結點是根結點
          if(root() == node)
          {
              this->m_root = NULL;
          }
          else
          {
              //獲取刪除結點的父結點的子結點鏈表
              LinkedList<GTreeNode<T>*>& child = dynamic_cast<GTreeNode<T>*>(node->parent)->m_children;
              //從鏈表中刪除結點
              child.remove(child.find(node));
              //結點的父結點置NULL
              node->parent = NULL;
          }
          //將刪除結點賦值給建立的樹ret的根結點
          ret->m_root = node;
      }
      else
      {
          THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
      }
    }

    int count(GTreeNode<T>* node) const
    {
      int ret = 0;
      if(node != NULL)
      {
          ret = 1;//根結點
          //遍歷根節點的子結點
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              ret += count(node->m_children.current());
          }
      }
      return ret;
    }

    int height(GTreeNode<T>* node)const
    {
      int ret = 0;
      if(node != NULL)
      {
          //遍歷子結點
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              //當前結點的高度
              int h = height(node->m_children.current());
              if(ret < h)
              {
                  ret = h;
              }
          }
          ret = ret + 1;
      }
      return ret;
    }

    int degree(GTreeNode<T>* node) const
    {
      int ret = 0;
      if(node != NULL)
      {
          //結點的子結點的數量
          ret = node->m_children.length();
          //遍歷子結點
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              int d = degree(node->m_children.current());
              if(ret < d)
              {
                  ret = d;
              }
          }
      }
      return ret;
    }
  public:
    GTree()
    {

    }
    //插入結點
    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->m_children.find(n) < 0)
                  {
                      ret = np->m_children.insert(n);
                  }
              }
              else
              {
                  THROW_EXCEPTION(InvalidOperationException, "Invalid node...");
              }
          }
      }
      else
      {
          THROW_EXCEPTION(InvalidParameterException, "Parameter is invalid...");
      }
      return ret;
    }
    bool insert(const T& value, TreeNode<T>* parent)
    {
      bool ret = true;
      GTreeNode<T>* node = GTreeNode<T>::NewNode();
      if(node != NULL)
      {
          node->value = value;
          node->parent = parent;
          insert(node);
      }
      else
      {
          THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory...");
      }
      return ret;
    }
    //刪除結點
    SharedPointer<Tree<T>> remove(const T& value)
    {
      GTree<T>* ret = NULL;
      //找到結點
      GTreeNode<T>* node = find(value);
      if(node != NULL)
      {
          remove(node, ret);
          m_queue.clear();
      }
      else
      {
          THROW_EXCEPTION(InvalidParameterException, "Parameter invalid...");
      }
      return ret;
    }

    SharedPointer<Tree<T>> remove(TreeNode<T>* node)
    {
      GTree<T>* ret = NULL;
      node = find(node);
      if(node != NULL)
      {
          remove(dynamic_cast<GTreeNode<T>*>(node), ret);
          m_queue.clear();
      }
      else
      {
          THROW_EXCEPTION(InvalidParameterException, "Parameter invalid...");
      }
      return ret;
    }
    //查找結點
    GTreeNode<T>* find(const T& value)const
    {
      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 degree(root());
    }
    //樹的高度訪問函數
    int height()const
    {
        height(root());
    }
    //樹的結點數目訪問函數
    int count()const
    {
        count(root());
    }
    //清空樹
    void clear()
    {
        free(root());
        this->m_root = NULL;
    }

    bool begin()
    {
      bool ret = (root() != NULL);
      if(ret)
      {
          //清空隊列
          m_queue.clear();
          //根節點加入隊列
          m_queue.add(root());
      }
      return ret;
    }

    bool end()
    {
        return (m_queue.length() == 0);
    }

    bool next()
    {
      bool ret = (m_queue.length() > 0);
      if(ret)
      {
          GTreeNode<T>* node = m_queue.front();
          m_queue.remove();//隊頭元素出隊
          //將隊頭元素的子結點入隊
          for(node->m_children.move(0); !node->m_children.end(); node->m_children.next())
          {
              m_queue.add(node->m_children.current());
          }
      }
      return ret;
    }

    T current()
    {
      if(!end())
      {
          return m_queue.front()->value;
      }
      else
      {
          THROW_EXCEPTION(InvalidOperationException, "No value at current Node...");
      }
    }
    virtual ~GTree()
    {
      clear();
    }
  };
相關文章
相關標籤/搜索