Building a trie for a set of strings - c++11

#include <iostream>
#include <vector>
#include <string>
#include <map>
#include <stdlib.h>
using namespace std;
struct trienode
{
map<char, struct trienode*> m;
bool endofword;
};
struct trienode* create_node()
{
struct trienode* new_node = (struct trienode*)malloc(sizeof(struct trienode));
new_node->endofword = false;
return new_node;
};
void word_insert(struct trienode* root, string word)
{
struct trienode* curr = root;
for (unsigned int i =0; i < word.size(); i++) {
if (curr->m.find(word[i]) == curr->m.end()) {
struct trienode* new_node = create_node();
***curr->m.insert(pair<char, struct trienode*>(word[i], new_node) );***
}
curr = curr->m.find(word[i])->second;
}
curr->endofword = true;
}
int main()
{
struct trienode* root = NULL;
root = create_node();
vector<string> v = {"aspirin", "aspetol", "astray", "atran", "chronic"};
for (unsigned int i =0; i < v.size(); i++) {
word_insert(root, v[i]);
}
}
I am trying to build a trie data structure to hold a set of strings. I have written a word_insert() function to insert a word into the trie. For inserting a word into the trie, I start at the root node, see if the map in the root node contains the char and if yes, I proceed to the next charachter. If the char is not present in the map of the node, I create another trienode and insert an entry into the map. However, when I am doing this, I see a problem with my code. My code hangs at the point where I try to insert the (char, struct trienode*) pair into the map.
Could someone tell me what is wrong with that? Thank you.

Related

Error E0146 : Too many initializer values C++

I have a school project and I have to use the AM in the Student.h as a char*.The AM have to have numbers in it. I can't understand why what I am doing is not working.
Student.cpp
#include <iostream>
#include <string>
#include "Student.h"
using namespace std;
int main()
{
Student dlg;
dlg.AM[10]={2,1,3,9,0,2,6,6};
}
Student.h
#pragma once
#include <string>
using namespace std;
class Student
{
public:
char *AM[20];
string Name;
unsigned int Semester = 1;
};
If you really need your student number to be a char string, then you need to convert your ints to char* before assigning them to the array.
int main()
{
Student dlg;
int j = 0;
for (auto i : {2,1,3,9,0,2,6,6})
{
auto strInt { std::to_string(i) }; // create a C++ string containing a int
// next copy the internal memory of the C++ string to a read-writable memory buffer
// and assign a pointer to that buffer casted to a char* to the appropriate slot in the array
dlg.AM[j++] = static_cast<char*> (std::memcpy (new char[16], strInt.c_str(), strInt.size()));
}
// test
for (int i = 0; i < 8; i++)
{
cout << dlg.AM[i] << ' ';
}
}
Are you sure the student number should be a char* ?

how can we add an element in the map of set...eg .map<int,unordered_multiset<int>>mp; in c++14

i want add an element to the mp[x].
map<int,unordered_multiset>adj;
for(int i=0;i<n;i++)
{
cin>>brr[i];
if(brr[i]!=arr[i])
{
// i want to add an element
//in mp[brr[i]] ;
}
else
{
comp.insert({brr[i],i+1}); //set
}
}
}
Here is an example for a map from int to unordered_multiset<int>.
#include <map>
#include <unordered_set>
#include <iostream>
int main() {
std::map<int, std::unordered_multiset<int>> adj;
const int z = 10;
adj[6].insert(z);
adj[6].insert({1,2,3});
auto& myset = adj[6];
for(auto const& x : myset) {
std::cout << x << std::endl;
}
return 0;
}
Output:
3
2
1
10
The examples on cppreference are usually quite good:
https://en.cppreference.com/w/cpp/container/map#Example
https://en.cppreference.com/w/cpp/container/map/insert#Example
And then you have to find the correct way to insert into the multiset:
https://en.cppreference.com/w/cpp/container/unordered_multiset/insert
And one of them uses the initializer_list {}

Efficient search for an element other than the one used for ordering in std::set

