二进制搜索树问题

时间:2012-04-05 00:49:30

标签: c++ binary-search-tree

我真的被困了,我在“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;
}

3 个答案:

答案 0 :(得分:5)

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

CTree myTree;
myTree.add(num);

答案 1 :(得分:1)

您知道您需要类CTree实例来实际使用它吗?你假设你正在一个类的实例上运行,你写了整个事情。实际的树,而不是蓝图

正如我前面的回答所说,它不是静态函数或类级别。需要在实例上调用非静态方法,以便可以将静默指针this设置为有意义的内容,即。您正在使用的实际实例 - 在这种情况下添加节点。

<强>附录

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

你需要做的就是在主进程中发生旧的process()调用:

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

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

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

另外,请注意编译器警告。良好的做法是照顾所有这些。请记住,这使得它编译,而不是工作。它似乎没有完成,边缘粗糙。

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

重新声明一切都不会带来之前发生的变化(因为东西超出了范围)。

,在类级别调用非静态成员方法也没有意义。

希望它有助于编码。坚持下去,没有什么值得做的很简单。

答案 2 :(得分:0)

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

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

CTree myTree;  

这为您的类分配内存,并在进入函数时调用构造函数。然后,您可以使用点表示法从实例名称引用函数来使用它。

myTree.Add(4);

或者您可以声明指向CTree的指针并使用new运算符

创建动态实例
CTree *myTree;

myTree = new CTree();

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

myTree->Add(4);

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

delete myTree;

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

CTree directoryTree;
CTree fileTree;
CTree indexTree;

这些都有自己的数据......

祝你好运,