【问题标题】:Printing all the words from a prefixtree in order按顺序打印前缀树中的所有单词
【发布时间】:2020-02-18 16:56:02
【问题描述】:

我已经设置了一个程序,它可以接收用户输入来创建前缀树。每个字符都是一个连接在一起的节点。我有一个“打印”命令,如果用户输入以下内容,它将打印出以下单词:cat、car、sat、saw: ca(R,T),sa(T,W)。

我正在尝试创建两个函数来代替按字母顺序打印出用户给出的单词。一个函数PrintAllWords() 是完成大部分工作的函数,我正在考虑让这个函数成为一个递归函数,通过push_back() 将每个单词打印到某种全局字符串,然后删除当前单词从 pull_back() 移到下一个。第二个函数printWordList();会打电话给printAllWords();并打印出创建的单词列表。

我从一些代码开始尝试慢慢到达我想要的地方,但是当我使用命令“list”(新函数的命令)时,我的代码只给了我父节点 C 和 S如下:cs.

我怎样才能得到每个单词的第一个节点,试着让前缀树中的第一个单词是“cat”。

我的头文件:

#ifndef __PREFIX_TREE_H
#define __PREFIX_TREE_H

#include <iostream>
using namespace std;

const int ALPHABET_SIZE = 26;

class PrefixTreeNode;

/*
  Prefix tree
  Stores a collection of strings as a tree
 */
class PrefixTree
{

private:
  PrefixTreeNode* root;
public:
  //Constructs an empty prefix tree
  PrefixTree();
  //Copy constructor
  PrefixTree(const PrefixTree&);
  //Copy assignment
   const PrefixTree& operator=(const PrefixTree&);
  //Utility func: checks whether all characters in str are letters
  bool isAllLetters(const string&) const;
  //Returns the root of the prefix tree
  PrefixTreeNode* getRoot() { return root; };
  //Returns the root of the prefix tree
  const PrefixTreeNode* getRoot() const { return root; };
  //Returns whether or not the given word belongs to the prefixtree
  bool contains(const string&) const;
  //Adds the given word to the prefix tree
  void addWord(const string&);
  //Prints all of the words in the prefix tree
  void printWordList() const;
  //Destructor
  ~PrefixTree();
};

/*
  Node of a prefix tree
 */
class PrefixTreeNode
{
  friend PrefixTree;
private:
  char c;
  bool final;
  PrefixTreeNode* link[ALPHABET_SIZE];
public:
  //Constructs a new node
  PrefixTreeNode();
  //Copy constructor
  PrefixTreeNode(const PrefixTreeNode&);
  //Copy assignment
  const PrefixTreeNode& operator=(const PrefixTreeNode&);
  //Returns the character this node contains
  char getChar() const { return c; }
  //Returns whether this node is the end of a word
  bool isFinal() const { return final; }
  //Changes whether this node is the end of a word
  void setFinal(bool b) { final = b; }
  //Returns the node corresponding to the given character
  PrefixTreeNode* getChild(char);
  //Returns the node corresponding to the given character
  const PrefixTreeNode* getChild(char) const;
  //Adds a child corresponding to the given character
  void addChild(char);
  //Removes the child corresponding to the given character
  void deleteChild(char);
  //print all words that end at or below this PrefixTreeNode
  void printAllWords() const;
  //Destructor
  ~PrefixTreeNode();
};

ostream& operator<<(ostream&, const PrefixTree&);
ostream& operator<<(ostream&, const PrefixTreeNode&);
#endif

我的源文件功能:

void PrefixTreeNode::printAllWords() const{

for (char c = 'a'; c < 'z' + 1; c++)
    {
      if (this->getChild(c) == nullptr)
        continue;

        this->getChild(c);
      cout << c;
    }

}

//Calls all words
void PrefixTree::printWordList() const{

    PrefixTreeNode* node = root;
    node->printAllWords();
}

PrefixTreeNode* PrefixTreeNode::getChild(char c)
{
  if (isalpha(c))
    return link[tolower(c)-'a'];
  else
    return nullptr;
}

void PrefixTree::addWord(const string& str)
{
  PrefixTreeNode* node = root;
  for (int i = 0; i < str.size(); i++)
  {
    if (node->getChild(str[i]) == nullptr)
      node->addChild(str[i]);
    node = node->getChild(str[i]);
  }
  node->setFinal(true);
}

【问题讨论】:

  • 与您的问题无关,但所有以双下划线开头的符号(例如__PREFIX_TREE_H)都是保留,不应被程序定义为预处理器或其他符号。详情请见What are the rules about using an underscore in a C++ identifier?
  • 至于你的问题,我建议你在printAllWords函数上做一些rubber duck debugging。它到底在做什么?
  • 在一个稍微相关的说明中,并非所有字符编码都有连续编码的字母。 ASCII 有,但还有其他可能的编码仍在使用(例如EBCDIC),其中像您这样的字母循环将不起作用。
  • 您可能希望在打印代码中使用递归。
  • 这棵树怎么有一个根?哪个字符在那个根中?

标签: c++ class pointers recursion member-function-pointers


【解决方案1】:

我们使用递归来按顺序打印树中所有存储的字符串。使用 printAllWords(root, "") 从 main 调用函数。如果root 指向nullptr,我们返回。如果root-&gt;finaltrue,我们打印这个词。然后我们将当前字符附加到word 并循环遍历它的所有子元素并为每个子元素调用printAllWords

每个节点都会发生同样的情况。

void printAllWords(Node* current, std::string word)
{
    if (current == nullptr)
        return;

    if (current->final)
        std::cout << (word+current->c) << std::endl;

    for (int i = 0; i < ALPHABET_SIZE; ++i)
        printAllWords(current->link[i], word + current->c);
}

编辑:虽然我必须承认我不确定 c 在树节点中有什么用处。如果您构建特里树,如果假设当前节点的第二个孩子 (b) 不为空,那么这意味着 b 是通过它的另一个单词的踪迹的一部分。下面的代码应该清楚:

void printAllWords(Node* root)
{
    string word = "";
    for (int i = 0; i < ALPHABET_SIZE; ++i)
        printAllWords(root->link[i], word + (char)(i + 'a'));
}

void printAllWords(Node* current, std::string word)
{
    if (current == nullptr)
        return;

    if (final)
        std::cout << word << std::endl;

    for (int i = 0; i < ALPHABET_SIZE; ++i)
        printAllWords(current->link[i], word + (char)(i + 'a'));
}

【讨论】:

  • 为什么?是什么让你的代码工作?请尝试解释一下,这样它就不会成为cargo cult programming 的又一次推广,而且操作简单,操作人员可能不知道它是如何工作或为什么工作的。
  • 啊,是的,你是对的。我将编辑代码。谢谢。
猜你喜欢
  • 2016-05-17
  • 1970-01-01
  • 1970-01-01
  • 2020-08-18
  • 2014-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多