【问题标题】:Binary Search Tree--Inserting a Node二叉搜索树--插入一个节点
【发布时间】:2020-10-09 01:42:49
【问题描述】:

我正在尝试实现一个将节点插入二叉搜索树的函数。我正在使用以下代码,但是当我尝试打印到屏幕时,我看到的只是“root = 1”。关于我做错了什么有什么建议吗?

#include <iostream>

class BTNode {
public:
   int item;
   BTNode *left;
   BTNode *right;
   BTNode(int i, BTNode *l=nullptr, BTNode *r=nullptr):item(i),left(l),right(r){}
};

BTNode *root = nullptr;
void insert(int i) {
   if (root==nullptr)
      root=new BTNode(i);
   else if(i<root->item){
      root=root->left;
      insert(i);
   }
   else{
      root=root->right;
      insert(i);
   }
}

int main()
{
   insert (5);
   insert (10);
   insert (1);
   
   if (root) 
   {
      std::cout << "root = " << root->item << std::endl;
      if (root->left)
         std::cout << "root->left = " << root->left->item << std::endl;
      if (root->right)
         std::cout << "root->right = " << root->right->item << std::endl;
   }
   
   return 0;
}

【问题讨论】:

  • 您是否尝试过在调试器中逐行运行代码,同时监控所有变量的值,以确定您的程序在哪个点停止按预期运行?如果您没有尝试过,那么您可能想阅读以下内容:What is a debugger and how can it help me diagnose problems? 您可能还想阅读以下内容:How to debug small programs?
  • your rubber duck.讨论root=root-&gt;left;的效果
  • 通过查看您的代码,您的 insert 函数似乎正在正确地将新节点添加到树中。但是,作为副作用,它有时会将全局变量root 更改为根的左侧或右侧节点,从而导致树的其余部分丢失。你的insert 函数永远不应该改变根,除非root == nullptr
  • 不要将root 设为全局变量,您可能希望将其设为main 的局部变量并将其作为函数参数传递给insert。这也将使递归函数调用更容易。
  • 建议:摆脱全局root。它以多种方式使您变得更加困难(例如,您不能同时拥有两个 BST)并且可能成为调试的噩梦。通过引用传递节点,例如 void insert(BTNode* &amp; location, int i)

标签: c++ binary-search-tree


【解决方案1】:

你的代码效果如下

  1. insert(5):创建一个值为 5 的新 BTNode 并将其分配给 root
  2. insert(10):创建一个值为 10 的新 BTNode 并将其分配给 root。您不再拥有对先前创建的节点的引用
  3. insert(1):创建一个值为 1 的新 BTNode 并将其分配给 root。您不再引用之前创建的两个节点中的任何一个。

您可以通过这种方式实现插入函数,它通常是 BTNode 类的成员函数,这就是我将它们称为私有/公共的原因,但是由于您选择将它们实现为类外部的函数,因此我将它们保持这种方式。

首先你有一个公共插入函数

void insert(int i){
      insert( i,root);// call the private function. see below
}

第二个你有一个私有插入函数(注意指针变量应该通过引用传递,否则会改变指针的副本)

void insert(int i,BTNode *& t){
    if(t==nullptr)t=new Node(i);
    else if(i<t->item)insert(i,t->left);
    else insert(i,t->right);
}

【讨论】:

    【解决方案2】:

    我在下面写下了代码。

    BTNode *root = nullptr;
    BTNode* insert_node(int ivalue, BTNode* _parent) {
        if (_parent == nullptr) {
            return _parent = new BTNode(ivalue);
        }
        else if (ivalue<_parent->item) {
            _parent->left = insert_node(ivalue, _parent->left);
        }
        else {
            _parent->right = insert_node(ivalue, _parent->right);
        }
        return nullptr;
    }
    void insert(int i) {
        BTNode*newnode = insert_node(i, root);
        if (newnode)root = newnode;
    }
    
    int main()
    {
        insert(5);
        insert(10);
        insert(1);
        //insert(2);
        //insert(4);
        if (root)
        {
            std::cout << "root = " << root->item << std::endl;
            if (root->left)
                std::cout << "root->left = " << root->left->item << std::endl;
            if (root->right)
                std::cout << "root->right = " << root->right->item << std::endl;
        }
    
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      您的insert 函数正在正确地将新节点添加到树中。但是,作为副作用,有时会更改全局变量root 以指向根的左侧或右侧节点,从而导致树的其余部分丢失。你的insert 函数不应该改变根,除非root == nullptr

      因此,我建议你重写你的函数insert,让它根本不使用root,而是接收一个指向节点的指针作为函数参数。该指针必须通过引用而不是值传递,因为函数insert 必须能够更改传递的实际指针,如果它是nullptr。为了实现这一点,您可以将函数原型更改为以下内容:

      void insert( BTNode &amp;*pp_node, int i );

      这也将使您的递归函数调用正常工作,因为该函数现在可以像这样重写:

      void insert( BTNode *&node, int i )
      {
          if ( node == nullptr )
              node = new BTNode( i );
          else if ( i < node->item )
              insert( node->left, i );
          else
              insert( node->right, i );
      }
      

      您的函数main 必须这样重写:

      int main()
      {
          insert( root, 5 );
          insert( root, 10 );
          insert( root, 1 );
      
          [...]
      }
      

      但是,由于您不再需要将 root 作为全局变量(因为它现在作为函数参数传递),因此最好将其声明为局部变量,如下所示:

      int main()
      {
          BTNode *root = nullptr;
      
          insert( root, 5 );
          insert( root, 10 );
          insert( root, 1 );
      
          [...]
      }
      

      虽然此问题的递归解决方案有效,但迭代解决方案会更有效。因此,您可能希望像这样重写您的函数insert

      void insert( BTNode **pp_node, int i )
      {
          while ( *pp_node != nullptr )
          {
              if ( i < (*pp_node)->item )
                  pp_node = &(*pp_node)->left;
              else
                  pp_node = &(*pp_node)->right;
          }
      
          *pp_node = new BTNode( i );
      }
      

      此解决方案需要指向指针的指针(所谓的双指针)而不是对指针的引用,因为无法重新分配引用。

      但是,由于 insert 的函数原型现在已经更改,您还必须相应地调整函数 main

      int main()
      {
          BTNode *root = nullptr;
      
          insert( &root, 5 );
          insert( &root, 10 );
          insert( &root, 1 );
      
          [...]
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-11
        • 1970-01-01
        • 1970-01-01
        • 2022-01-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多