Counting vowels in a book - c++

I'm trying to count vowels in a book "War and Peace" by Lev Tolstoi with 4 different methods:
Using Count_if/find
Using Count_if/for
for/find
4.for/for
The programm also calculates time it takes for every method to get the number of vowels. I'm using a russian version of the book as a reference so all the vowels are taken from cyrillic alphabet. Here is the code:
#include <chrono>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <Windows.h>
#include <string>
#include <fstream>
#include <iterator>
class Timer
{
private:
using clock_t = std::chrono::high_resolution_clock;
using second_t = std::chrono::duration<double, std::ratio<1> >;
std::string m_name;
std::chrono::time_point<clock_t> m_beg;
double elapsed() const
{
return std::chrono::duration_cast<second_t>(clock_t::now()
- m_beg).count();
}
public:
Timer() : m_beg(clock_t::now()) { }
Timer(std::string name) : m_name(name), m_beg(clock_t::now()) { }
void start(std::string name) {
m_name = name;
m_beg = clock_t::now();
}
void print() const {
std::cout << m_name << ":\t" << elapsed() * 1000 << " ms" << '\n';
}
};
const std::string vowels = "аеёиоуыэюяАЕЁИОУЫЭЮЯ";
bool containVowel(const std::string& s, const char& a)
{
for (size_t i = 0; i < s.size(); i++)
{
if (a == s[i])
{
return true;
}
return false;
}
}
void ForFor(std::ifstream& ifs, std::string& ww)
{
size_t count = 0;
Timer t1("for for");
while (ifs >> ww)
{
for (size_t i = 0; i < ww.size(); i++)
{
if (containVowel(vowels, ww[i]))
{
count++;
}
}
}
t1.print();
std::cout << count << std::endl;
}
//bool findVowel(char c)
//{
// return vowels.find(c) != std::string::npos;
//}
void CountIfFind(std::ifstream& ifs, std::string& ww) // not sure what is the way to cout count here...
{
Timer t("count_if/find");
while (ifs >> ww)
{
size_t count = std::count_if(ww.begin(), ww.end(), [&](char c) {return vowels.find(c) != std::string::npos; });
}
t.print();
}
void CountIfFor(std::ifstream& ifs, std::string& ww) // not sure what is the way to cout count here...
{
Timer t("count_if/for");
while (ifs >> ww)
{
for (size_t i = 0; i < vowels.size(); i++)
{
auto count = std::count_if(ww.begin(), ww.end(), [&](char c) {return c == vowels[i]; });
}
}
t.print();
}
void ForFind(std::ifstream& ifs, std::string& ww)
{
char c{};
int count = 0;
Timer t("for/find");
while (ifs >> ww)
{
for (size_t i = 0; i < ww.size(); i++)
{
if (vowels.find(c) != std::string::npos)
{
count++;
}
}
}
t.print();
std::cout << count << std::endl;
}
int main()
{
setlocale(LC_ALL, "ru");
SetConsoleCP(1251);
SetConsoleOutputCP(1251);
std::ifstream ifs;
ifs.open("Толстой Лев. Война и мир. Книга 1 - royallib.ru.txt");
if (ifs.is_open())
{
std::string ww;
ForFor(ifs, ww);
CountIfFind(ifs,ww);
CountIfFor(ifs,ww);
ForFind(ifs, ww);
ifs.close();
}
else
{
std::cout << "Can't open the file!" << std::endl;
}
}
Function ForFor works just fine but 3 other don't work (they don't show count but show time though). I'm guessing there is a problem with parsing the file, though I'm not sure because of my inexperience.
Will be hoping for your help!) Thank you all, in advance.
EDIT:Ok so now I'm sure the issue is in while(ifs>>ww). ForFor was the first function in the main so it worked, I tried commenting it and the next one CountIfFind started working. But when I delete while in every function and use it in main like: while(ifs>>ww) {ForFor(ww); CountIfFind(ww); CountIfFor(ww); ForFind(ww);} It doesn't work at all... How do I fix it?

So here is the correct way to do it:
class Timer
{
private:
using clock_t = std::chrono::high_resolution_clock;
using second_t = std::chrono::duration<double, std::ratio<1> >;
std::string m_name;
std::chrono::time_point<clock_t> m_beg;
double elapsed() const
{
return std::chrono::duration_cast<second_t>(clock_t::now()
- m_beg).count();
}
public:
Timer() : m_beg(clock_t::now()) { }
Timer(std::string name) : m_name(name), m_beg(clock_t::now()) { }
void start(std::string name) {
m_name = name;
m_beg = clock_t::now();
}
void print() const {
std::cout << m_name << ":\t" << elapsed() * 1000 << " ms" << '\n';
}
};
const std::string vowels = "аеёиоуыэюяАЕЁИОУЫЭЮЯ";
size_t ForFor(std::string& ww)
{
size_t count = 0;
Timer t1("for for");
for(const auto& ch : ww)
{
for (const auto& vow : vowels)
{
if (ch == vow)
{
++count;
break;
}
}
}
t1.print();
return count;
}
size_t CountIfFind(std::string& ww)
{
Timer t("count_if/find");
size_t count = std::count_if(ww.begin(), ww.end(), [ & ](char c) {return vowels.find(c) != std::string::npos; });
t.print();
return count;
}
size_t CountIfFor(std::string& ww)
{
Timer t("count_if/for");
size_t count = std::count_if(ww.begin(), ww.end(), [&](const char& c1)
{
for (const auto& ch : vowels)
{
if (c1 == ch)
{
return true;
}
}
return false;
});
t.print();
return count;
}
size_t ForFind(std::string& ww)
{
char c{};
size_t count = 0;
Timer t("for/find");
for (const auto& ch :ww)
{
if (vowels.find(ch) != std::string::npos)
{
++count;
}
}
t.print();
return count;
}
int main()
{SetConsoleCP(1251);
SetConsoleOutputCP(1251);
std::ifstream file("Толстой Лев. Война и мир. Книга 1 - royallib.ru.txt");
file.seekg(0, std::ios::end);
size_t size = file.tellg();
file.seekg(0);
std::string s(size, ' ');
file.read(&s[0], size);
std::cout << CountIfFind(s) << std::endl;
std::cout << ForFor(s) << std::endl;
std::cout << ForFind(s) << std::endl;
std::cout << CountIfFor(s) << std:: endl;
}

