【问题标题】:Wrong output after after searching binary search tree搜索二叉搜索树后输出错误
【发布时间】:2013-03-11 08:22:22
【问题描述】:

我正在使用二叉搜索树来收集字符串,然后按后序对它们进行排序。我还使用一个列表来显示字符串出现的行号。我可以使 BST 正常工作,但是我的输出最终出错了。我认为当我遇到一个重复的单词时就会出现问题。当我在重复的单词中添加行号时,我的输出搞砸了。

我的输出应该是这样的

hawaii    3

hello     1

is        3

paradise  2

to        2

welcome   2

wonderful 1 3

world    1

但是我得到这个作为输出

Contents of tree:

hello 1

Contents of tree:

hello 1
wonderful 1
.
.
.

Contents of tree:

hawaii 3
hello 1
is 3
paradise 2
to 2
welcome 2
wonderful 1
world 1

Contents of tree:

is 3
paradise 2
to 2
welcome 2
wonderful 1 3
world 1
Press any key to continue . . .

这里是主要逻辑

struct TreeNode
{
    string data;
    list<int> lineNum;
    TreeNode *left;
    TreeNode *right;


    TreeNode(string str,list<int> num)
    {
        data = str;
        lineNum = num;
        left = NULL;
        right = NULL;
    }
};

void insert(TreeNode *&root, string newNode,list<int> num)
{
    if(root == NULL)
    {
        root = new TreeNode(newNode,num);
    }
    else if(newNode < root -> data)
    {
        insert(root -> left, newNode,num);
    }
    else
    {
        insert(root -> right, newNode,num);
    }
}

bool treeContains( TreeNode *root, string item )
{

    if ( root == NULL )
    {
        return false;
    }
    else if ( item == root->data)
    {
        return true;
    }
    else if ( item < root->data )
    {
        return treeContains( root->left, item );
    }
    else
    {
        return treeContains( root->right, item );
    }
}

void treeInsert(TreeNode *&root, string newItem,int num)
{
    list<int> temp;
    temp.push_back(num);
    if ( root == NULL ) 
    {
        root = new TreeNode(newItem,temp );
        return;
    }
    else if ( newItem < root->data ) 
    {
        treeInsert( root->left, newItem,num );
    }
    else 
    {
        treeInsert( root->right, newItem,num );
    }
}

void printTree(TreeNode *node)
{
    list<int>::iterator i;

    if ( node != NULL )
    {
        printTree(node->left);
        cout <<node->data;
        for( i = node->lineNum.begin(); i != node ->lineNum.end(); ++i)
            cout<<" "<<*i;

        cout << endl;

        printTree(node->right);
    }
}

TreeNode search(TreeNode *root, string item)
{
    while ( root != NULL )
    {
        if(item == root->data)
        {
            break;
        }

        if ( item > root->data )
        {
            root = root-> right;
        }
        else if(item < root->data )
        {
            root = root-> left;
        }

        if(root == NULL)
        {
            cout << "error";
        }

    }
    return *root;
}

int main()
{
    TreeNode *root;
    root = NULL;
    ifstream test("test.txt");
    istringstream strLine;
    string line, word;
    list<int> lineNum;

    int currentLine=0;

    // Go line by line
    while (getline(test,line))
    {
        ++currentLine;

        strLine.clear();
        strLine.str(line);

        lineNum.push_back(currentLine);
        // Now from the line read word by word
        while (strLine >> word)
        {

            // if word is already in tree search tree for node and line number
            if (treeContains(root,word))
            {
                *root = search(root,word);
                root->lineNum.push_back(currentLine);
                cout << "\nContents of tree:\n\n";
                printTree(root);

            }
            // if word is new add to tree insert node
            else
            {
                treeInsert(root,word,currentLine);  
                cout << "\nContents of tree:\n\n";
                printTree(root);
            }
        }
    }
}

输入文本如下所示:

hello wonderful world
welcome to paradise
hawaii is wonderful

提前谢谢各位!

【问题讨论】:

  • 这听起来像是学习使用调试器的绝佳机会。这是一项有用的技能,从长远来看可以为您节省大量时间。
  • 问题没有说得太清楚,但我假设您指的是最后一个输出中缺少“hawaii”和“hello”的事实。如果是这样,那可能是树实现的问题 - 那是您没有显示的代码。
  • 我更新了代码以显示 BST 函数
  • FWIW,这是一大堆 list&lt;int&gt; 对象的复制。您可能要考虑最后一个参数应该是插入代码的const list&lt;int&gt;&amp;。另外,必须你用一棵手卷的树来做这个吗?还是std::map&lt;&gt; 允许?
  • @WhozCraig 我不能使用 std::map

标签: c++ list tree


【解决方案1】:

我查看了您的代码并对其进行了简化。我正在粘贴结果。 错误消失了:)

你的问题主要是你做了两次同样的事情 - 你在“搜索”和“插入”函数中都在树中找到一个节点。这两种实现有细微的差异,会导致您的错误。

我还冒昧地将您的函数调用移至方法调用。

#include <list>
#include <string>
#include <iostream>
#include <fstream>
#include <sstream>
using namespace std;

