【问题标题】:Inheritance and AVL/BST Trees继承和 AVL/BST 树
【发布时间】:2016-02-28 10:05:39
【问题描述】:

有什么方法可以对 Bst 和 Avl 树使用相同的插入函数?问题是 Bst 和 Avl 有不同的节点类型,但我不想让 Bst 节点成为一般情况(里面有 height 和 Node* 父级,这是没有意义的,因为 a 内不需要父级和高度Bst)。

class Bst
{
public:
    struct Node
    {
        int value;
        Node* left;
        Node* right;
    };

    Node* insert(Node* node) {/* do stuff using Bst::Node */}

    // ...
};

class Avl : public Bst
{
public:
    struct Node : public Bst::Node
    {
        int height;
        Node* parent;
    };

    // now I want that Bst::insert use this Node
    // instead of the old one


    Node* insert(Node* node)
    {
        Node* inserted_node = Bst::insert(node);
        /* rotations stuff */
        return inserted_node;
    }
};

我想做的大致是Bst::Node "virtual"

那么,如何解决实现Avl Tree的问题,而不需要仅仅因为Node改变而重写整个insert函数呢?

【问题讨论】:

  • 为什么BST和AVL树的节点类型不同?据我了解,表示的数据是一样的,AVL树只是使用更复杂的算法来插入和删除节点。
  • 这是模板和virtual 是实现同一目标的两种不同机制的情况之一。但在这种特定情况下,virtual 显然是劣势。它不是通常的风格选择,而是一个好/坏的选择。
  • BST 只需要一个值和左右指针,AVL 需要一个额外的高度值和父指针。表示的数据(值)是同一类型
  • 我不相信有足够的共同点值得分享该代码的麻烦。但是,如果您选择这样做,它可以通过几种不同的方式实现。最强大的方法是使用 CRTP,这样基类(其中定义了 insert)可以使用派生类的内部类型(例如 Node)。

标签: c++ inheritance binary-search-tree avl-tree


【解决方案1】:

也许您想要 CRTP(在这种情况下,即使是一个粗略的示例,您也没有提供足够的信息来说明您的需求,但是更简单但功能不太强大的模板方法可能对您更有意义。有一个基类(在您的每个树类型)没有数据成员,只是为公共代码定义了静态模板函数。由于函数是静态的,您需要传入相关数据(对于插入应该是&root)但应该不多麻烦。(粗略且未经测试):

struct tree_base
{
   template <class Node>
   static Node* insert( Node** where, Node* what)
   {
      Node* here;
      while ( (here = *where) != 0 )
      {
         if ( *what < *here ) where = &(here->left);
         else if ( *here < *what ) where = &(here->right);
         else
         {
      Trying to insert something already there, what should be done
         }
      }
      *where = what;
      return what;  // Is that the desired return?
   }
};

然后你的每个真正的树类都将继承自 tree_base 并调用 tree_base::insert(&amp;root, new_node) 来完成 insert 的公共部分

它的 CRTP 版本将允许 root 成为基类的成员,即使它指向派生类的 Node 类型。给定 root 作为基类的成员,插入函数不需要是static,也不需要将&amp;root 作为输入。并且由于 CRTP 基类已正确模板化以访问 Node 类型,因此基类插入方法不需要是模板。所有这些都需要学习更多的东西(通过查看一些 CRTP 的真实示例),并且对于您想要的代码共享来说可能是多余的。

【讨论】:

    【解决方案2】:

    其实我也在做这方面的工作,我觉得你很清楚地描述了你想要什么。

    首先,对于给定的接口可能有点混淆,insert() 不应该返回节点的指针,不是吗。我们可以使用 findNode() 函数,它返回 Node 的指针,只做这个工作。

    回到主要问题,您可以使用模板为 BST 中的每个函数设置节点类型。 但是BST不仅仅是一个抽象接口,它也实现了BST操作,所以不是CRTP..

    现在的伪代码可能如下: // 预定义:

    //parent ptr also alleviate the implementation of BST.
    
    template<typename T>
    class BST{
        ... omit..
        protected:
            template<typename node_type>
            class BST_Node{  
                public:
                    T val;
                    BST_Node *left, *right, *parent;  
                    BST_Node():left{nullptr}, 
                               right{nullptr},
                               parent{nullptr}, val{}{};
            // empty {} default to value initialization.
            }
     ... omit ...
    }
    
    
    template<typename T>
    class AVL_Node : public BST_Node{
        public:
            short height;
            AVL_Node(T val):BST_Node(val), height(0){};
    }
    
    template<typename T>
    void insert(T val){
        AVL_Node<T> Node(val);
        BST<T>::insert_node<AVL_Node>(Node);
        AVL_Node<T>* ptr = BST<T>::find_node<AVL_Node>(val);
        ptr->height = BST<T>::get_height(ptr); 
    
        state = chk_balance(ptr);
        switch(state){
            case 0:  // tree very balance..
                break;
            case 1:
                LL_rotate(ptr);
                break;
            case 2:
                RR_rotate(ptr);
                break;
            ... omit
         }
    }
    

    @帮助这篇文章解决你的问题..

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-19
      • 2013-04-21
      相关资源
      最近更新 更多