Related

Overloading Operator and vector STL problems

I have a task: Implementing 60.000 English words from EnglishWords.txt, then Sorting it and Searching.
I have done the Sorting and Linear Search using custom MergeSort and find_if STL but when i tried to use other vector STL like upper_bound, lower_bound, binary_search it cause some problems below:
If the lower_bound function run, it does not return the same "Index" with "searchmanually" function.
Can not use "MatchString" (My overload operator) for lower_bound and binary_search ST or other vector STL and return C2672 and C2893 code.
Also, can some one give me some advices on "sorting" base on alphabetical.
My full code is on https://onlinegdb.com/l4pfS9pYJ, please click on "Fork this" to edit the code.
Some additional requirements and notions.
I'm new to OOP so show me some advices to improve my code writing skills.
Do not use STL sort(), write your own.
Must put all sorting, searching and working function to FastDictionary.
Below is my overload operator and the function that has problem.
void searchmanually(vector<Dictionary> list, string value)
{
vector<Dictionary>::iterator it;
it = find_if(list.begin(), list.end(), FastDictionary::MatchString(value));
if (it != list.end())
{
auto idx = distance(list.begin(), it);
cout << "Index = " << idx << endl;
}
else
{
cout << "Can not find the value !." << endl;
}
}
void binary_search_find_index(vector<Dictionary> list, string value)
{
vector<Dictionary>::iterator it1;
it1 = lower_bound(list.begin(), list.end(), FastDictionary::MatchString(value));
if (it1 != list.end())
{
auto idx1 = distance(list.begin(), it1);
cout << "Index = " << idx1 << endl;
}
else
{
cout << "Can not find the value !." << endl;
}
}
struct MatchString
{
private:
const std::string& s_;
public:
MatchString(const std::string& s) : s_(s) {}
bool operator()(const Dictionary& obj) const
{
return obj._word == s_;
}
friend bool operator<(const Dictionary& obj, const MatchString &str)
{
return obj._word < str.s_;
}
friend bool operator>(const Dictionary& obj, const MatchString &str)
{
return obj._word > str.s_;
}
};
Because i think that my "errors" are kinda chained so i try to described the error as much detail as possible.
Many thanks.
First The problem is that at your given link you have named your input file incorrectly. Note carefully your input file name in the main.cpp file is EnglishWord.txt while your actual input file name is EnglistWord.txt. Note the t at the end of the file name.
Second you should replace while (reader >> word) with:
while (std::getline(reader, word))
as i have done in the below correct example:
#include<iostream>
#include<string>
#include<vector>
#include<fstream>
#include<sstream>
#include<algorithm>
using namespace std;
class Dictionary
{
public:
string _word;
public:
string word() { return _word; }
void getword(string value) { _word=value; }
string display()
{
stringstream writer;
writer << _word << " ";
return writer.str();
}
};
class FastDictionary : public Dictionary
{
public:
void merge(std::vector<Dictionary>& list, int start, int middle, int end)
{
std::vector<Dictionary> left_vector(middle - start + 1);
std::vector<Dictionary> right_vector(end - middle);
for (int i = 0; i < left_vector.size(); ++i)
left_vector[i] = list[start + i];
for (int i = 0; i < right_vector.size(); ++i)
right_vector[i] = list[middle + 1 + i];
int left_value = 0, right_value = 0;
int currentIndex = start;
while (left_value < left_vector.size() && right_value < right_vector.size()) {
if (left_vector[left_value]._word.size() <= right_vector[right_value]._word.size()) {
list[currentIndex] = left_vector[left_value];
left_value++;
}
else {
list[currentIndex] = right_vector[right_value];
right_value++;
}
currentIndex++;
}
while (left_value < left_vector.size()) list[currentIndex++] = left_vector[left_value++];
while (right_value < right_vector.size()) list[currentIndex++] = right_vector[right_value++];
}
void mergeSort(std::vector<Dictionary>& list, int start, int end) {
if (start < end) {
int middle = (start + end) / 2;
mergeSort(list, start, middle);
mergeSort(list, middle + 1, end);
merge(list, start, middle, end);
}
}
public:
void searchmanually(vector<Dictionary> list, string value)
{
vector<Dictionary>::iterator it;
it = find_if(list.begin(), list.end(), FastDictionary::MatchString(value));
if (it != list.end())
{
auto idx = distance(list.begin(), it);
cout << "Index = " << idx << endl;
}
else
{
cout << "Can not find the value !." << endl;
}
}
void binary_search_find_index(vector<Dictionary> list, string value)
{
vector<Dictionary>::iterator it1;
it1 = lower_bound(list.begin(), list.end(), FastDictionary::MatchString(value));
if (it1 != list.end())
{
auto idx1 = distance(list.begin(), it1);
cout << "Index = " << idx1 << endl;
}
else
{
cout << "Can not find the value !." << endl;
}
}
struct MatchString
{
private:
const std::string& s_;
public:
MatchString(const std::string& s) : s_(s) {}
bool operator()(const Dictionary& obj) const
{
return obj._word == s_;
}
friend bool operator<(const Dictionary& obj, const MatchString &str)
{
return obj._word < str.s_;
}
friend bool operator>(const Dictionary& obj, const MatchString &str)
{
return obj._word > str.s_;
}
};
};
void readfile(vector<Dictionary>& list)
{
ifstream reader("EnglishWord.txt");
string word;
//reader.open(, ios::in);//no need for this
if(reader)//check the state
{
while (std::getline(reader, word))//use getline
{
std::cout<<word<<std::endl;
Dictionary newList;
newList.getword(word);
list.push_back(newList);
}
}
else
{
std::cout<<"file cannot be opened"<<std::endl;
}
}
void displayvector(vector<Dictionary>& list)
{
unsigned int size = list.size();
for (int i = 0; i < size; i++)
{
cout << list[i].display();
}
}
int main()
{
vector<Dictionary>list;
FastDictionary fd;
readfile(list);
fd.mergeSort(list, 0, list.size() - 1);
displayvector(list);
cout << endl;
cout << endl;
fd.binary_search_find_index(list, "decidedly");
cout << endl;
fd.searchmanually(list, "decidedly");
cout << endl;
return 0;
}
The output of this corrected/modified example can be seen here.