Consider the following set implementation. Here I have ordered the set based on fScore parameter. What should I do If I want to search for an element of particular 'id' in 'NodeData'.
I know I can use 'find' to search for any element of 'fScore' in the set with O(logn).
Is there any efficient way to search for 'id' (less time) than a linear search (implemented below)?
#include<iostream>
#include<algorithm>
#include<iterator>
#include<set>
#include<stdlib.h>
#include<vector>
struct NodeData{
int id;
int parent;
double fScore, gScore, hScore;
std::vector<double> nScores;
NodeData(const int& idIn = 0,
const int& parentIn = -1,
const double& fIn = 1,
const double& gIn = 1,
const double& hIn = 1):id(idIn), parent(parentIn),
fScore(fIn), gScore(gIn), hScore(hIn)
{
}
bool operator<(const NodeData& rhs) const {
return fScore < rhs.fScore;
}
};
class test
{
public:
std::set<NodeData> NodeList;
};
int main()
{
test q;
for(int i=1;i<=5;i++)
{
NodeData n1 = {i,1,i,1,1};
q.NodeList.insert(n1);
}
std::set<NodeData>::iterator it;
//search for node with fScore 1 - cost O(logn)
it = q.NodeList.find(1);
if(it != q.NodeList.end()){
std::cout<<"node with fScore 1 found. id = "<<it->id<<std::endl;
}
else{
std::cout<<"node not found = "<<std::endl;
}
//searching for id=3 - Linear search - cost O(n)
int searchId = 3;
std::set<NodeData>::iterator it1 = q.NodeList.begin();
while(it1 != q.NodeList.end())
{
if(it1->id == searchId)
{
std::cout <<"found node with id = "<<it1->id<<std::endl;
}
it1++;
}
}
Does your set changes often? If not - you could consider building an "index" - unordered_map<> of whatever field you need to the element of your set.
There is a cost of maintaining such "index", you should see if it overweights the faster search.
You can't achieve this without using different/additional data structures. If you're using C++ and you're OK with using a library, you can find this functionality in the Boost multi-index containers library.
Adding to Falk's answer, here's an example of how the thing could be done with Boost.MultiIndex:
Live On Coliru
#include <iostream>
#include <algorithm>
#include <iterator>
#include <stdlib.h>
#include <vector>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>
struct NodeData{
int id;
int parent;
double fScore, gScore, hScore;
std::vector<double> nScores;
NodeData(const int& idIn = 0,
const int& parentIn = -1,
const double& fIn = 1,
const double& gIn = 1,
const double& hIn = 1):id(idIn), parent(parentIn),
fScore(fIn), gScore(gIn), hScore(hIn)
{
}
bool operator<(const NodeData& rhs) const {
return fScore < rhs.fScore;
}
};
class test
{
public:
typedef boost::multi_index_container<
NodeData,
boost::multi_index::indexed_by<
boost::multi_index::ordered_unique<
boost::multi_index::identity<NodeData>
>,
boost::multi_index::ordered_unique<
boost::multi_index::member<NodeData, int, &NodeData::id>
>
>
> NodeListType;
NodeListType NodeList;
};
int main()
{
test q;
for(int i=1;i<=5;i++)
{
NodeData n1 = {i,1,double(i),1,1};
q.NodeList.insert(n1);
}
test::NodeListType::iterator it;
//search for node with fScore 1 - cost O(logn)
it = q.NodeList.find(1);
if(it != q.NodeList.end()){
std::cout<<"node with fScore 1 found. id = "<<it->id<<std::endl;
}
else{
std::cout<<"node not found = "<<std::endl;
}
//searching for id=3 on second index - cost O(logn)
int searchId = 3;
test::NodeListType::nth_index<1>::type::iterator it1 = q.NodeList.get<1>().find(searchId);
if(it1 != q.NodeList.get<1>().end()){
std::cout <<"found node with id = "<<it1->id<<std::endl;
}
}
If, instead of an ordered index, you use a hashed index for NodeData::id, lookup is constant (in average).

Error C2679 binary '<<': no operator found which takes a right-hand operand of type 'T' (or there is no acceptable conversion)

I'm having problems with my friend function within my template class. For some reason it doesn't like the fact that I'm trying to use a variable that is type T in an operator overloading friend function.
#include <iostream>
#include <fstream>
#include <string>
template <typename T>
class LL
{
struct Node
{
T mData;
Node *mNext;
Node();
Node(T data);
};
private:
Node *mHead, *mTail;
int mCount;
public:
LL();
~LL();
bool insert(T data);
bool isExist(T data);
bool remove(T data);
void showLinkedList();
void clear();
int getCount() const;
bool isEmpty();
friend std::ofstream& operator<<(std::ofstream& output, const LL& obj)
{
Node* tmp;
if (obj.mHead != NULL)
{
tmp = obj.mHead;
while (tmp != NULL)
{
output << tmp->mData << std::endl; // "tmp->mData is causing the error
tmp = tmp->mNext;
}
}
return output;
}
};
This is a linked list class, and I need the friend function operator overload to basically allow me to output any particular list of objects onto a text file. I hope someone can help me out.

C++ pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug

I keep getting this error. I know what function causes it, but don't know how to fix it. Looking up online from this post saying:
You need to pass a pointer to a dynamically allocated object, or make your own insde your chainLink class.
However, as I try to pass a string pointer. error still popping up. Here is my code.
#include <iostream>
#include "MWTNode.h"
#include "MWT.h"
using namespace std;
int main() {
MWT t;
string str ="abc";
string* strPtr = &str;
t.insert(strPtr);
std::cout << "Hello, World!" << std::endl;
return 0;
}
#include "MWTNode.h"
class MWT {
public:
MWTNode *root;
string find(const string &);
void insert(const string* string);
};
void MWT::insert(const string* word) {
MWTNode* curr = root;
MWTNode newNode;
string w = *word;
for (int i = 0; i < word->length(); i++) {
const char c = w[i];
if (curr->children.find(c) == curr->children.end()){
//curr->children[c]= MWTNode();
//node->frequency=node->frequency+1;
}
curr = &(curr->children[c]);
}
curr->flag = true;
}
#include <unordered_map>
#include <vector>
#include <string>
#include <sstream>
#include <set>
using namespace std;
class MWTNode {
public:
unordered_map<char, MWTNode> children;
string value;
bool flag;
int frequency;
MWTNode(const string &);
MWTNode(const char c);
MWTNode();
void setFrequency ();
int getFrequency ();
};
MWTNode::MWTNode(const string &val) {
value = val;
flag = false;
frequency = 0;
}
MWTNode::MWTNode(const char c) {
value =c;
flag = false;
frequency = 0;
}
MWTNode::MWTNode() {
value ="";
flag = false;
frequency = 0;
}
Lets highlight a few lines of the code you show
class MWT {
public:
MWTNode *root;
// ...
};
In that you declare the member variable root as a pointer.
void MWT::insert(const string* word) {
MWTNode* curr = root;
// ...
}
In the above you make curr point to where root is pointing.
But you never make root point anywhere! The MWT::root variable is uninitialized and will have an indeterminate value. Using this pointer in any way without initialization will lead to undefined behavior.
And yes you use this pointer, as you dereference curr inside the MWT::insert function.
It's a little unclear what you're doing (to me) but you need to make sure that root (and therefore curr) is a valid pointer before attempting to dereference it.

Resources