【问题标题】:How to call a function method recursively in classes in c++?如何在 C++ 中的类中递归调用函数方法?
【发布时间】:2020-06-18 20:30:29
【问题描述】:

所以,不久前我开始学习和阅读 OOP,我一直在使用类和对象来实现我所知道的所有数据结构,只是为了整体练习并熟悉在 c++ 中使用 OOP。

我正在实现树数据结构,我一直想知道如何递归调用一个方法(我知道我必须传入一个参数),这样当我在 main 中创建一个对象并调用一个特定的方法写成如下a.inorder(); 而不是a.inorder(root),因为root 是私有属性。

这可能吗?

我的代码:

#include<iostream>
using namespace std;

struct node
{
    int data;
    node* left;
    node* right;
};

class tree
{
private:
    node* root;
public:
    tree();
    tree(int val);

    void insert(int val);
    void preorder();
    void postorder();
    void inorder();
    int count();
};

tree::tree() : root { NULL }
{
}
tree::tree(int val)
{
    root = new node;
    root->data = val;
    root->left = root->right = NULL;
}

void tree::insert(int val)
{
    if (!root)
    {
        root = new node;
        root->data = val;
        root->left = root->right = NULL;
    }

    else
    {
        node* t = root;
        node* p = NULL;

        while (t)
        {
            p = t;

            if (val > root->data)
                t = root->right;
            else
                t = root->left;
        }

        t = new node;
        t->data = val;
        t->left = t->right = NULL;

        if (p->data > t->data)
            p->left = t;
        else
            p->right = t;
    }
}
void tree::preorder()
{
    if (root)
    {

    }
}

【问题讨论】:

  • ⟼请记住,尤其是在 Stack Overflow 上学习和提问时,尽可能让代码保持井井有条是很重要的。 Consistent indentation 有助于传达结构,更重要的是,有助于传达意图,这有助于我们快速找到问题的根源,而无需花费大量时间尝试解码正在发生的事情。
  • 如果一个类有一个像root 这样的属性,那么将它传递给一个函数是多余的,这个类已经知道它是什么了。对于递归,您始终可以使用单独的 protected 方法进行挖掘,然后根据需要使用它。
  • indirection 是你的朋友...从该方法调用另一个执行递归的 [private] 方法
  • “我知道我必须传入一个参数” - 在一个类中,每个(非静态)方法属性都会自动传递一个“this”指针。在某些递归工作中,隐藏指针就足够了。

标签: c++ oop


【解决方案1】:

在您的设计中,node 指的是它自己。由于是递归的node对象,你可以在node上定义递归方法:

struct node
{
    int data;
    node* left;
    node* right;

    void preorder() {
        //...
        left->preorder();
        right->preorder();
    }
};

然后,tree::preorder() 只会向root-&gt;preorder() 发送呼叫。

【讨论】:

    【解决方案2】:

    编写一个私有静态递归函数,将指向根节点的指针传递给它,并从相应的公共非静态成员函数中调用该函数。

    例如

    public:
        std::ostream & preorder( std::ostream &os = std::cout ) const
        {
            return preorder( root, os );
        }
        //...
    
    private:
        static std::ostream & preorder( const node *root, std::ostream &os );
        //...
    

    【讨论】:

      【解决方案3】:

      这是评论而非实际答案,因为它解决的问题与您所询问的问题不同。不过评论区太长了,所以才放在这里。

      我想你在这部分错误地引用了root

              while (t)
              {
                  p = t;
      
                  if (val > root->data)
                      t = root->right;
                  else
                      t = root->left;
              }
      

      恕我直言,它应该是这样的:

              while (t)
              {
                  p = t;
      
                  if (val > t->data)
                      t = t->right;
                  else
                      t = t->left;
              }
      

      还将寻找插入位置的代码与进行实际插入的代码进行比较:

              if (p->data > t->data)
                  p->left = t;
              else
                  p->right = t;
      

      您已将比较子表达式以相反的顺序放置 - 查找时,您测试新值是否大于现有节点中的值,但在插入时,您测试现有值是否大于新值。如果它们不同,则代码可以正常工作,因为您还在“then”和“else”分支中交换了 leftright
      但是,如果值看起来相等,则执行控制将在两个位置转到“else”。因此,测试代码可能会在空的left 指针处停止,但随后会在right 上附加一个新节点,而NULL 并未经过测试。

      【讨论】:

        【解决方案4】:

        为什么tree 类会对node 执行内部操作? node 类最了解node 的内部结构,所以让它自己初始化。这也将帮助您坚持使用DRY principle,并间接地使用KISS principle,以及Single-responsibility principle

        结构节点
        {
            整数数据;
            节点*左;
            节点* 对;
        
            节点(int val):数据(val),左(NULL),右(NULL){}
        };
        
        类树
        {
        私人的:
            节点*根;
        上市:
            树();
            树(int val);
        
            无效插入(int val);
        };
        
        树::树() : 根 { NULL }
        {
        }
        
        树::树(int val) : 根(新节点(val))
        {
        }
        
        无效树::插入(int val)
        {
            如果(!根)
            {
                根=新节点(val);
            }
            别的
            {
                节点* t = 根;
                节点* p = NULL;
                
                而 (t)
                {
                    p = t;
                    
                    如果(val 数据)
                        t = t->左;
                    别的
                        t = t->对;
                }
                
                t = 新节点(val);
                
                如果(t-> 数据  数据)
                    p->左 = t;
                别的
                    p->右=t;
            }
        }
        

        此外,您也可以使 insert 递归。

        结构节点
        {
            整数数据;
            节点*左;
            节点* 对;
        
            节点(int val):数据(val),左(NULL),右(NULL){}
        };
        
        类树
        {
        私人的:
            节点*根;
        上市:
            树();
            树(int val);
        
            无效插入(int val);
        受保护:
            无效插入(节点* p,int val);
        };
        
        无效树::插入(int val)
        {
            如果(!根)
                根=新节点(val);
            别的
                插入(根,val);
        }
        
        无效树::插入(节点* t,int val);
        {
            如果(val 数据)
            {
                如果(t->左)
                    insertat(t->left, val);
                别的
                    t->left = 新节点(val);
            }
            别的
            {
                如果(t-> 右)
                    insertat(t->right, val);
                别的
                    t->right = 新节点(val);
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2022-01-24
          • 1970-01-01
          • 2019-08-21
          • 1970-01-01
          • 1970-01-01
          • 2014-04-28
          • 2018-04-19
          • 2010-10-28
          • 1970-01-01
          相关资源
          最近更新 更多