I have to implement a class that behaves like a map of strings using binary search tree. This is the class I implemented:
template<class T>
class StringMapper {
private:
// Pair
struct Pair {
std::string el1;
T el2;
};
// Nod
struct Node {
Pair* data;
Node* left;
Node* right;
Node()
{
data = new Pair;
}
~Node()
{
delete data;
}
int nod_size()
{
// code here
}
};
Node* root;
public:
StringMapper()
{
root = 0;
}
~StringMapper() {}
void insert(std::string from, const T& to)
{
// code here
}
bool find(std::string from,const T& to) const
{
return find(root, to);
}
bool find(Node* node, const T& value) const
{
// code here
}
bool getFirstPair(std::string& from, T& to)
{
if(root != 0)
{
from = root->data->el1;
to = root->data->el2;
return true;
}
return false;
}
bool getNextPair(std::string& from, T& to)
{
if(root != 0)
{
}
return false;
}
int size() const
{
return root->nod_size();
}
};
To be honest I don't know how to implement the function getNextPair().
If someone could help me I'd appreciate it.
Your interface is an internal iterator. You need to keep some kind of pointer to where you are in the iteration, and set it in getFirstPair().
Once you add this, getNextPair() just goes to the next one. It's somewhat difficult to do this, but that's your assignment, so I leave it to you.
The actual std::map uses an external iterator -- that keeps the state of the iteration separate from the data structure. The major advantage is being able to have more than one simultaneous iteration.
Without just throwing the algorithm for getNextPair, you will need to keep some kind of internal iterator which will point to the "current" pair. Once you got that, in order to figure the algorithm for the next pair draw yourself a tree with some nodes and see how one can find the next node in the tree given any node in the tree.
Related
I have the following tree structure:
template<typename T>
class Tree : public std::enable_shared_from_this<Tree<T>>
{
public:
Tree(T data);
Tree(T data, std::vector<std::shared_ptr<Tree<T>>> children);
void add_child(std::shared_ptr<Tree<T>>& child);
void add_children(std::vector<std::shared_ptr<Tree<T>>> children);
void set_parent(std::shared_ptr<Tree<T>> parent)
{ this->parent = parent; }
const T get_data() const
{ return this->data; }
const std::shared_ptr<Tree<T>>& get_parent() const
{ return this->parent; }
const std::vector<std::shared_ptr<Tree<T>>>& get_children() const
{ return this->children; }
private:
T data;
std::shared_ptr<Tree<T>> parent=nullptr;
std::vector<std::shared_ptr<Tree<T>>> children;
};
template<typename T>
Tree<T>::Tree(T data): data(data)
{ }
template<typename T>
Tree<T>::Tree(T data, std::vector<std::shared_ptr<Tree<T>>> children): data(data)
{
this->add_children(children);
}
template<typename T>
void Tree<T>::add_child(std::shared_ptr<Tree<T>>& child)
{
this->children.push_back(child);
child->set_parent(this->shared_from_this());
}
template<typename T>
void Tree<T>::add_children(std::vector<std::shared_ptr<Tree<T>>> children)
{
for (auto&& child : children)
{
this->children.push_back(child);
child->set_parent(this->shared_from_this());
}
}
And I wand to create a function find:
template<typename T>
generator<std::shared_ptr<Tree<T>>> find(const std::shared_ptr<Tree<T>>& t, T value);
Where you give a Tree and a value and it returns a generator that finds each subtree whose root node contains value. My question is, how would I create this generator in C++? I looked into coroutines, but they seemed overly complex for this(or almost anything). I also tried to think about doing the search with helper static variables, but I couldn't think about a way to code it without accidentally skipping nodes.
Here is a helper code to create a tree:
#include <vector>
#include <memory>
#include <iostream>
#include "tree.hpp"
std::shared_ptr<Tree<int>> create_tree()
{
// init tree and nodes
std::shared_ptr<Tree<int>> tree(new Tree<int>(1));
std::shared_ptr<Tree<int>> leaf1(new Tree<int>(5));
std::shared_ptr<Tree<int>> leaf2(new Tree<int>(4));
std::shared_ptr<Tree<int>> leaf11(new Tree<int>(3));
// construct tree
leaf1->add_child(leaf11);
std::vector<std::shared_ptr<Tree<int>>> v;
v.push_back(leaf1);
v.push_back(leaf2);
tree->add_children(v);
return tree;
}
int main()
{
std::shared_ptr<Tree<int>> tree = create_tree();
return 0;
}
First of all you can't use std::shared_ptr<Tree<T>> type for parent in your class. Since you are creating circular dependencies between std::shared_ptr's and they will never be deleted, thus creating memory leak. You can use plain pointer or std::weak_ptr, later is probably better option for you, to keep unified interface. So, in this case your get_parent() function will look like this:
std::shared_ptr<Tree<T>> get_parent() const
{ return this->parent.lock(); }
Now about generator, it is pretty simply to create one. Yes, you need to keep some state, but in case of a tree there is no much of a state to keep. You can do something like this:
template<typename T>
struct generator {
generator(std::shared_ptr<Tree<T>> t, T v) : value(v), tree(t) {}
std::shared_ptr<Tree<T>> getNext() {
std::shared_ptr<Tree<T>> next = advance();
while (next != nullptr && next->get_data() != value) {
next = advance();
}
return next;
}
private:
std::shared_ptr<Tree<T>> advance() {
if (tree == nullptr) return nullptr;
// Special case for first entry
if (state.empty()) {
// If we don't have children, this is last chance
if (tree->get_children().empty()) {
return std::exchange(tree, nullptr);
}
state.push(0);
return tree;
}
// Going up, till next node, can be few levels
while (state.top() >= tree->get_children().size()) {
state.pop();
tree = tree->get_parent();
if (tree == nullptr) return nullptr;
}
std::shared_ptr<Tree<T>> child = tree->get_children()[state.top()];
if (!child->get_children().empty()) {
// Go deeper
state.top()++;
state.push(0);
tree = child;
return child;
}
state.top()++;
return child;
}
T value;
std::shared_ptr<Tree<T>> tree;
std::stack<size_t> state;
};
You should implement an iterator for a generator class.
I'm looking into implementing a linked list, using templates.
As it stands, after looking at some guides, I have managed to built a functioning one, but I am wondering what is the purpose of template pointer? The code seems to be using them arbitrarily. I'll exemplify on my header code below:
template <class T>
class LinkedList{};
template <class T>
class LinkedList<T*>{
private:
Node<T*> *first;
int size;
public:
class Iterator{
public:
Iterator(Node<T*> *newElem){
elem = newElem;
}
virtual ~Iterator(){
}
T getValue(){
return *(elem->getValue());
}
void next(){
elem = elem->getNext();
}
void operator++(int i){
next();
}
void operator++(){
next();
}
T operator*(){
return getValue();
}
bool operator==(const Iterator& rhs){
return (elem == rhs.elem);
}
bool operator!=(const Iterator& rhs){
return (elem != rhs.elem);
}
bool hasNext(){
if (elem == NULL)
return false;
return true;
}
private:
Node<T*> *elem;
};
In this specific context, why do we need to declare the node variable or the linked list with < T *>? In my case, it works just fine using < T >, but I'm most likely missing something. The Node class(not listed above) is implemented using < T > as well, so what is actually happening when you add that pointer there?
Many thanks!
The difference is in the content of your Node.
Let's define the Node class:
template <class T>
struct Node
{
T data;
Node * next;
Node * previous;
};
Let's use int as type T and instantiate:
struct Node
{
int data;
Node * next;
Node * previous;
};
Let's use int and instantiate a T *, as in Node<T*> or Node <int *>:
struct Node
{
int * data;
Node * next;
Node * previous;
};
Notice any difference in the data type of the data member?
In one example, data is an int. In the other example, data is a pointer to an int.
Im trying to make a class to use in a Library, and im not sure if its even possible to do. The idea of this class, is to provide methods to insert, search and delete items on a list, but my main problem is that, as i dont know the type of object that i want to place in a list, I dont know how to work with it. I thought I could place a void pointer, and then make it point to a structure, but I havent been able to make it work.
Lets suppose my class is something like this:
class ListManager
{
private:
void* FirstItem;//This would point to the first item of the list
void* LastItem;//This would point to the last item of the list
public:
void AddItemToList(void* Item);
void RemoveItemFromList(void* Item);
}
So, the idea would be that, from my program, I can define a structure like
struct Employee
{
*char Name;
int Id;
int PhoneNumber;
}
And then, use this class, to be able to add/delete Employees. So in this case, the void* pointers, should be pointing to a struct of the type Employee. Nevertheless, i want to make my class work for any type of struct.
I dont know if i explained exactly what I want to do, I tried several ways of doing this, and failed on all of them.
Im going to post a code of how I would like the class to work, if I havent explained myself correctly
ListManager *Worker;
Worker=new(ListManager);
Employee *Item;
Item=new (Employee);
Item->Id=126;
Item->PhoneNumber=42154872;
Worker->AddItemToList(Item);
/*At this point, FirstItem and LastItem should point to the Item i just created*/
Could someone point me in the right direction, as how to make a class work with a structure, without knowing the type of structure?
Thanks in advance
You need templates!
here's a simple interface that you can start working with.
template <typename T>
class ListManager
{
public:
void addItemToList(const T& item);
void removeItemFromList(const T& item);
}
Now T is your type, and you'd declare a ListManager like this:
ListManager<Employee> manager;
I would suggest you also to look at the stl documentation/implementation of a list at: http://www.cplusplus.com/reference/list/list/
You have also the concept of iterators to dig into.
Also, try to use values instead of pointers. With the interface I gave you, you would store the actual value in the list and not a pointer, so the list owns the object and you won't need to manage your memory manually.
See this Tutorial:
http://www.tutorialspoint.com/cplusplus/cpp_templates.htm
Your Example could be look like:
#include <iostream>
using namespace std;
template <class T>
class ListManager
{
private:
void* FirstItem;//This would point to the first item of the list
void* LastItem;//This would point to the last item of the list
public:
void AddItemToList(const T& Item){
std::cout << Item << std::endl;
};
void RemoveItemFromList(const T& Item){};
};
int main() {
ListManager<std::string> mgr;
mgr.AddItemToList("Test");
return 0;
}
Output:
Test
Working Example:
http://ideone.com/FCAtcJ
There really are no interfaces in C++, but you could use a class template just the same way:
template <typename T>
class ListInterface {
public:
void add(T * item) { list.push_back( item); }
void remove(T * item) { list.erase(std::find(list.begin(), list.end(), item)); }
T * get(int index) { return list[index]; }
int size() const { return list.size(); }
private:
std::vector<T *> list;
};
class Manager : public ListInterface<Employee> {
// ...
};
Naturally, this is a barebone example, you really outta do some checking in the remove() and get() methods.
There are multiple solutions to this problem.
Simply use std::list
std::list<Employee> manager;
If 1. is not possible you can define your own list interface using template
template <class T>
class ListManager
{
private:
class Iterator {
public:
T& item;
Iterator* next;
Iterator* prev;
Iterator(T& i, Iterator* n, Iterator* p) : item(i), next(n), prev(p) {}
}
Iterator* FirstItem = NULL;//This would point to the first item of the list
Iterator* LastItem = NULL;//This would point to the last item of the list
public:
void AddItemToList(T& Item) {
if(LastItem) {
Iterator* it = new Iterator{Item, NULL, LastItem};
LastItem->next = it;
LastItem = it;
} else {
Iterator* it = new Iterator{Item, NULL, NULL};
FirstItem = it;
LastItem = it;
}
}
void RemoveItemFromList(const T& Item) {
for(Iterator* it = FirstItem; it != NULL; it = it->next) {
if(it->item == Item) {
if(it->prev)
it->prev->next = it->next;
else
FirstItem = it->next;
if(it->next)
it->next->pref = it->pref;
else
LastItem = it->pref;
delete it;
break;
}
}
}
};
If 1. and 2. is not possible because you need need multiple types inside your list. You can either use a list of Anys (like boost::Any) or a unsafe version with void*:
class ListManager
{
private:
class Iterator {
public:
void* item;
Iterator* next;
Iterator* prev;
Iterator(void* i, Iterator* n, Iterator* p) : item(i), next(n), prev(p) {}
}
Iterator* FirstItem = NULL;//This would point to the first item of the list
Iterator* LastItem = NULL;//This would point to the last item of the list
public:
template<class T>
void AddItemToList(T& Item) {
if(LastItem) {
Iterator* it = new Iterator{&Item, NULL, LastItem};
LastItem->next = it;
LastItem = it;
} else {
Iterator* it = new Iterator{&Item, NULL, NULL};
FirstItem = it;
LastItem = it;
}
}
template<class T>
void RemoveItemFromList(const T& Item) {
for(Iterator* it = FirstItem; it != NULL; it = it->next) {
if(it->item == &Item) {
if(it->prev)
it->prev->next = it->next;
else
FirstItem = it->next;
if(it->next)
it->next->pref = it->pref;
else
LastItem = it->pref;
delete it;
break;
}
}
}
};
Code is not tested
I'm having a little trouble trying to sort a vector of pointers.
This is what I have done so far:
class Node
{
private:
vector <Node*> _children;
string _data;
...
public:
void Node::add_child(Node* child)
{
...
sort(_children.begin(), _children.end());
}
bool Node::operator<(const Node& node)
{
return (this->_data.compare(node._data) == -1);
}
};
My less-than operator works, if I write like this:
Node* root = new Node("abc");
Node* n = new Node("def");
cout << (*root<*n) << endl;
Why does sort never call the operator?? Any help would be appreciated!
Thanks.
madshov
Because you sort the pointer values, not the Nodes they point to.
You can use the third argument of the std::sort algorithm to specify a custom comparator.
For example :
bool comparePtrToNode(Node* a, Node* b) { return (*a < *b); }
std::sort(_children.begin(), _children.end(), comparePtrToNode);
(note that this code is just an indication - you'll have to add extra safety checks where needed)
Your less-than operator takes const Node& arguments, but your vector is sorting Node*s. You need to specify a comparison function as the third parameter to std::sort.
class Node
{
private:
vector <Node*> _children;
string _data;
struct PointerCompare {
bool operator()(const Node* l, const Node* r) {
return *l < *r;
}
};
public:
void add_child(Node* child)
{
sort(_children.begin(), _children.end(), PointerCompare());
}
bool operator<(const Node& node) const
{
return (this->_data.compare(node._data) == -1);
}
};
Also, your operator< needs to be declared const.
Your operator<() operates on references to Node objects; but the vector contains pointers to Node objects, which can't be compared with that function. You'll have to explicitly supply a proper function (one that accepts pointers as arguments) to the sort() algorithm.
I have a Tree class with the following definition:
class Tree {
Tree();
private:
TreeNode *rootPtr;
}
TreeNode represents a node and has data, leftPtr and rightPtr.
How do I create a copy of a tree object using a copy constructor? I want to do something like:
Tree obj1;
//insert nodes
Tree obj2(obj1); //without modifying obj1.
Any help is appreciated!
Pseudo-code:
struct Tree {
Tree(Tree const& other) {
for (each in other) {
insert(each);
}
}
void insert(T item);
};
Concrete example (changing how you walk the tree is important to know, but detracts from showing how the copy ctor works, and might be doing too much of someone's homework here):
#include <algorithm>
#include <iostream>
#include <vector>
template<class Type>
struct TreeNode {
Type data;
TreeNode* left;
TreeNode* right;
explicit
TreeNode(Type const& value=Type()) : data(value), left(0), right(0) {}
};
template<class Type>
struct Tree {
typedef TreeNode<Type> Node;
Tree() : root(0) {}
Tree(Tree const& other) : root(0) {
std::vector<Node const*> remaining;
Node const* cur = other.root;
while (cur) {
insert(cur->data);
if (cur->right) {
remaining.push_back(cur->right);
}
if (cur->left) {
cur = cur->left;
}
else if (remaining.empty()) {
break;
}
else {
cur = remaining.back();
remaining.pop_back();
}
}
}
~Tree() {
std::vector<Node*> remaining;
Node* cur = root;
while (cur) {
Node* left = cur->left;
if (cur->right) {
remaining.push_back(cur->right);
}
delete cur;
if (left) {
cur = left;
}
else if (remaining.empty()) {
break;
}
else {
cur = remaining.back();
remaining.pop_back();
}
}
}
void insert(Type const& value) {
// sub-optimal insert
Node* new_root = new Node(value);
new_root->left = root;
root = new_root;
}
// easier to include simple op= than either disallow it
// or be wrong by using the compiler-supplied one
void swap(Tree& other) { std::swap(root, other.root); }
Tree& operator=(Tree copy) { swap(copy); return *this; }
friend
ostream& operator<<(ostream& s, Tree const& t) {
std::vector<Node const*> remaining;
Node const* cur = t.root;
while (cur) {
s << cur->data << ' ';
if (cur->right) {
remaining.push_back(cur->right);
}
if (cur->left) {
cur = cur->left;
}
else if (remaining.empty()) {
break;
}
else {
cur = remaining.back();
remaining.pop_back();
}
}
return s;
}
private:
Node* root;
};
int main() {
using namespace std;
Tree<int> a;
a.insert(5);
a.insert(28);
a.insert(3);
a.insert(42);
cout << a << '\n';
Tree<int> b (a);
cout << b << '\n';
return 0;
}
It depends on whether you want a shallow or deep copy. Assuming a deep copy, you need to be able to copy whatever's at the "leaves" hanging off a TreeNode object; so ideally the functionality should be in TreeNode (unless Tree is a friend class of TreeNode that you've designed to be deeply familiar with its implementation, which is often the case of course;-). Assuming something like...:
template <class Leaf>
class TreeNode {
private:
bool isLeaf;
Leaf* leafValue;
TreeNode *leftPtr, *rightPtr;
TreeNode(const&Leaf leafValue);
TreeNode(const TreeNode *left, const TreeNode *right);
...
then you could add to it a
public:
TreeNode<Leaf>* clone() const {
if (isLeaf) return new TreeNode<Leaf>(*leafValue);
return new TreeNode<Leaf>(
leftPtr? leftPtr->clone() : NULL,
rightPtr? rightPtr->clone() : NULL,
);
}
If Tree is taking care of this level of functionality (as a friend class), then obviously you'll have the exact equivalent but with the node being cloned as an explicit arg.
Two basic options:
If you have an iterator available, you can simply iterate over the elements in the tree and insert each one manually, as R. Pate described. If your tree class doesn't take explicit measures to balance the tree (e.g. AVL or red-black rotations), you'll end up effectively with a linked list of nodes this way (that is, all the left child pointers will be null). If you are balancing your tree, you'll effectively do the balancing work twice (since you already had to figure it out on the source tree from which you're copying).
A quicker but messier and more error-prone solution would be to build the copy top down by doing a breadth-first or depth-first traversal of the source tree structure. You wouldn't need any balancing rotations and you'd end up with an identical node topology.
Here's another example I used with a binary tree.
In this example, node and tree are defined in separate classes and a copyHelper recursive function helps the copyTree function. The code isn't complete, I tried to put only what was necessary to understand how the functions are implemented.
copyHelper:
void copyHelper( BinTreeNode<T>* copy, BinTreeNode<T>* originalNode ) {
if (originalTree == NULL)
copy = NULL;
else {
// set value of copy to that of originalTree
copy->setValue( originalTree->getValue() );
if ( originalTree->hasLeft() ) {
// call the copyHelper function on a newly created left child and set the pointers
// accordingly, I did this using an 'addLeftChild( node, value )' function, which creates
// a new node in memory, sets the left, right child, and returns that node. Notice
// I call the addLeftChild function within the recursive call to copyHelper.
copyHelper(addLeftChild( copy, originalTree->getValue()), originalTree->getLeftChild());
}
if ( originalTree->hasRight() ) { // same with left child
copyHelper(addRightChild(copy, originalTree->getValue()), originalTree->getRightChild());
}
} // end else
} // end copyHelper
copy: returns a pointer to the new tree
Tree* copy( Tree* old ) {
Tree* tree = new Tree();
copyHelper( tree->root, oldTree->getRoot() );
// we just created a newly allocated tree copy of oldTree!
return tree;
} // end copy
Usage:
Tree obj2 = obj2->copy(obj1);
I hope this helps someone.
When your class has a pointer pointing to dynamically allocated memory, in the copy constructor of that class you need to allocate memory for newly created object. Then you need to initialize newly allocated memory with whatever the other pointer pointing at. Here is an example how you need to deal with a class having dynamically allocated memory:
class A
{
int *a;
public:
A(): a(new int) {*a = 0;}
A(const A& obj): a(new int)
{
*a = *(obj.a);
}
~A() {delete a;}
int get() const {return *a;}
void set(int x) {*a = x;}
};
You can try something like (untested)
class Tree {
TreeNode *rootPtr;
TreeNode* makeTree(Treenode*);
TreeNode* newNode(TreeNode* p)
{
TreeNode* node = new Treenode ;
node->data = p->data ;
node->left = 0 ;
node->right = 0 ;
}
public:
Tree(){}
Tree(const Tree& other)
{
rootPtr = makeTree(other.rootPtr) ;
}
~Tree(){//delete nodes}
};
TreeNode* Tree::makeTree(Treenode *p)
{
if( !p )
{
TreeNode* pBase = newNode(p); //create a new node with same data as p
pBase->left = makeTree(p->left->data);
pBase->right = makeTree(p->right->data);
return pBase ;
}
return 0 ;
}