Trying to make a B inary S earch T ree (BST for short) using a template.
When I try to create a new instance of my BST I get an unexpected error. I hope the solution does not involve pointers since I would like to keep them at a minimum.
For now I have:
template <typename Type>
class BST { // The binary search tree containing nodes
private:
BSTNode<Type> *root; // Has reference to root node
public:
BST ();
bool add (int, Type);
};
And the Node type:
EDIT: When I cut out code to un-encumber text, I forgot the constructor, now it's been added
template <typename Type>
class BSTNode { // Binary Search Tree nodes
private:
int key; // we search by key, no matter what type of data we have
Type data;
BSTNode *left;
BSTNode *right;
public:
BSTNode (int, Type&);
bool add (int, Type);
};
EDIT2: Here is the actual constructor
template <typename Type>
BSTNode<Type>::BSTNode (int initKey, Type &initData) {
this->key = initKey;
this->data = initData;
this->left = NULL;
this->right = NULL;
}
I want to try and test if anything works / doesn't work
BSTNode<int> data = new BSTNode (key, 10);
And I get: Expected type specifier before BSTNode. I have no idea what I'm doing wrong, but one thing I do hope is I don't have to use data as a pointer.
BSTNode<int> data = new BSTNode<int> (key, 10);
Also does not work, seems it believes < int > is < & int> and it doesn't match
First, you need to fully specify the type on the RHS of the assignment, and, since you are instantiating a dynamically allocated node with new, the LHS should be a pointer:
BSTNode<int>* data = new BSTNode<int> (key, 10);
^ ^
If you don't need a node pointer, then use
BSTNode<int> data(key, 10);
Second, your BSTNode<T> class doesn't have a constructor taking an int and a Type, so you need to provide that too.
template <typename Type>
class BSTNode {
public:
BSTNode(int k, const Type& val) : key(k), data(val), left(0), right(0) { .... }
};
Related
I want to create a Node in Linked List, with data has multiple type (ex: int, string).
So the first thing right in my mind is template.
header file
template <typename T>
class SymbolTable
{
struct Node
{
string id;
T data;
Node *next;
};
public:
void insert(string id, string dataType); // I intend to use "dataType" to deduce type of data in Node struct
}
cpp file
template<typename T>
void SymbolTable<T>::insert(string id, string dataType)
{
Node *traverser = &(this->head);
while (traverser->next != nullptr) // Insert at the end of Linked List
{
traverser = traverser->next;
}
Node *newNode = new Node();
newNode->id = id;
newNode->next = nullptr;
traverser->next = newNode;
// I don't know how to use "dataType" to deduce the type of data in Node struct
}
But then in main.cpp, it said
SymbolTable *st = new SymbolTable(); // cannot deduce class template arguments <-- I don't want this
So is there anyway to
Deduce the type of data using a variable + condition (something like: if dataType == "number" then deduce T -> int) in cpp file?
Get rid of "cannot deduce class template arguments" in main.cpp?
P/S:
No external library except string
File in main.cpp can't be modified
I think you might want to do something like this:
template <typename T>
struct Node
{
string id;
T data;
Node *next;
};
template <typename T>
class SymbolTable
{
public:
void insert(string id, T dataType);
private:
Node<T> *root = nullptr;
}
SymbolTable<string> table;
table.insert("hello", "My data");
I'm not actually coding it, but this might work.
I have one semestral work (own double linked list) and our teacher want this definition of class DoubleList:
template <typename T> //just part of all methods
class DoubleList {
public:
DoubleList(void); //We HAVE TO follow this definitions
void AddFirst(const T &); //const!
T &AccessActual(void);
T RemoveFirst(void);
}
My question is, how can I define a node? AddFirst have const argument and other methods haven't. Data must be set in constructor and then they can't be changed. Is this task so limited or are here other ways to complete the task?
Here is my actual Node:
template <class U>
class Node{
Node<U> * next;
Node<U> * previous;
const U * data;
public:
Node(const U *data){ //
next = NULL;
previous = NULL;
this->data = data;
}
void SetNext(Node<U> *next) {
this->next = next;
}
Node<U> *GetNext(){ return next; }
void SetPrevious(Node<U> *previous) {
this->previous = previous;
}
Node<U> *GetPrevious(){ return previous; }
const U *GetData() { return data; }
};
In containers, it's usually better to have a copy of the data so change const U * data; to U data;
The Node constructor would be easier to use if it had this signature Node(const U& data). No pointers.
The GetData would also have to change. Return a reference. U& GetData().
It is dangerous to hold addresses of data items. If the user of the lists wants that functionality he can use a list that stored pointers (e.g. U=int*)
Your node class seems fine, although i would keep using template argument T instead of U, right now it is confusing.
Your AddFirst() method should simply create a new node and assign the correct next pointer to the new node and the correct prev pointer to the "old" first node and adjust the actual object? what does that refer to?
Your interface of nodes differs from this one returning a reference instead of a pointer. I find it quite strange that the AccessActual can always return an object, while when the list is empty this can be a nullptr??
example implementation:
void AddFirst(const T &)
{
Node<T>* newNode = new Node<T>(T);
Node<T>* current = &AccessActual(); // how can there be an actual when the list can be empty or is that impossible?
{
while( current.GetPrev() != nullptr )
{
current = *current.GetPrev();
}
current.SetPrev(newnode);
newnode->SetNext(current);
}
}
template <class Type>
class Node
{
public:
Node ()
{
}
Node (Type x, Node* nd)
{
data = x;
next = nd;
}
Node (Type x)
{
data = x;
next = NULL;
}
~Node (void)
{
}
Node (const Node* & nd)
{
data = nd->data;
next = nd->next;
}
Node & Node::operator = (const Node* & nd)
{
data = nd->data;
next = nd->next;
}
T data;
Node* next;
};
Do I replace every Node* with
Node*<Type>
I tried replacing it and tried running something like
Node* temp = myq.head;
but it says argument list for class template "Node" is missing. I'm not really sure how to work with Templates when I need the Node class itself being part of it
Every declaration of Node will need a type in <>.
For
Node* temp = myq.head;
it depends on what myq.head is defined as. If it's defined as Node<int>* then temp also has to be defined as Node<int>* temp. You always have to have the <> with template objects.
If you wanted to have Node* without knowing the type, you could use inheritance. Have a templated TypedNode class that inherits from a non-template Node class. You would be able to pass all those TypeNode<> objects around with Node*, but you wouldn't be able to get the value of the nodes back out without knowing their type.
I don't recommend this but If you really want to make nodelists with mixed types you'll need to track the types by either
Include an enum type in the base class that defines the type stored in the node, and define typedNode for each class, setting the enum in it's constructor, or returning it from a virtual method.
RTTI, Run Time Type Information http://en.wikipedia.org/wiki/Run-time_type_information
Let's suppose we have a RedBlack-Tree implementation which consists of 2 classes:
Tree - holds the pointer to the Node *root of the tree and defines all operations over the tree (Insert, Delete, etc)
Node - a data storage, which holds pointers to Node *parent, Node *left, Node *right nodes and std::string key.
The Tree::Insert() has the following implementation:
void Tree::Insert(const std::string &key)
{
Node *z = new Node(key);
// adding node logic
}
Now the task: every node has to store the time of its creation.
Limitations: the base tree implementation should be modified as less as possible and should contain details of specific extensions (so it should know nothing about the creation time property).
My thoughts: extending NodeWithTime : Node and adding unsigned int creation_time property.
Where I'm in stuck: how would we instantiate the node now?
Any proposals?
PS: it's neither a homework or a job task - I'm just learning c++ and data structures.
It's relatively simple. First, the Node struct:
template<typename T> struct Node {
Node(T t) : value(std::move(t)), time(RightNow()) {}
T value;
TimeType time;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
};
A quick helper make_unique:
template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) {
return std::unique_ptr<T>(new T(std::forward<Args>(args...)));
}
template<typename T> void Tree<T>::Insert(T key) {
auto z = make_unique<Node<T>>(std::move(key));
// insert
}
First, I fixed your crappy new and delete and replaced it with smart pointers. Then I also made your tree a template because who needs a tree that can only do one type? Then I swapped out your const T& with a T so that it might live with move-only types.
Then I just added a Time field and called RightNow() in the constructor. The exact TimeType and RightNow() you use depends on your needs and what exactly you mean by "time of it's creation". Are we talking about "6th July, 2013"? Or a very-high-resolution clock? In any case, these "creation time" details do not impact the tree.
Edit: Wait, you want to have one tree type where only some of the nodes know the creation time? Or just to alter the tree so that all the nodes know the creation time? I did #2, but for #1, you could indeed simply inherit from Node. To wit,
template<typename T> struct Node {
Node(T t) : value(std::move(t)) {}
T value;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
};
template<typename T> struct NodeWithTime : Node<T> {
TimeType time;
NodeWithTime(T t) : Node(std::move(t)), time(RightNow()) {}
};
template<typename T> void Tree<T>::insert(T t) {
std::unique_ptr<Node> nodeptr;
if (IWantToStoreCreationTime)
nodeptr = make_unique<NodeWithTime<T>>(std::move(t));
else
nodeptr = make_unique<Node>(std::move(t));
// insert
}
I'm making a B inary S earch T ree (BST for short) and I've run into a problem that I can't figure out.
I shall try and reduce the amount of code but it still may require quite a bit I'm afraid.
Nodes:
template <typename Type>
class BSTNode { // Binary Search Tree nodes
private:
int key; // we search by key, no matter what type of data we have
Type data;
BSTNode *left;
BSTNode *right;
public:
BSTNode (int, Type);
bool add (int, Type);
Type search (int);
BSTNode<Type> *remove (int, BSTNode*);
BSTNode<Type> *minNode (int);
};
Root:
template <typename Type>
class BST { // The binary search tree containing nodes
private:
BSTNode<Type> *root; // Has reference to root node
public:
BST ();
bool add (int, Type);
Type search (int);
bool remove (int);
};
I don't know how much code to give since I don't want to exaggerate, if you need more, say so please.
I do both do recursive search and remove
template<typename Type>
BSTNode<Type> *BSTNode<Type>::remove(int removeKey, BSTNode *parent) {
// Here I try to remove nodes
// Depending on the number of children a node has, I remove in different ways
// The error occurs at removing a node with 2 children
// here I look for smallest node greater than current node, replace current node, delete node I replaced WITH
if (this->left != NULL && this->right != NULL){
int *auxKey = &key;
this = this->right->minNode(auxKey); // replace
return this->right->remove(this->key, this); // remove old node
}
}
Here is minNode:
template<typename Type>
Type *BSTNode<Type>::minNode (int oldKey) {
if (this->left == NULL) {
//oldKey = this->key;
return this->data;
} else
return left->minNode();
}
This is where the error occurs:
this = right->minNode(auxKey);
This causes a chain of errors, but I think the main error is:
error: invalid conversion from 'int*' to 'int' [-fpermissive]
I'm guessing it's something simple I've overlooked, but I just can't find it, have been trying for quite some time.
EDIT: Decided for now to simply pass key to minNode() and ignore oldKey and auxKey, modified minNode to return pointer.
New Error, same place
lvalue required as left operand
Your minNode function takes in an int value representing the old key, but you're passing an int* into it in the remove function (specifically, auxKey). Try passing in the value of the old key, not a pointer to it. Alternatively, if you want to update the in parameter to hold the correct value (you seem to be trying to do this), change the parameter to a reference parameter.
Hope this helps!