二进制搜索树问题

Binary Search Tree issue

本文关键字:问题 搜索树 二进制      更新时间:2023-10-16

我真的被卡住了,我在"CTree.add(num);"处收到一个错误,说"CTree"未声明,这没有意义,因为我在tree.h中初始化了它?

该程序应该提示用户,用户输入一个命令(即"添加3",只有0-9个整数),然后我希望它将该数字插入树中。

//File: tree.h
class CTree
{
private:
    CTree* m_pLeft;
    CTree* m_pRight;
    CTree* m_pRoot;
    int m_nData;
public:
    CTree();
    bool isEmpty() const { return m_pRoot; }
    bool search(int);
    void print_inorder();
    void inorder(CTree*);
    void Add(int);
    void remove(int);
    void height();
};
//File: CTree.cpp
#include <iostream>
#include <cstdlib>
using namespace std;
CTree::CTree()
{
 m_pRoot=NULL;
}
bool CTree::search(int x)
{
    if(x==m_nData) return true;
    if(x < m_nData){ //go left
       if(m_pLeft != NULL) //if possible
            return m_pLeft->search(x);
    }
    else //go right
       if(m_pRight != NULL) //ifpossible
            return m_pRight->search(x);
    return false;
}
void CTree::Add(int x)
{
CTree* t = new CTree;
CTree* parent;
t->m_nData = x;
t->m_pLeft = NULL;
t->m_pRight = NULL;
parent = NULL;
if(isEmpty()) m_pRoot = t;
else
{
     //insert leaf nodes
    CTree* leaf;
    leaf = m_pRoot;
     // find parent
    while(leaf)
    {
        parent = leaf;
        if(t->m_nData > leaf->m_nData)
            leaf = leaf->m_pRight;
        else
            leaf = leaf->m_pLeft;
    }
    if(t->m_nData < parent->m_nData)
       parent->m_pLeft = t;
    else
       parent->m_pRight = t;
}
}
void CTree::remove(int x)
{
bool found = false;
if(isEmpty())
{
    cout<< "Tree is empty!" <<endl;
    return;
}
CTree* current;
CTree* parent;
current = m_pRoot;
while(current != NULL)
{
     if(current->m_nData == x)
     {
        found = true;
        break;
     }
     else
     {
         parent = current;
         if(x > current->m_nData) current = current->m_pRight;
         else current = current->m_pLeft;
     }
}
if(!found)
{
    cout<< "Not found!" <<endl;
    return;
}
// Node with single child
if((current->m_pLeft == NULL && current->m_pRight != NULL)|| (current->m_pLeft != NULL&& current->m_pRight != NULL))
{
   if(current->m_pLeft == NULL && current->m_pRight != NULL)
   {
       if(parent->m_pLeft == current)
       {
         parent->m_pLeft = current->m_pRight;
         delete current;
       }
       else
       {
         parent->m_pRight = current->m_pRight;
         delete current;
       }
   }
   else // left child present, no right child
   {
      if(parent->m_pLeft == current)
       {
         parent->m_pLeft = current->m_pLeft;
         delete current;
       }
       else
       {
         parent->m_pRight = current->m_pLeft;
         delete current;
       }
   }
 return;
}
             //We're looking at a leaf node
             if( current->m_pLeft == NULL && current->m_pRight == NULL)
{
    if(parent->m_pLeft == current) parent->m_pLeft = NULL;
    else parent->m_pRight = NULL;
                             delete current;
//Node with 2 children
// replace node with smallest value in right subtree
if (current->m_pLeft != NULL && current->m_pRight != NULL)
{
    CTree* check;
    check = current->m_pRight;
    if((check->m_pLeft == NULL) && (check->m_pRight == NULL))
    {
        current = check;
        delete check;
        current->m_pRight = NULL;
    }
    else // right child has children
    {
        //if the node's right child has a left child
        // Move all the way down left to locate smallest element
        if((current->m_pRight)->m_pLeft != NULL)
        {
            CTree* lcurrent;
            CTree* lcurrent_parent;
            lcurrent_parent = current->m_pRight;
            lcurrent = (current->m_pRight)->m_pLeft;
            while(lcurrent->m_pLeft != NULL)
            {
               lcurrent_parent = lcurrent;
               lcurrent = lcurrent->m_pLeft;
            }
            current->m_nData = lcurrent->m_nData;
            delete lcurrent;
            lcurrent_parent->m_pLeft = NULL;
       }
       else
       {
           CTree* tmp;
           tmp = current->m_pRight;
           current->m_nData = tmp->m_nData;
           current->m_pRight = tmp->m_pRight;
           delete tmp;
       }
    }
             return;
}
}
}
void CTree::print_inorder()
{
 inorder(m_pRoot);
}
void CTree::inorder(CTree* x)
{
  if(x != NULL)
{
    if(x->m_pLeft) inorder(x->m_pLeft);
    cout<<" "<<x->m_nData<<" ";
    if(x->m_pRight) inorder(x->m_pRight);
}
else return;
}
//File: main.cpp
#include <iostream>
#include <cstdlib>
#include <sstream>
#include <locale>
#include <string>
#define PROMPT "bst> "
using namespace std;
int getNumber(string s)
{
    int num;
for(int i; i<=s.length();i++)
{
        if(isdigit(s[i]))
        {
              num= s[i]-48;
        }
}
return num;
} // getNumber
bool process(const string& s, CTree* aTree)
{
    bool mustquit=false;
    int num;
    istringstream iss(s);
do
{
    string sub;
    iss >> sub; //               
    if(sub=="add" || sub=="insert")
    {
        num=getNumber(s);
        cout<<num<<endl;
        aTree->Add(num);
    }
    else if(sub=="delete" || sub=="remove")
    {
        num=getNumber(s);
        cout<<num<<endl;
    }
    else if(sub=="search" || sub=="find")
    {
         num=getNumber(s);
         cout<<num<<endl;
    }
    else if(sub=="height")
    {
         //do stuff
    }
    else if (sub=="quit") 
        return mustquit;
    //else cout<<"INPUT ERROR"<<endl;    
 }  while (iss);     


 return mustquit;
 }// process

