Initial commit
This commit is contained in:
2
P3/Makefile
Normal file
2
P3/Makefile
Normal file
@@ -0,0 +1,2 @@
|
||||
all: trietest.cpp Trie.cpp
|
||||
g++ -std=c++11 trietest.cpp Trie.cpp
|
||||
218
P3/Trie.cpp
Normal file
218
P3/Trie.cpp
Normal file
@@ -0,0 +1,218 @@
|
||||
#include "Trie.h"
|
||||
#include "illegal_exception.h"
|
||||
|
||||
Trie::Trie()
|
||||
{
|
||||
children = new Trie *[MAX_SLOTS];
|
||||
isEnd = false;
|
||||
for (int i = 0; i < MAX_SLOTS; i++)
|
||||
{
|
||||
children[i] = nullptr;
|
||||
}
|
||||
count = 0;
|
||||
}
|
||||
|
||||
Trie::~Trie()
|
||||
{
|
||||
delete[] children;
|
||||
}
|
||||
|
||||
/// @brief Wrapper function to recursively insert string s into the trie.
|
||||
/// @param s The string to insert into the trie.
|
||||
/// @return True if the string was inserted, false otherwise.
|
||||
bool Trie::Insert(std::string s)
|
||||
{
|
||||
// Wrapper function is needed to meet illegal_exception criteria without having O(n^2) runtime (recursive function).
|
||||
for (int i = 0; i < s.length(); i++)
|
||||
{
|
||||
if (s[i] < ASCII_FACTOR || s[i] > ASCII_UPPER)
|
||||
{
|
||||
throw illegal_exception();
|
||||
}
|
||||
}
|
||||
return PerformInsert(s);
|
||||
}
|
||||
|
||||
/// @brief Recursive function to insert string s into the trie.
|
||||
/// @param s The string to insert into the trie.
|
||||
/// @return True if the string was inserted successfully, false otherwise.
|
||||
bool Trie::PerformInsert(std::string s)
|
||||
{
|
||||
if (s.length() > 0) // Add until there are no more characters.
|
||||
{
|
||||
char c = s.at(0);
|
||||
// Create the new trie if it does not exist. This condition will never be true if the word cannot be inserted.
|
||||
if (children[c - ASCII_FACTOR] == nullptr)
|
||||
children[c - ASCII_FACTOR] = new Trie();
|
||||
|
||||
// Recursively insert, checking if the previous insertion was successful (if so, increment count).
|
||||
if (children[c - ASCII_FACTOR]->PerformInsert(s.substr(1)))
|
||||
{
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// If there are no characters and we have not reached a word end then the word is not already added.
|
||||
else if (!this->isEnd)
|
||||
{
|
||||
this->isEnd = true;
|
||||
count++;
|
||||
return true;
|
||||
}
|
||||
return false; // If the word is already in the trie, return false.
|
||||
}
|
||||
|
||||
/// @brief Wrapper function to remove an element from the trie.
|
||||
/// @param s The string to remove from the trie.
|
||||
/// @return True if the element was removed successfully, false otherwise.
|
||||
bool Trie::Remove(std::string s)
|
||||
{
|
||||
// Achieve O(n) runtime using wrapper function.
|
||||
for (int i = 0; i < s.length(); i++)
|
||||
{
|
||||
if (s[i] < ASCII_FACTOR || s[i] > ASCII_UPPER)
|
||||
{
|
||||
throw illegal_exception();
|
||||
}
|
||||
}
|
||||
return PerformRemove(s);
|
||||
}
|
||||
|
||||
/// @brief Recursively remove string s from the trie.
|
||||
/// @param s The string to remove from the trie.
|
||||
/// @return True if the string was removed, false otherwise.
|
||||
bool Trie::PerformRemove(std::string s)
|
||||
{
|
||||
if (s.length() > 0) // Remove until there are no more characters to remove.
|
||||
{
|
||||
// If we have reached a trie that does not have the correct child, we cannot remove the word.
|
||||
char c = s.at(0);
|
||||
if (children[c - ASCII_FACTOR] == nullptr)
|
||||
return false;
|
||||
|
||||
// Recursively remove the remaining bit of the word. Subtracting from the count if successful.
|
||||
if (children[c - ASCII_FACTOR]->PerformRemove(s.substr(1)))
|
||||
{
|
||||
count--;
|
||||
|
||||
// Free any child tries that have a count of 0. These are guaranteed to have no children.
|
||||
for (int i = 0; i < MAX_SLOTS; i++)
|
||||
{
|
||||
if (children[i] != nullptr && children[i]->IsEmpty())
|
||||
{
|
||||
delete children[i];
|
||||
children[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // If previous removes were successful, this remove is also successful.
|
||||
}
|
||||
}
|
||||
// If we have reached the end of the word, we can succesfully remove it from the trie.
|
||||
else if (this->isEnd)
|
||||
{
|
||||
this->isEnd = false;
|
||||
count--;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false; // When we are out of characters, but did not find a word end, cannot remove.
|
||||
}
|
||||
|
||||
/// @brief Determine if the trie is empty.
|
||||
/// @return True if the trie is empty, false otherwise.
|
||||
bool Trie::IsEmpty()
|
||||
{
|
||||
return count == 0;
|
||||
}
|
||||
|
||||
/// @brief Empty the trie.
|
||||
void Trie::Clear()
|
||||
{
|
||||
// We do not need to worry about dangling pointers, since everything is being deleted in order.
|
||||
for (int i = 0; i < MAX_SLOTS; i++)
|
||||
{
|
||||
if (children[i] != nullptr)
|
||||
children[i]->Clear(); // Recursively delete any non-null pointer children.
|
||||
}
|
||||
|
||||
delete this;
|
||||
}
|
||||
|
||||
/// @brief Perform a depth first search on the trie for string s, outputting the result by performing in place modification of the vector out.
|
||||
/// @param out
|
||||
/// @param s
|
||||
void Trie::DepthFirstSearch(std::vector<std::string> *out, std::string s)
|
||||
{
|
||||
if (isEnd)
|
||||
out->push_back(s); // If we have reached the end, put the word into the output
|
||||
|
||||
// Recursively search children nodes, in order from A-Z.
|
||||
for (int i = 0; i < MAX_SLOTS; i++)
|
||||
{
|
||||
if (children[i] != nullptr)
|
||||
children[i]->DepthFirstSearch(out, s + (char)(i + ASCII_FACTOR));
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Get the number of words in the trie.
|
||||
/// @return An integer of the number of words in the trie.
|
||||
int Trie::Size()
|
||||
{
|
||||
return count;
|
||||
}
|
||||
|
||||
/// @brief Wrapper function to count the number of suffixes for a given string s.
|
||||
/// @param s
|
||||
/// @return
|
||||
int Trie::CountSuffixes(std::string s)
|
||||
{
|
||||
for (int i = 0; i < s.length(); i++)
|
||||
{
|
||||
if (s[i] < ASCII_FACTOR || s[i] > ASCII_UPPER)
|
||||
{
|
||||
throw illegal_exception();
|
||||
}
|
||||
}
|
||||
return PerformCountSuffixes(s);
|
||||
}
|
||||
|
||||
|
||||
int Trie::PerformCountSuffixes(std::string s)
|
||||
{
|
||||
if (s.empty())
|
||||
return count;
|
||||
|
||||
char c = s.at(0);
|
||||
int index = c - ASCII_FACTOR;
|
||||
|
||||
if (children[index] != nullptr)
|
||||
return children[index]->PerformCountSuffixes(s.substr(1));
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Trie::SpellCheck(std::vector<std::string> *out, std::string check, std::string s)
|
||||
{
|
||||
if (check.empty() && isEnd)
|
||||
return true;
|
||||
else if (check.empty())
|
||||
return false;
|
||||
|
||||
char c = check.at(0);
|
||||
int index = c - ASCII_FACTOR;
|
||||
;
|
||||
if (children[index] != nullptr)
|
||||
{
|
||||
if (children[index]->SpellCheck(out, check.substr(1), s + c))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
children[index]->DepthFirstSearch(out, s + c);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
33
P3/Trie.h
Normal file
33
P3/Trie.h
Normal file
@@ -0,0 +1,33 @@
|
||||
#ifndef TRIE_H
|
||||
#define TRIE_H
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
class Trie
|
||||
{
|
||||
public:
|
||||
Trie();
|
||||
~Trie();
|
||||
bool Insert(std::string s);
|
||||
bool Remove(std::string s);
|
||||
void DepthFirstSearch(std::vector<std::string> *out, std::string s);
|
||||
bool IsEmpty();
|
||||
void Clear();
|
||||
int Size();
|
||||
int CountSuffixes(std::string s);
|
||||
bool SpellCheck(std::vector<std::string> *out, std::string check, std::string s);
|
||||
|
||||
private:
|
||||
const int MAX_SLOTS = 26;
|
||||
const int ASCII_FACTOR = 65;
|
||||
const int ASCII_UPPER = 90;
|
||||
int count;
|
||||
bool isEnd;
|
||||
Trie **children;
|
||||
|
||||
bool PerformInsert(std::string s);
|
||||
bool PerformRemove(std::string s);
|
||||
int PerformCountSuffixes(std::string s);
|
||||
};
|
||||
#endif
|
||||
8
P3/illegal_exception.h
Normal file
8
P3/illegal_exception.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef ILLEGAL_EXCEPTION_H
|
||||
#define ILLEGAL_EXCEPTION_H
|
||||
|
||||
#include <exception>
|
||||
|
||||
class illegal_exception : std::exception {};
|
||||
|
||||
#endif
|
||||
153
P3/trietest.cpp
Normal file
153
P3/trietest.cpp
Normal file
@@ -0,0 +1,153 @@
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include "Trie.h"
|
||||
#include <vector>
|
||||
#include "illegal_exception.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
const string FILE_NAME = "corpus.txt";
|
||||
|
||||
void PrintVector(vector<string> *out)
|
||||
{
|
||||
for (int i = 0; i < out->size(); i++)
|
||||
{
|
||||
cout << (*out)[i];
|
||||
if (i < out->size() - 1)
|
||||
cout << " ";
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
string cmd;
|
||||
string addWord;
|
||||
ifstream fin(FILE_NAME);
|
||||
Trie *trie = new Trie();
|
||||
|
||||
while (cin >> cmd)
|
||||
{
|
||||
if (cmd == "load")
|
||||
{
|
||||
if (!fin.is_open())
|
||||
fin.open(FILE_NAME);
|
||||
|
||||
while (fin >> addWord)
|
||||
{
|
||||
trie->Insert(addWord);
|
||||
}
|
||||
|
||||
fin.close();
|
||||
cout << "success" << endl;
|
||||
}
|
||||
else if (cmd == "i")
|
||||
{
|
||||
string word;
|
||||
cin >> word;
|
||||
try
|
||||
{
|
||||
if (trie->Insert(word))
|
||||
cout << "success" << endl;
|
||||
else
|
||||
cout << "failure" << endl;
|
||||
}
|
||||
catch (illegal_exception e)
|
||||
{
|
||||
cout << "illegal argument" << endl;
|
||||
}
|
||||
}
|
||||
else if (cmd == "e")
|
||||
{
|
||||
string word;
|
||||
cin >> word;
|
||||
|
||||
try
|
||||
{
|
||||
if (trie->Remove(word))
|
||||
cout << "success" << endl;
|
||||
else
|
||||
cout << "failure" << endl;
|
||||
}
|
||||
catch (illegal_exception e)
|
||||
{
|
||||
cout << "illegal argument" << endl;
|
||||
}
|
||||
}
|
||||
else if (cmd == "clear")
|
||||
{
|
||||
trie->Clear();
|
||||
trie = new Trie();
|
||||
cout << "success" << endl;
|
||||
}
|
||||
else if (cmd == "size")
|
||||
{
|
||||
cout << "number of words is " << trie->Size() << endl;
|
||||
}
|
||||
else if (cmd == "empty")
|
||||
{
|
||||
if (trie->IsEmpty())
|
||||
cout << "empty 1" << endl;
|
||||
else
|
||||
cout << "empty 0" << endl;
|
||||
}
|
||||
else if (cmd == "spellcheck")
|
||||
{
|
||||
string word;
|
||||
cin >> word;
|
||||
|
||||
vector<string> out;
|
||||
|
||||
bool result = trie->SpellCheck(&out, word, "");
|
||||
|
||||
if (out.empty() && result)
|
||||
{
|
||||
cout << "correct" << endl;
|
||||
}
|
||||
else if (!result)
|
||||
{
|
||||
cout << endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
PrintVector(&out);
|
||||
cout << endl;
|
||||
}
|
||||
}
|
||||
else if (cmd == "p")
|
||||
{
|
||||
vector<string> out;
|
||||
trie->DepthFirstSearch(&out, "");
|
||||
|
||||
PrintVector(&out);
|
||||
|
||||
if (out.size() > 0)
|
||||
cout << endl;
|
||||
|
||||
}
|
||||
|
||||
else if (cmd == "c")
|
||||
{
|
||||
string prefix;
|
||||
cin >> prefix;
|
||||
|
||||
try
|
||||
{
|
||||
int count = trie->CountSuffixes(prefix);
|
||||
|
||||
if (count != -1 && count != 0)
|
||||
cout << "count is " << count << endl;
|
||||
else
|
||||
cout << "not found" << endl;
|
||||
}
|
||||
catch (illegal_exception e)
|
||||
{
|
||||
cout << "illegal argument" << endl;
|
||||
}
|
||||
}
|
||||
else if (cmd == "exit")
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
trie->Clear();
|
||||
}
|
||||
Reference in New Issue
Block a user