Trie,phonenumbers的前缀

时间:2014-02-24 16:12:12

标签: c++ trie

我正在构建一个以电话号码作为输入的程序。然后应检查是否已存在电话号码,该电话号码是我们新号码中的前缀。 例如:

Input:
555 //This is okay
5556888 //This is not okay because 555 is a registered number
556888 //this is okay
5568889 // Not okay

希望你明白我的目标。

我已经实现了两个功能:

包含 那应该检查数字或前缀是否已经存在。

bool PrefixStringSet::contains(string s)
{
    NodePtr temp = root;
    for ( int i = 0; i < s.size(); i++)
    {
        if(temp->children[s[i] - '0'] == NULL)
        {
            return false;
        }
        temp = temp->children[s[i] - '0'];
    }
    return true;
}

插入

bool PrefixStringSet::insert(string s)
{
    if(contains(s) == true)
    {
        return false;
    }
    NodePtr temp = root;
    for (int i = 0; i < s.size(); i++)
    {
        int number = (int)s[i] - (int)'0';
        if(temp->children[number] == NULL)
        {
            temp->children[number] = new TrieNode;
            temp = temp->children[number];
        }
    }
    return true;
}

现在只包含支票,如果号码已经注册的话。我无法弄清楚检查前缀是否已经是一个数字的好方法。 我应该在contains或者插入函数中实现它(也许有一个循环遍历每个前缀,从第一个数字开始?)

任何帮助表示感谢。

主要

int main()
{
    PrefixStringSet Phonenumber;
   int HowManyPhoneNumbers;
   cin >> HowManyPhoneNumbers;
   for(int i = 0 ; i<HowManyPhoneNumbers ; i++)
   {

       string temp;
       cin >> temp;
       if(Phonenumber.insert(temp) == true)
       {
           cout << "Yes" << endl;
       }
       else
       {
           cout << "NO" <<endl;
       }

   }
  return 0;
}

修改 插入:

    bool PrefixStringSet::insert(string s)
    {
       if(contains(s) == true)
        {
            return false;
        }
        NodePtr temp = root;
        for (int i = 0; i < s.size(); i++)
        {
            int number = (int)s[i] - (int)'0';
            if(temp->children[number] == NULL)
            {
                temp->children[number] = new TrieNode;
            }
            temp = temp->children[number];
        }
        return true;
    }

Contains:
bool PrefixStringSet::contains(string s)
{
    NodePtr temp = root;
    for ( int i = 0; i < s.size(); i++)
    {
        if(temp->is_leaf())
        {
            return false;
        }
        if(temp->children[s[i] - '0'] == NULL)
        {
            return false;
        }
        temp = temp->children[s[i] - '0'];
    }
    return true;
}

input:
 911
YES
9111 /Not working
Yes
91 //Working
NO

EDIT2:

bool PrefixStringSet::contains(string s)
{
    NodePtr temp = root;
    for ( int i = 0; i < s.size(); i++)
    {
        if(temp->is_leaf())
        {
            return false;
        }
        if (temp !=root &&  temp->is_leaf())
        {
            return true;
        }
        if(temp->children[s[i] - '0'] == NULL)
        {
            return false;
        }
        temp = temp->children[s[i] - '0'];
    }
    return true;
}

2 个答案:

答案 0 :(得分:2)

PrefixStringSet::contains(string s)

    if(temp->children[s[i] - '0'] == NULL)
    {
        return false;
    }

不应直接返回false,而应检查temp是否包含任何非NULL子项。 也就是说,

    if(temp->children[s[i] - '0'] == NULL)
    {
        return (temp != root && temp->is_leaf());
    }

因为如果temp根本没有孩子,那么字符串s的前缀已经存在。
修改:检查temp != root以避免陷入空洞的行为。

TrieNode::hasAnyChild()的最有效实施取决于TrieNode::children的存储方式,您未在问题陈述中显示。如果你的trie只接受十进制数字,那么简单地通过所有的孩子应该足够好。

顺便提一句,在PrefixStringSet::insert(string s)

    int number = (int)s[i] - (int)'0';
    if(temp->children[number] == NULL)
    {
        temp->children[number] = new TrieNode;
        temp = temp->children[number];
    }

temp = temp->children[number];块结束后应移动行if,因为无论您是否创建新节点,都需要将temp向前移动一步。

答案 1 :(得分:2)

在标准Trie中,Node结构中应该有另一个字段来指示它是否表示单词。

bool PrefixStringSet::contains(string s)
{
    NodePtr temp = root;
    for ( int i = 0; i < s.size(); i++)
    {
        if(temp->isWord)
        {
            return false;
        }
        if(temp->children[s[i] - '0'] == NULL)
        {
            return false;
        }
        temp = temp->children[s[i] - '0'];
    }
    return true;
}

bool PrefixStringSet::insert(string s)
{
    if(contains(s) == true)
    {
        return false;
    }
    NodePtr temp = root;
    for (int i = 0; i < s.size(); i++)
    {
        int number = (int)s[i] - (int)'0';
        if(temp->children[number] == NULL)
        {
            temp->children[number] = new TrieNode;
        }
        temp = temp->children[number];
    }
    temp->isWord = true;
    return true;
}

但是,在您的问题中,只有 LEAF 节点表示现有单词,因为您不允许任何数字成为此Trie中其他数字的前缀。

因此,您可以通过迭代其子节点来检查节点是否是叶子节点,如@timaru所说。但它效率不高。