VS Code not showing local variables at all

I am using VS code for coding in C++. The problem arises when I try to debug a code and set a breakpoint. The local variables pane doesn't show any variables at all. Sometimes it does show some variables but not all of them.
Also when I try to close the debugger and click on the stop button, it does not stop. It requires me to click on it multiple times, which I think means, that multiple debuggers are opened or something like that.
To reproduce this problem, save this text as input_static.txt.
T1 1 2 5
T2 2 4
T3 2 3
T4 1 2 4
T5 1 3
T6 2 3
T7 1 3
T8 1 2 3 5
T9 1 2 3
And debug the following code by setting a breakpoint at line number 201.
#include <bits/stdc++.h>
using namespace std;
ifstream fin;
ofstream fout;
typedef struct fptnode
{
int item, count;
fptnode *next;
map<int, fptnode *> children;
fptnode *parent;
fptnode(int item, int count, fptnode *parent)
{
this->item = item;
this->count = count;
this->parent = parent;
}
} * FPTPTR;
map<int, int> frequency;
bool isMoreFrequent(int a, int b)
{
if (frequency[a] == frequency[b])
return a < b;
return frequency[a] > frequency[b];
}
class FPTREE
{
public:
FPTPTR root;
map<int, list<FPTPTR>> headers;
// map<int, int> frequency;
FPTREE()
{
this->root = new fptnode(-1, 0, NULL);
}
// class isMoreFrequent
// {
// public:
// FPTREE *T;
// isMoreFrequent(FPTREE *T)
// {
// this->T = T;
// }
// bool operator()(int item1, int item2)
// {
// return T->frequency[item1] > T->frequency[item2];
// }
// };
FPTPTR getNewNode(int item, int count, fptnode *parent)
{
FPTPTR T = new fptnode(item, count, parent);
this->headers[item].push_back(T);
return T;
}
void add(vector<int> &transaction)
{
stack<int> S;
std::sort(transaction.begin(), transaction.end(), isMoreFrequent);
for (int i = transaction.size() - 1; i >= 0; i--)
{
S.push(transaction[i]);
}
insert(root, S);
}
int insert(FPTPTR T, stack<int> &S)
{
T->count++;
if (S.empty())
return 0;
int top = S.top();
S.pop();
if (T->children[top] == NULL)
{
T->children[top] = getNewNode(top, 0, T);
}
insert(T->children[top], S);
return 0;
}
void printPreOrder(ofstream &fout)
{
printPreOrder(fout, this->root);
}
void printPreOrder(ofstream &fout, FPTPTR T)
{
if (T)
{
fout << "[" << T->item << ", " << T->count << "]" << ' ';
for (auto p : T->children)
{
printPreOrder(fout, p.second);
}
}
}
void printTree(ofstream &fout)
{
printTree(fout, this->root);
}
void printTree(ofstream &fout, FPTPTR T, int level = 0)
{
if (T)
{
for (int i = 0; i < level; i++)
fout << "\t";
fout << "[" << T->item << ", " << T->count << "]" << endl;
for (auto p : T->children)
{
printTree(fout, p.second, level + 1);
}
}
}
void generatePath(FPTPTR node, vector<int> &path)
{
if (node && node->item >= 0)
{
path.push_back(node->item);
generatePath(node->parent, path);
}
}
FPTREE newTree(int item)
{
list<FPTPTR> &nodes = this->headers[item];
vector<int> patternBase;
FPTREE f;
for (auto node : nodes)
{
patternBase.clear();
generatePath(node->parent, patternBase);
for (int j = 0; j < node->count; ++j)
f.add(patternBase);
}
return f;
}
int clear()
{
return this->clear(this->root);
}
int clear(FPTPTR T)
{
for (auto p : T->children)
{
clear(p.second);
}
return 0;
}
bool isEmpty()
{
// return this->root->count == 0;
return this->root->children.empty();
}
} F;
ofstream tempout;
map<set<int>, int> mine(FPTREE f, int r = -1)
{
map<set<int>, int> M;
if (!f.isEmpty())
{
// if (f.root->children.empty())
// M[{}] += f.root->count;
tempout << "\nOn removing " << r << ":\n";
f.printTree(tempout);
for (auto p : frequency)
{
FPTREE subF = f.newTree(p.first);
map<set<int>, int> m = mine(subF, p.first);
for (auto q : m)
{
auto itemset = q.first;
itemset.insert(p.first);
M[itemset] += q.second;
}
subF.clear();
}
return M;
}
// tempout << "\nTerminated.\n";
return {};
}
int main(int argc, char const *argv[])
{
fin.open("input_static.txt");
fout.open("output_static.txt");
tempout.open("temp");
string str, s;
while (fin >> s)
{
if (s.front() != 'T')
{
frequency[stoi(s)]++;
}
}
vector<int> transaction;
stringstream st;
fin.clear();
fin.seekg(0);
while (std::getline(fin, str))
{
st.clear();
st.str(str);
transaction.clear();
while (st >> s)
{
if (s.front() != 'T')
{
transaction.push_back(stoi(s));
}
}
F.add(transaction);
}
fout << "Preorder:\n";
F.printPreOrder(fout);
fout << endl
<< endl;
fout << "Tree in directory form:\n";
F.printTree(fout);
// printPrefixes(5);
map<set<int>, int> frequentItemsets = mine(F);
fout << endl;
for (auto p : frequentItemsets)
{
fout << "Frequency=" << p.second << "\t";
for (int item : p.first)
{
fout << item << ' ';
}
fout << endl;
}
// for (int i = 1; i <= 5; ++i)
// {
// fout << i << ":\n";
// FPTREE f = F.newTree(i);
// f.printTree();
// }
// F.newTree(1).newTree(2).printTree(fout);
return 0;
}
If it helps this is a program to generate and mine an FP-tree to find frequent itemsets in a transactional database.

Exception thrown: read access violation. **_Right_data** was 0x4. C++

I tried everything and looked everywhere but I keep getting
Exception thrown: read access violation.
**_Right_data was 0x4.**
What is wrong with the code? I am not very good with C++ and don't like it at all but working on this school project and trying to figure out why I get the exception. Any help is appreciated
#include "Roster.h"
#include "Student.h"
#include "NetworkStudent.h"
#include "SecurityStudent.h"
#include "SoftwareStudent.h"
#include <iostream>
#include <string>
#include<vector>
#include<sstream>
#include<regex>
// Separates Data on basis of ,
template <class Container>
void splitString(const std::string& str, Container& cont)
{
char delim = ',';
std::stringstream ss(str);
std::string token;
while (std::getline(ss, token, delim)) {
cont.push_back(token);
}
}
// Checks and returns if email is valid or not
bool Email(std::string email)
{
const std::regex pattern("(\\w+)(\\.|_)?(\\w*)#(\\w+)(\\.(\\w+))+");
return regex_match(email, pattern);
}
// Main Function
int main()
{
Roster classRoster;
// Data Array
const std::string studentData[] = { "A1,John,Smith,John1989#gm ail.com,20,30,35,40,SECURITY",
"A2,Suzan,Erickson,Erickson_1990#gmailcom,19,50,30,40,NETWORK",
"A3,Jack,Napoli,The_lawyer99yahoo.com,19,20,40,33,SOFTWARE",
"A4,Erin,Black,Erin.black#comcast.net,22,50,58,40,SECURITY",
};
for (unsigned int i = 0;i < 5;i++)
{
std::vector<std::string> words;
std::string s = studentData[i];
// Splits Input
splitString(s, words);
// if Student belongs to Security
if (words.at(8) == "SECURITY")
{
int a[3] = { stoi(words.at(5)),stoi(words.at(6)),stoi(words.at(7)) };
classRoster.classRosterArray[i] = new SecurityStudent(words.at(0), words.at(1), words.at(2), words.at(3), stoi(words.at(4)), a, SECURITY);
}
// IF Student Belongs to Software
else if (words.at(8) == "SOFTWARE")
{
int a[3] = { stoi(words.at(5)),stoi(words.at(6)),stoi(words.at(7)) };
classRoster.classRosterArray[i]=new SoftwareStudent(words.at(0), words.at(1), words.at(2), words.at(3), stoi(words.at(4)), a, SOFTWARE);
}
// If Student Belongs to Network
else if (words.at(8) == "NETWORK")
{
int a[3] = { stoi(words.at(5)),stoi(words.at(6)),stoi(words.at(7)) };
classRoster.classRosterArray[i] = new NetworkStudent(words.at(0), words.at(1), words.at(2), words.at(3), stoi(words.at(4)), a, NETWORK);
}
}
std::cout << "\n---------Print All Student's Data------------\n";
classRoster.printAll();
std::cout << "\n---------------------------------------------\n";
std::cout << "Invalid Emails\n";
classRoster.printInvalidEmails();
std::cout << "\n--------------Days in Course------------------\n";
classRoster.printDaysInCourse("A2");
std::cout << "\n--------------By Degree Program------------------";
classRoster.printByDegreeProgram(3);
std::cout << "\n--------------Removes A3------------------\n";
classRoster.remove("A3");
classRoster.remove("A3");
return 0;
}
// Adds Student to Roster
void Roster::add(std::string studentID, std::string firstName, std::string lastName, std::string emailAddress, int age, int daysInCourse1, int daysInCourse2, int daysInCourse3, degree d)
{
if (d == SOFTWARE)
{
delete classRosterArray[4];
int a[3] = { daysInCourse1,daysInCourse2,daysInCourse3 };
classRosterArray[4] = new SoftwareStudent(studentID, firstName, lastName, emailAddress, age,a, d);
}
else if (d == NETWORK)
{
delete classRosterArray[4];
int a[3] = { daysInCourse1,daysInCourse2,daysInCourse3 };
classRosterArray[4] = new NetworkStudent(studentID, firstName, lastName, emailAddress, age, a, d);
}
else if (d == SECURITY)
{
delete classRosterArray[4];
int a[3] = { daysInCourse1,daysInCourse2,daysInCourse3 };
classRosterArray[4] = new SecurityStudent(studentID, firstName, lastName, emailAddress, age, a, d);
}
}
// Removes Student
void Roster::remove(std::string studentID)
{
for (unsigned i = 0;i < 5;i++)
{
if (classRosterArray[i]->getStudentID() == studentID){
std::cout << "STUDENT REMOVED " << classRosterArray[i]->getStudentID()<<"\n";
classRosterArray[i] = NULL;
}
}
std::cout << "Student ID Does not Exist \n";
}
// Prints All Data Of Array
void Roster::printAll()
{
for (unsigned i = 0;i < 5;i++)
{
std::cout << i + 1 << "\t";
classRosterArray[i]->print();
std::cout << "\n";
}
}
// Prints Average Days in Course for a specific Student
void Roster::printDaysInCourse(std::string studentID)
{
int sum = 0;
for (unsigned i = 0;i < 5;i++)
{
if (classRosterArray[i]->getStudentID() == studentID)
{
int *p = classRosterArray[i]->getStudentDaysofCourses();
for (unsigned int j = 0;j < 3;j++)
sum += p[j];
delete[]p;
break;
}
}
std::cout << sum / 3.0;
}
// Prints Invalid Emails
void Roster::printInvalidEmails()
{
for (unsigned i = 0;i < 5;i++)
{
std::string email = classRosterArray[i]->getStudentEmail();
if (!Email(email))
{
std::cout << classRosterArray[i]->getStudentEmail();
//classRosterArray[i]->print();
std::cout << "\n";
}
}
}
// Prints By Degree Program
void Roster::printByDegreeProgram(int degreeProgram)
{
for (unsigned i = 0;i < 5;i++)
{
if (classRosterArray[i]->getDegreeProgram()==degreeProgram)
classRosterArray[i]->print();
std::cout << "\n";
}
}
// Destructor
Roster::~Roster()
{
for (unsigned i = 0; i < 5; i++)
{
if (classRosterArray[i]!=NULL)
delete classRosterArray[i];
}
}
Figured it out!
This part was causing the error
// Removes Student
void Roster::remove(std::string studentID)
{
for (unsigned i = 0;i < 5;i++)
{
if (classRosterArray[i]->getStudentID() == studentID){
std::cout << "STUDENT REMOVED " << classRosterArray[i]->getStudentID()<<"\n";
classRosterArray[i] = NULL;
}
}
std::cout << "Student ID Does not Exist \n";
}
Changed to
// Removes Student
void Roster::remove(std::string studentID)
{
for (unsigned i = 0; i < 5; i++)
{
if (classRosterArray[i] != NULL && classRosterArray[i]->getStudentID() == studentID) {
std::cout << "STUDENT REMOVED " << classRosterArray[i]->getStudentID() << "\n";
delete classRosterArray[i];
classRosterArray[i] = NULL;
return;
}
}
std::cout << "Student ID Does not Exist \n";
}

Printing from Trie

I have built a trie in C++ designed to hold words of sentences. Each sentence will have a weight which determines the order in which they should be output. I have several recursive functions that call other recursive functions, and the dilemma I am facing is that I want to print my list only once.
Basically my get function calls the printFromNode function which creates the vector of pairs p that I want to sort and print. If someone could point me in the right direction in how to do that it would be much appreciated.
Code:
Trie.cpp:
//#include "Trie.h"
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <string>
#include <vector>
#include <sstream>
#include <stack>
using namespace std;
class Node
{
private:
string word = "";
bool endOfSentence = false;
int weight = -1;
public:
vector<Node> children = {};
Node() {
this->setWord("");
}
Node(string s){
this->setWord(s);
}
string getWord(){
return this->word;
}
void setWord(string s) {
this->word = s;
}
void setEOS(){
this->endOfSentence = true;
}
void setWeight(int weight){
this->weight = weight;
}
int getWeight() {
return this->weight;
}
};
class Trie
{
public:
Node root;
void add(vector<string> phrase, int weight, Node* n){
Node* current = n;
int w = weight;
int found = -1;
for (int i = 0; i < current->children.size(); i++) {
if (phrase[0] == current->children[i].getWord()) {
found = i;
}
}
if (found > -1) {
current = &current->children[found];
phrase.erase(phrase.begin());
add(phrase, w, current);
}
else {
addPhrase(phrase, w, current);
}
}
void addPhrase(vector<string> phrase, int weight, Node* n) {
Node* current = n;
for (int i = 0; i < phrase.size(); i++) {
Node temp = *new Node(phrase[i]);
current->children.push_back(temp);
current = &current->children.back();
if (i == phrase.size() - 1) {
current->setEOS();
current->setWeight(weight);
}
}
}
void get(vector<string> search) {
Node* current = &this->root;
get(search, current);
}
void get(vector<string> search, Node* n) {
Node* current = n;
int found = -1;
//test search size
if (search.size() == 0) {
cout << "Please enter a valid search" << endl;
}
for (int i = 0; i < current->children.size(); i++) {
if (search[0] == current->children[i].getWord()) {
found = i;
}
}
if (found > -1 && search.size() == 1) {
current = &current->children[found];
printFromNode(*current);
maxNode(*current);
}
else if (found > -1 && search.size() != 1) {
current = &current->children[found];
search.erase(search.begin());
get(search, current);
}
else {
cout << "Not Found" << endl;
}
}
void printOutput(vector<pair<int,string>> p){
sort(p.begin(), p.end());
cout << p.size() << endl;
for (int i = 0; i < p.size(); i++) {
cout << p[i].second << " " << endl;
}
}
void printFromNode(Node n) {
vector<string> phrase = {};
vector <pair < int, string>> final = {};
printFromNode(n,phrase,final);
}
void printFromNode(Node n, vector<string> &v, vector<pair<int,string>> &p) {
string output;
if (n.getWord() == "") {
return;
}
for (int i = 0; i < n.children.size(); i++) {
if (n.children[i].getWeight() > 0) {
for (int i = 0; i < v.size(); i++)
{
output.append(v[i] + " ");
}
output.append(n.children[i].getWord());
p.push_back(make_pair(n.children[i].getWeight(), output));
}
v.push_back(n.children[i].getWord());
printFromNode(n.children[i], v, p);
v.pop_back();
sort(p.begin(), p.end());
}
return;
}
void maxNode(Node n) {
int max = 0;
int index = 0;
int temp = 0;
for (int i = 0; i < n.children.size(); i++) {
temp = n.children[i].children.size();
if (temp > max) {
max = temp;
index = i;
}
}
cout << n.children[index].getWord() << " " << max << endl;
}
};
Main.cpp:
#include "Trie.cpp"
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
using namespace std;
int main(int argc, char* argv[]) {
// Initialize trie up here
Trie myTrie = *new Trie();
// parse input lines until I find newline
for(string line; getline(cin, line) && line.compare(""); ) {
stringstream ss(line);
string string_weight;
ss >> string_weight;
int weight = stoi(string_weight);
// I am just going to put these words into a vector
// you probably want to put them in your trie
vector<string> phrase = {};
for(string word; ss >> word;) {
phrase.push_back(word);
}
myTrie.add(phrase, weight, &myTrie.root);
vector<string> ans = {};
}
// parse query line
string query;
getline(cin, query);
stringstream ss(query);
vector<string> search = {};
for (string query; ss >> query;) {
search.push_back(query);
}
myTrie.get(search);
return 0;
}
You can remove recursive methods, and doing something like the following:
#include <algorithm>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <set>
class Node
{
public:
bool endOfSentence = false;
std::set<int> weights;
std::map<std::string, Node> children;
Node() = default;
const Node* get(const std::string& word) const
{
auto it = children.find(word);
if (it == children.end()) {
return nullptr;
}
return &it->second;
}
auto find_by_weight(int weight) const
{
return std::find_if(children.begin(),
children.end(),
[=](const auto& p){ return p.second.weights.count(weight);});
}
};
class Trie
{
Node root;
public:
void add(int weight, const std::vector<std::string>& phrase)
{
Node* node = &root;
for (const auto& word : phrase) {
node->weights.insert(weight);
node = &node->children[word];
}
node->weights.insert(weight);
node->endOfSentence = true;
}
bool contains(const std::vector<std::string>& phrase) const
{
const Node* node = &root;
for (const auto& word : phrase) {
node = node->get(word);
if (node == nullptr) {
return false;
}
}
return node->endOfSentence;
}
void print(int weight) const
{
const Node* node = &root;
const char* sep = "";
while (node) {
const auto it = node->find_by_weight(weight);
if (it == node->children.end()) {
break;
}
std::cout << sep << it->first;
sep = " ";
node = &it->second;
}
std::cout << std::endl;
}
void print_all() const
{
for (int i : root.weights) {
print(i);
}
}
};
And usage/Test:
int main(int argc, char* argv[]) {
const std::vector<std::vector<std::string>> sentences = {
{"My", "name", "is", "John"},
{"My", "house", "is", "small"},
{"Hello", "world"},
{"Hello", "world", "!"}
};
Trie trie;
int i = 0;
for (const auto& sentence : sentences) {
trie.add(i, sentence);
++i;
}
const std::vector<std::vector<std::string>> queries = {
{"My", "name", "is", "John"},
{"My", "house"},
{"Hello", "world"}
};
for (const auto& query : queries) {
std::cout << trie.contains(query) << std::endl;
}
trie.print_all();
}
Demo

Printing out information from a file by looping through another function designed to search the file - C++

I have this function that can scan my file and print out a predesignated record according to which one you choose to look at:
void addressBook::showRecord(int pickNum) {
PEOPLE2 p;
ifstream indata("vectortest.dat", ios::binary);
if(!indata) {
cout << "Error opening file for reading " << endl;
exit(0);
}
indata.seekg(pickNum * sizeof(PEOPLE2));
indata.read(reinterpret_cast <char*> (&p), sizeof(PEOPLE2));
cout << p.fName2 << " " << p.lName2 << " " << p.Address2 << " " << endl;
}
So all you have to do is pop showRecord into main, and then pick which name you want to print out. Say I want to look at the second name stored, I would put in
newBook->showRecord(1);
Thats all fine an dandy, and it works perfect, but what if I want to go a bit further. So I create another function that can use showRecord to print out all of the names in the address book that have been stored to my file. I tried this:
void addressBook::showAll() {
ifstream indata("vectortest.dat", ios::binary);
for(int i = 0; i < indata.end; i++) {
showRecord(i);
}
}
and it works, but it only prints out the stuff that's hard coded into my PERSON struct from a previous assignment:
addressBook *newBook = addressBook::newbookInst();
PERSON me[] = {{"First" , "Last", "ADDRESS"}, {"John", "Doe", "1234"}};
newBook->addPerson(me[1]);
newBook->addPerson(me[0]);
which is just odd beacuse when I go into the file itself, I can see all of the names that were added.
So how do I use this so that it actually prints out everything in the file, and not just the two entries that are permanently stored?
Here is my addressbook.h and addressbook.cpp code in case you need a better understanding of whats going on...
\\addressbook.h////////
#ifndef _ADDRESSBOOK
#define _ADDRESSBOOK
#include <fstream>
#include <vector>
#include<string>
using std::string;
#include <iostream>
using namespace std;
using std::istream;
using std::ostream;
namespace CJ
{
const int MAXADDRESS =25;
struct PERSON
{
string fName;
string lName;
string Address;
};
struct PEOPLE2
{
char fName2[25];
char lName2[25];
char Address2[25];
};
class addressBook
{
private:
vector<PERSON> people;
int head;
int tail;
public:
addressBook();
addressBook(const PERSON &p);
addressBook(const PERSON p[], int size);
addressBook(char *fName, char *lName, char *address);
bool addPerson(const PERSON &p);
bool sortcomp(const PERSON& p1, const PERSON& p2);
bool getPerson(PERSON &p);
bool findPerson(const string& lastName, PERSON& p);
bool findPerson(const string& lastName, const string& firstName, PERSON& p);
void bubbleSort(int *array,int length);
void printBook();
void sort();
void waitKey();
static addressBook *newbookInst();
static addressBook *tempNew;
static PERSON *p();
static PERSON *temPerson;
void showRecord(int pickNum);
void writeRecord();
void showAll();
friend ostream &operator << (ostream &, addressBook &);
addressBook operator =(const string& str);
addressBook &operator +=(const PERSON &p);
addressBook operator [](int x);
};
}
#endif
\\addressbook.cpp/////
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <conio.h>
#include <string>
using std::string;
#include "addressBook.h"
#include "menu.h"
namespace CJ
{
addressBook::addressBook()
: head(0), tail(-1)
{
}
addressBook::addressBook(const PERSON &p)
: head(0), tail(-1)
{
addPerson(p);
}
addressBook::addressBook(const PERSON p[], int size)
: head(0), tail(-1)
{
for(int i = 0; i < size; i++)
addPerson(p[i]);
}
addressBook::addressBook(char *fName, char *lName, char *Address)
: head(0), tail(-1)
{
PERSON tmp;
tmp.fName = fName;
tmp.lName = lName;
tmp.Address = Address;
addPerson(tmp);
}
bool addressBook::addPerson(const PERSON &p)
{
people.push_back(p);
if(tail == -1)
tail++;
return true;
}
bool addressBook::getPerson(PERSON &p)
{
if(tail >=0)
{
if(tail >= people.size())
tail = 0;
p = people[tail];
tail++;
return true;
}
return false;
}
bool addressBook::findPerson(const string &lastName, PERSON &p)
{
for(size_t i = 0; i < people.size(); i++)
{
if(people[i].lName == lastName)
{
PERSON *p = addressBook::p();
*p = people[i];
return true;
}
}
return false;
}
bool addressBook::findPerson(const string &lastName, const string &firstName, PERSON &p)
{
for(size_t i = 0; i < people.size(); i++)
{
if(people[i].lName == lastName && people[i].fName == firstName)
{
PERSON *p = addressBook::p();
*p = people[i];
return true;
}
}
return false;
}
void addressBook::printBook()
{
for(size_t i = 0; i < people.size(); i++)
{
std::cout << people[i].fName << "\t" << people[i].lName << "\t" << people[i].Address << std::endl;
}
}
bool addressBook::sortcomp(const PERSON& p1, const PERSON& p2)
{
int result = (p1.lName.compare(p2.lName)) ;
if ( result > 0 )
return true ;
if ( result < 0 )
return false ;
return (p1.fName.compare(p2.fName)) > 0 ;
}
void addressBook::sort()
{
bool didSwap ;
do
{
didSwap = false ;
for ( unsigned i=1; i<people.size(); ++i )
if ( sortcomp(people[i-1], people[i]) )
{
std::swap(people[i-1], people[i]) ;
didSwap = true ;
}
} while ( didSwap ) ;
}
addressBook &addressBook::operator +=(const PERSON &p)
{
addPerson(p);
return *this;
};
addressBook addressBook::operator [](int x)
{
return people[x];
};
ostream &operator << (ostream &output, addressBook &ab)
{
PERSON tmp;
ab.getPerson(tmp);
output << tmp.fName << " " << tmp.lName << " " << tmp.Address << endl;
return output;
}
addressBook * addressBook::tempNew = NULL;
addressBook *addressBook::newbookInst()
{
if(tempNew == NULL)
{
tempNew = new addressBook;
}
return tempNew;
}
PERSON * addressBook::temPerson = NULL;
PERSON *addressBook::p()
{
if(temPerson == NULL)
{
temPerson = new PERSON;
}
return temPerson;
}
bool status;
char lName[50];
char fName[50];
void addressBook::writeRecord()
{
PEOPLE2 temp;
ofstream outFile("vectortest.dat", ios::app);
if(!outFile)
{
cout << "Error opening file for writing " << endl;
return;
}
for (vector<PERSON>::iterator iter = people.begin(), end = people.end(); iter != end; ++iter)
{
strncpy(temp.fName2, iter->fName.c_str(), 25);
strncpy(temp.lName2, iter->lName.c_str(), 25);
strncpy(temp.Address2, iter->Address.c_str(), 25);
outFile.write(reinterpret_cast<const char *>(&temp), sizeof(PEOPLE2));
}
outFile.close();
}
void addressBook::showRecord(int pickNum)
{
PEOPLE2 p;
ifstream indata("vectortest.dat", ios::binary);
if(!indata)
{
cout << "Error opening file for reading " << endl;
exit(0);
}
indata.seekg(pickNum * sizeof(PEOPLE2));
indata.read(reinterpret_cast<char *>(&p), sizeof(PEOPLE2));
cout << p.fName2 << " " << p.lName2 << " " << p.Address2 << " " << endl;
indata.close();
}
void addressBook::showAll()
{
ifstream indata("vectortest.dat", ios::binary);
for(int i = 0; i < indata.end; i ++)
{
showRecord(i);
}
}
}
I don't really know that much about the context of how you're planning to use your address book class. But what I've done is re-work the basic structure of what you had into a little more idiomatic C++. This should hopefully help guide your future work on this class. The reading from file issue that you were having issues with is fixed.
#include <iostream>
#include <iterator>
#include <fstream>
#include <cstdlib>
#include <conio.h>
#include <string>
#include <vector>
#include <algorithm>
const int MAXADDRESS = 25;
struct PEOPLE2
{
char fName2[25];
char lName2[25];
char Address2[25];
};
struct PERSON
{
PERSON()
{}
PERSON(PEOPLE2 p)
: fName(p.fName2), lName(p.lName2), Address(p.Address2)
{}
PERSON(const std::string& first, const std::string& last, const std::string& add)
: fName(first), lName(last), Address(add)
{}
std::string fName;
std::string lName;
std::string Address;
};
// required for std::sort
bool operator< (const PERSON &lhs, const PERSON &rhs)
{
int result = (lhs.lName.compare(rhs.lName));
if(result == 0)
return lhs.fName < rhs.fName;
return result < 0;
}
// required for os << people
std::ostream& operator<< (std::ostream& os, const PERSON& rhs)
{
os << rhs.fName << " " << rhs.lName << " " << rhs.Address;
return os;
}
class addressBook
{
private:
std::vector<PERSON> people;
public:
addressBook()
{ }
addressBook(const PERSON &p)
{
addPerson(p);
}
template<typename IT>
addressBook(IT begin, IT end)
{
std::copy(begin, end, std::back_inserter(people));
}
addressBook(char *fName, char *lName, char *address)
{
PERSON tmp;
tmp.fName = fName;
tmp.lName = lName;
tmp.Address = address;
addPerson(tmp);
}
addressBook(const std::string& fileName)
{
std::ifstream indata(fileName, std::ios::binary);
PEOPLE2 p;
while(true)
{
indata.read(reinterpret_cast<char*>(&p), sizeof(PEOPLE2));
if(indata.fail())
break;
people.push_back(p);
}
}
void addPerson(const PERSON &p)
{
people.push_back(p);
}
bool findPerson(const std::string& lastName, PERSON& p)
{
std::find_if(std::begin(people), std::end(people), [&](const PERSON& in)->bool
{
if(lastName == in.lName)
{
p = in;
return true;
}
return false;
});
}
bool findPerson(const std::string& lastName, const std::string& firstName, PERSON& p)
{
std::find_if(std::begin(people), std::end(people), [&](const PERSON& in)->bool
{
if(lastName == in.lName && firstName == in.fName)
{
p = in;
return true;
}
return false;
});
}
void printBook()
{
std::for_each(std::begin(people), std::end(people), [](const PERSON& p)
{
std::cout << p.fName << "\t" << p.lName << "\t" << p.Address << std::endl;
});
}
void sort()
{
std::sort(std::begin(people),std::end(people));
}
void waitKey();
void showRecord(int pickNum)
{
std::cout << people[pickNum] << std::endl;
}
void writeRecord(const std::string& fileName)
{
PEOPLE2 temp;
std::ofstream outFile(fileName, std::ios::app);
if(!outFile)
{
std::cout << "Error opening file for writing " << std::endl;
return;
}
for(auto iter = people.begin(), end = people.end(); iter != end; ++iter)
{
strncpy(temp.fName2, iter->fName.c_str(), 25);
strncpy(temp.lName2, iter->lName.c_str(), 25);
strncpy(temp.Address2, iter->Address.c_str(), 25);
outFile.write(reinterpret_cast<const char *>(&temp), sizeof(PEOPLE2));
}
}
void showAll()
{
std::for_each(std::begin(people), std::end(people), [](const PERSON& in)
{
std::cout << in << std::endl;
});
}
friend std::ostream &operator << (std::ostream &output, addressBook &ab)
{
std::for_each(std::begin(ab.people), std::end(ab.people), [&](const PERSON& in)
{
output << in << "\n";
});
return output;
}
addressBook &operator +=(const PERSON &p)
{
addPerson(p);
return *this;
};
PERSON operator [](int x)
{
return people[x];
};
};
std::string fileName = "c:\\temp\\test.rec";
int main()
{
addressBook ab(fileName);
ab.sort();
ab.showAll();
//addressBook ab;
//ab.addPerson(PERSON("Mary", "Smith", "1 West Street"));
//ab.addPerson(PERSON("Joe", "Brown", "2 East Street"));
//ab.addPerson(PERSON("Harry", "Cooper", "3 South Street"));
//ab.writeRecord(fileName);
}