int main(){ 
string input="";
CTree *myTree;
myTree = new CTree();
bool finished=false;
int i;

    cout<<PROMPT;
    while(!finished)
    {
            if(input!="")cout<<PROMPT;
            getline(cin,input);
            finished=process(input, myTree);
            delete myTree;
    }//while
return 0;
}

add是一个非静态成员函数,这意味着您只能在CTree实例上调用它。例如

CTree myTree;
myTree.add(num);

您知道需要CTree类的实例才能实际使用它吗?你在假设你正在操作一个类的实例的情况下写了整个东西。一个实际的树,而不是它的蓝图

正如前面的答案所说,它不是一个静态函数或类级别。需要在实例上调用一个非静态方法,以便将静默指针this设置为有意义的东西,即您正在处理的实际实例——在本例中是添加一个节点。

附录

(下面的所有内容都可以在不修改代码的情况下工作,只是对问题的明确回答,使其编译。从"工作的角度"来看,这个程序还远远不够完整。有些部分甚至没有意义,许多变量被闲置或未初始化(然后被使用)。让我在下面进一步阐述。)

你需要做的是在发生旧process()调用的main中添加这个:

CTree myTree; // you could also add (), even though it's a default constructor
finished=process(input, myTree);

并修改函数进程的参数列表,以包含对您希望操作的树的引用。这只是其中一种可能性,您也可以使用指针等。但引用更干净:

bool process(const string& s, CTree& aTree)

此外,请注意编译器警告。好的做法是照顾好他们所有人。记住,这会使它编译,而不是工作。它似乎未完成,边缘粗糙。

记住类(一个想法)和实例(这个想法的表现形式)之间的区别。技术细节现在并不重要,只要确保你有一个实例可以使用,就像你的类设计所希望的那样。在我看来,你似乎不了解计算机软件是如何工作的,不了解操作它的数据和指令是如何连接的,尤其是从内存的角度来看。仅仅让计算机知道你想做什么是不够的,它需要知道你想执行什么操作(哪些变量或对象,或者你有什么)。你可以按值复制并返回,在主函数中执行,传递一个引用或一个带地址的指针,这样它就可以知道你的对象/实例在内存中的位置等等。如果你只是在尝试,你可以创建一个全局实例。有很多选择。

重新定义一切并不能继承以前发生的更改(因为内容超出了范围)。在类级别调用非静态成员方法也没有意义,甚至不正确。

希望它能帮助和快乐的编码。坚持下去,没有什么值得做的事是简单的

我认为他们对您的经验水平来说有点过于技术化了。YourTree类代码创建了什么是CTree类以及它的行为(蓝图),但实际上你必须告诉你的代码构造一个,然后有一种方法来引用它

您可以这样声明一个堆栈变量实例:

CTree myTree;  

这为类分配内存,并在进入函数时调用构造函数。然后,您可以通过使用点符号引用实例名称中的函数来处理它。

myTree.Add(4);

或者,您可以声明一个指向CTree的指针,并使用新的操作符创建一个动态实例

CTree *myTree;
myTree = new CTree();

然后使用指针表示法引用树:

myTree->Add(4);

如果你这样做,你将需要删除你分配给的内存

delete myTree;

总之,这里显示的类定义描述了一个类,但没有创建一个类(为方法代码分配内存和设置指针)。如果代码逻辑需要,这允许您拥有许多树;

CTree directoryTree;
CTree fileTree;
CTree indexTree;

每个人都有自己的数据。。。

祝你好运,