简体   繁体   中英

Binary Search Tree issue

I am really stuck, I'm getting an error at "CTree.add(num);"saying 'CTree' is undeclared, which doesn't make sense because I initialized it in tree.h?

The program is supposed to prompt the user, the user enters a command (ie "add 3", only 0-9 integers) and then I want it to insert that number into the tree.

//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 is a non-static member function, which means you can only call it on an instance of CTree . eg

CTree myTree;
myTree.add(num);

You are aware that you need an instance of the class CTree to actually use it? You wrote the entire thing under the assumption that you're operating on an instance of a class. An actual tree, rather than a blueprint for it.

As the answer before me said, it's not a static function or class-level. A non-static method needs to be invoked on an instance so that a silent pointer this can be set to something meaningful, ie. the actual instance you're working with - in this case adding a node.

ADDENDUM

(everything below works without modifying your code, just an explicit answer to your question, to make it compile. From a "working standpoint", this program is far from complete. Some pieces don't even make sense, many variables are left unused or uninitialized (and then used). Let me elaborate further below.)

What you need to do is this add this in your main where the old process() call occured:

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

And modify the function process' argument list to include a reference to your tree which you wish to operate on. This is just one of the possibilities, you can also take a pointer etc. But a reference is cleaner:

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

Also, pay attention to compiler warnings. Good practice is to take care of all of them. And remember, this makes it compile, not work. It seems unfinished and rough around the edges.

And remember the difference between a class (an idea) and an instance (a manifestation of that idea). The technical details are not important right now, just make sure you have an instance to work with, as your class design intends. It seems to me that you don't have a grasp around how computer software works, how data and instructions that operate on it connect, especially from a viewpoint of memory. It's not enough for the computer to know what you want to do, it needs to know on what do you want the operations performed (which variables or objects or what-have-you). You can copy by value and return, do it in the main function, pass a reference or a pointer with an address so it can know where in memory is your object/instance located etc. If you're just experimenting, you could create a global instance. A lot of options.

Redeclaring everything doesn't carry over the changes that happen previously (since stuff goes out of scope). Nor does it make sense to call non-static member methods on the class level - and not even properly.

Hope it helps and happy coding. Keep at it, nothing worth doing is simple.

I think they are getting a little too technical for your level of experience. YourCTree class code creates what a CTree class is and how it behaves (a blueprint) but you actually have to tell your code to construct one and then have a way to reference it.

You can declare a stack variable instance like this:

CTree myTree;  

This allocates the memory for your class and calls the constructor on entry into the function. You would then work with it by referencing the functions from the instance name using dot notation.

myTree.Add(4);

Or you can declare a pointer to a CTree and create a dynamic instance using the new operator

CTree *myTree;

myTree = new CTree();

Then you reference the tree using pointer notation:

myTree->Add(4);

if you do it that way you will need to delete the memory you allocated

delete myTree;

So in summary, a class definition of the kind you show here describes a class, but does not create one (allocate memory and setup pointers to the method code). This allows you to have many trees if your code logic requires them;

CTree directoryTree;
CTree fileTree;
CTree indexTree;

These would each have their own data...

Good luck,

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM