I implemented a Trie in C++11, but I am not sure if my usage of struct
and std::unique_ptr
, and std::unordered_map
are correct and idiomatic. Therefore, I hope someone could provide constructive criticism on my code.
My Trie implementation has three simple methods:
void Trie::Insert(const std::string& word);
bool Trie::StartsWithPrefix(const std::string& prefix);
bool Trie::IsACompleteWord(const std::string& word);
Code
// tries.h
#ifndef TRIE_H_
#define TRIE_H_
#include <vector>
#include <string>
#include <unordered_map>
class Trie {
public:
// Trie Constructor
Trie();
explicit Trie(std::vector<std::string>);
// Trie Operations
void Insert(const std::string& word);
bool StartsWithPrefix(const std::string& prefix);
bool IsACompleteWord(const std::string& word);
private:
struct Node {
bool end_of_word;
std::unordered_map<char, std::unique_ptr<Node>> children;
Node(): end_of_word(false) {}
};
std::unique_ptr<Node> root;
};
/// ===========================
/// Tries Implementation
/// ===========================
Trie::Trie() {
root = std::unique_ptr<Node>(new Node());
}
Trie::Trie(std::vector<std::string> words) {
root = std::unique_ptr<Node>(new Node());
for (auto w : words)
Insert(w);
}
void Trie::Insert(const std::string& word) {
if (word.empty()) return;
auto it = root.get();
for (const char & key : word) {
int found = it->children.count(key);
if (!found)
it->children.emplace(key, std::unique_ptr<Node>(new Node()));
it = it->children[key].get();
}
it->end_of_word = true;
}
bool Trie::StartsWithPrefix(const std::string& prefix) {
auto it = root.get();
for (const char & key : prefix) {
auto found = it->children.count(key);
if (!found)
return false;
it = it->children[key].get();
}
return true;
}
bool Trie::IsACompleteWord(const std::string& word) {
auto it = root.get();
for (const char & key : word) {
auto found = it->children.count(key);
if (!found)
return false;
it = it->children[key].get();
}
return (it->end_of_word) ? true : false;
}
#endif // TRIE_H_
Test
#define CATCH_CONFIG_MAIN
#include "catch2/catch.hpp"
#include "trie.h"
SCENARIO("Trie operations", "[trie]") {
GIVEN("A Trie Data Structure") {
Trie trie({"hello", "test"});
REQUIRE(trie.StartsWithPrefix("hell") == true);
REQUIRE(trie.StartsWithPrefix("helli") == false);
REQUIRE(trie.StartsWithPrefix("test") == true);
REQUIRE(trie.StartsWithPrefix("ab") == false);
trie.Insert("ab");
REQUIRE(trie.StartsWithPrefix("ab") == true);
REQUIRE(trie.IsACompleteWord("ab") == true);
REQUIRE(trie.IsACompleteWord("hell") == false);
}
}