struct TreeNode {
        string data;
        list<int> lineNum;
        TreeNode *left;
        TreeNode *right;

    public:
        TreeNode(string str, int num) {
            data = str;
            lineNum.push_back(num);
            left = NULL;
            right = NULL;
        }


        void print() const {
            if (this->left != NULL) {
                this->left->print();
            }

            this->printNode();

            if (this->right != NULL) {
                this->right->print();
            }
        }

        static void insert(TreeNode *&root, string newNode, int num) {
            if (root == NULL) {
                root = new TreeNode(newNode, num);
            } else if (newNode < root->data) {
                TreeNode::insert(root->left, newNode, num);
            } else if (newNode > root->data) {
                TreeNode::insert(root->right, newNode, num);
            } else {
                root->lineNum.push_back(num);
            }
        }

    private:
        void printNode() const {
            list<int>::const_iterator i;
            cout<<this->data;

            for (i = this->lineNum.begin(); i != this->lineNum.end(); ++i) {
                cout<<" "<<*i;
            }

            cout << endl;
        }
};


int main()
{
    TreeNode *root;
    root = NULL;
    ifstream test("test.txt");
    istringstream strLine;
    string line, word;
    int currentLine=0;

    // Go line by line
    while (getline(test,line)) {
        ++currentLine;
        strLine.clear();
        strLine.str(line);

        // Now from the line read word by word
        while (strLine >> word) {
            TreeNode::insert(root,word,currentLine);
        }
    }

    cout << "\nContents of tree:\n\n";
    root->print();
}

【讨论】:

  • 感谢您浏览所有我非常感谢的内容。
【解决方案2】:

好的。我盯着看了一会儿。甚至写了我自己的版本,但最后这是我认为你应该做的:

首先,将treeInsert() 更改为如下所示:

void treeInsert(TreeNode *&root, const string& newItem,int num)
{
    if (root == NULL )
    {
        root = new TreeNode(newItem, list<int>(1, num));
        return;
    }

    if (newItem < root->data )
    {
        treeInsert( root->left, newItem, num );
    }
    else if (root->data < newItem)
    {
        treeInsert( root->right, newItem, num );
    }

    else
    {   // found the item. just add it to the node's list
        //  if it isn't already there.
        if (find(root->lineNum.begin(), root->lineNum.end(), num) == root->lineNum.end())
            root->lineNum.push_back(num);
    }
}

为什么?:这实际上首先检查节点是否为 NULL。如果是,那么我们要新建一个节点,并且这样做,其中一个新列表中的一项:当前行号。如果根是 not NULL,那么我们有三个选项。

  1. 如果单词比根单词“小于”,则向下移动左侧树。
  2. 否则,如果该词比根词“更大”,则向下移动右树
  3. 否则它既不小于也不大于,因此它必须相等,因此在行列表中搜索当前行号,如果不存在,添加它。

仅此一项就解决了许多问题。一方面,它减少了我将对您的 main 函数所做的另一项更改(并且它变得 更简单):

int main(int argc, char *argv[])
{
    TreeNode *root = NULL;

    ifstream test("test.txt");
    string line;
    int currentLine=0;

    // Go line by line
    while (getline(test,line))
    {
        ++currentLine;

        istringstream strLine(line);
        string word;
        while (strLine >> word)
        {
            treeInsert(root, word, currentLine);
            cout << "\nContents of tree:\n";
            printTree(root);
        }
    }
    return 0;
}

最后,这允许您丢弃以下不需要的函数:

void insert(TreeNode *&root, string newNode,list<int> num);
bool treeContains( TreeNode *root, string item );
TreeNode search(TreeNode *root, string item);

根据我指出的更改,以下是我认为您期望的输出:

Contents of tree:
hello 1

Contents of tree:
hello 1
wonderful 1

Contents of tree:
hello 1
wonderful 1
world 1

Contents of tree:
hello 1
welcome 2
wonderful 1
world 1

Contents of tree:
hello 1
to 2
welcome 2
wonderful 1
world 1

Contents of tree:
hello 1
paradise 2
to 2
welcome 2
wonderful 1
world 1

Contents of tree:
hawaii 3
hello 1
paradise 2
to 2
welcome 2
wonderful 1
world 1

Contents of tree:
hawaii 3
hello 1
is 3
paradise 2
to 2
welcome 2
wonderful 1
world 1

Contents of tree:
hawaii 3
hello 1
is 3
paradise 2
to 2
welcome 2
wonderful 1 3
world 1

我希望这会有所帮助。

【讨论】:

  • 今晚我学到了很多。感谢您花时间审查和解释代码。谢谢一百万。
  • @FireStorm 没问题。这是我能看到的最小更改,它可以让您使用所有相关的现有代码并最终正常工作。我仍然有很多不同的方式来写这个,但那就是我;这是你的。大部分都还不错。例如,我没有对您的节点结构或打印机进行任何更改。无论如何,很高兴它有所帮助。
猜你喜欢
  • 2015-05-14
  • 1970-01-01
  • 2023-03-08
  • 2021-08-22
  • 2022-11-15
  • 2021-01-01
  • 1970-01-01
  • 2010-12-23
  • 2019-04-15
相关资源
最近更新 更多