So i want to make a code, that creates a binary tree, that holds data, for example ints like 1,6,2,10,8 and on pop i get the biggest number, and after that it gets deleted from the tree, and on push i can insert a new element. And this should be in a template so i can easy change the data type i want to hold in the tree. Now i got the tree so far, without template it is working fine thought, i can add items, and i can print them, but when i try to put it in a template, i get the following error: use of class template requires template argument list . What could be the problem? Maybe i am doing it totally wrong. Any suggestions are welcome.
This was my first question it got fixed by avakar ty. (i will post the code at the end of my question)
I just read trough the project request , and its like, i have to make this thing i above in the first part of question described, but its like the binary tree should represent a priority queue. And that is why in the request is written that i have to use push to put a new element in the tree by priority order and with pop i will get the element with the highest priority and then that element will be deleted. So how could i use my Tree as a Priority queue, or is he already one(i think not but who knew)? I hope i could explain it.
And here is the code as promised:
#include <iostream>
using namespace std;
template<class T>
class BinaryTree
{
struct Node
{
T data;
Node* lChildptr;
Node* rChildptr;
Node(T dataNew)
{
data = dataNew;
lChildptr = NULL;
rChildptr = NULL;
}
};
private:
Node* root;
void Insert(T newData, Node* &theRoot)
{
if(theRoot == NULL)
{
theRoot = new Node(newData);
return;
}
if(newData < theRoot->data)
Insert(newData, theRoot->lChildptr);
else
Insert(newData, theRoot->rChildptr);;
}
void PrintTree(Node* theRoot)
{
if(theRoot != NULL)
{
PrintTree(theRoot->lChildptr);
cout<< theRoot->data<<" ";;
PrintTree(theRoot->rChildptr);
}
}
public:
BinaryTree()
{
root = NULL;
}
void AddItem(T newData)
{
Insert(newData, root);
}
void PrintTree()
{
PrintTree(root);
}
};
int main()
{
BinaryTree<int> *myBT = new BinaryTree<int>();
myBT->AddItem(1);
myBT->AddItem(7);
myBT->AddItem(1);
myBT->AddItem(10);
myBT->AddItem(4);
myBT->PrintTree();
}
If you want to use the binary tree as a priority queue, you extract the maximum element by stepping only through right child pointers. Any left child would be smaller than the current element. So you record the value of that node and then remove it -- you would still have to write a node deletion routine.
The problem with a simple BST is that it can become unbalanced and send your complexities to O(n). You can use a self-balancing BST, but it's unusual for priority queues. Instead of BSTs they are usually heaps, as Kerrek said.
The simplest heap implementation that I know personally is the binary heap. The binary heap is theoretically a type of binary tree although not stored as such. So, depending on whether you had to implement a BST or just a binary tree, it might fit your requirements.
On this line:
BinaryTree<int> *myBT = new BinaryTree();
You need to also specify the type of template you want to instantiate on the right side of the assignment:
BinaryTree<int> *myBT = new BinaryTree<int>();
Because BinaryTree is not a BinaryTree<int>; one is the name of a template (BinaryTree) and one is the name of a specific type of that template (BinaryTree<int>). You can't create instances of plain templates, you have to give it the type of template you want to use all the time.
Related
My preorder method don't work from main, but array elem has been formed rightly (I checked it with printing every step). All functions/methods used in definition work correctly. I think the problem occurs because of line "return elem;". Can anyone suggest any idea, it's too important.
T* TreeNode<T>::preorder()const
{
T* elem = new T[elCount(left)+elCount(right)+1];
elem[0] = data;
TreeNode<T>* curr = left;
Stack<TreeNode<T>*> st;
if (right) {
st.push(right);
}
int i = 1;
while (curr) {
elem[i++] = curr->getData();
//std::cout << elem[i - 1];
if (curr->getRight())
st.push(curr->getRight());
curr = curr->getLeft();
if (!curr)
{
curr = st.getTop();
st.pop();
} }
return elem;
}
It's a bit difficult to see exactly what you're trying to do as it wasn't specified, but it seems that you're trying to grab all the data from your binary tree. This GFG article does a really simple explanation and breakdown of how to transverse a binary tree. Obviously your nodes are more complicated, but the general logic is the same. I'd ask yourself as to whether the preorder() function really needs to be part of the tree node class and if a separate function wouldn't be a bit more useful. I'd also consider using a std::vector rather than the carray you're currently using. If you need the fixed size, std::array would probably also work better.
To show how you could possibly rewrite your code you can try something like
std::vector<int> vect;
template<class T>
void preorder(const TreeNode<T>& node, vector<T>& elem) {
if(!node.getData()) {
return;
}
elem.push(node.getData());
if(node.getLeft()) {
preorder(node.getLeft());
}
if(node.getRight()) {
preorder(node.getRight());
}
}
This isn't perfect as I wrote this off the top of my head, but it should provide an easy groundwork for traversing the binary tree and pulling out all the data. A little bit of recursion should make it a lot easier.
So as a novice programming I am trying to learn data structures and a question came in my mind while I was working on Binary trees. So the code/function to add a node to binary tree is:
//binary tree node addition
struct tree* addnode(int rdata)
{
struct tree* temp = new tree();
temp->data = rdata;
temp->right = NULL;
temp->left = NULL;
return temp;
}
Here we can see that there is only one parameter required in the addition of node i.e. we don't pass the root address in the function. But in addition of linked list the addition of node is at any place (Beginning, ending or after k nodes) has two parameters which are a headref pointer of linked list and the data value. Like code for adding a node in the starting of the linked list is :
void addatstartLL(struct LL** headref, int rdata) {
struct LL* temp = new LL();
temp->data = rdata;
temp->next = (*headref);
(*headref) = temp;
}
The above two codes are applied like this :
#include<iostream>
using namespace std;
struct LL {
int data;
struct LL* next;
};
struct tree {
int data;
struct tree* left;
struct tree* right;
};
int main()
{
struct tree* root = new tree();
root->data = 1;
root->left=addnode(2);
struct LL* head = NULL;
addatstartLL(&head, 2);
}
So, my question here why do we need only one parameter in binary tree (only data and not the root address cause) and two parameters in linked list i.e. headref and data? Why don't we write the same kind of function for both of the data structures? Thank you in advanced.
TLDR They are badly written functions.
Those functions are what you make them to be. If you make one take one argument and the other take 2 arguments then that's what it is. They are not standard functions and they are not well written functions either (in terms of both interface and implementation).
There are many problems with the code you have:
addnode doesn't actually add a node to a list. It just creates a node. That's why it takes one argument.
LL structure doesn't represent a linked list. It represents a node.
You use owning raw pointers everywhere so there is no clear owner of the memory allocated by new. You code will leak at the first exception, even if you explicitly delete the nodes. That's why you need to religiously follow RAII concept in C++.
struct tree* root = new tree(); There is absolutely no reason to dynamically allocate tree there in main. tree root{} would suffice.
structures are used in the most minimalist way possible, just the bare C capable way. In C++ - true C++ - you would use constructors, encapsulation, methods and so on.
This is by far not idiomatic, correct C++ code. It's C code (sprinkled with C++ IO) and compiled with a C++ compiler. If that's what your teacher requires then by all means write this for him/her to make them happy, but be aware that it's definitely not how you write correct, clean, idiomatic, modern C++ code. If you lean this from a tutorial or book then ditch it immediately and learn from a good C++ resource.
Your first function doesn't add a node to a tree. It creates a new tree of one node.
It can be used by a function that adds a node to a tree, once the location to add it is determined.
Your second function is adding a node to a list at a specific position. Comparable tree functions would be
void addnodebefore(tree** root, int rdata)
{
tree* temp = new tree();
temp->data = rdata;
temp->right = *root;
temp->left = nullptr;
*root = temp;
}
void addnodeafter(tree** root, int rdata)
{
tree* temp = new tree();
temp->data = rdata;
temp->right = nullptr;
temp->left = *root;
*root = temp;
}
There are STL containters similar to what you have, std::set is usually implemented as some type of sorted tree, while std::list is usually implemented as a circular doubly linked list with a dummy node used for the head and tail of the list.
To add a new element to std::set, std::set::insert(value) can be used, and it is a single parameter call.
To add a new element to std::list, std::list::push_front(value) or std::list::push_back(value) can be used, and they are single parameter calls.
Although these are single parameter calls, the container itself could be considered to be similar to having a second parameter. In other words, you could create static functions (not tied to a specific instance of a container) for insert, push_front, or push_back, that would take an instance of the container as one the parameters.
I tried searching for this problem on stackoverflow but couldn't find it, so pardon me if it already existed.
So, what I wish to do is to create a function that traverses a tree and returns a pointer to the Node with the highest value. The Tree would be unordered and asymmetric, and will not have a fixed depth. Each node has a pointer to its Parent node, a list containing its Child nodes, and an integer named 'value'. And the tree would have a pointer to its root node, like this:
struct Node
{
private:
Node* parent;
list<Node> childs;
int value;
public:
// Getters, setters and constructors
}
struct Tree
{
private:
Node* root;
public:
// Getters, setters and constructors
}
And, as I stated before, I wish to make a function that traverses the entire tree, aka every single Node in the entire tree regardless of the depth, and returns a pointer to the node with the highest value. I assume it'll require recursion, but I can't figure out a way to do this.
Pardon me if my question seems dumb / stupid, but I really need help
You can use recursive method, which returns the pointer to the node with maximal value of current and child nodes:
struct Node
{
...
Node* getMaxNode()
{
Node* maxNode = this;
for (auto& child : this->childs) {
Node* childsMaxNode = child.getMaxNode();
if (childsMaxNode->getValue() > maxNode->getValue())
maxNode = childsMaxNode;
}
return maxNode;
}
}
If current node doesn't have child nodes, it will return pointer to the current node. So, in struct Tree you can implement something like this:
struct Tree
{
Node* getMax()
{
return this->root->getMaxNode();
}
}
Here's a simplified version of my Node class :
class Node {
public:
Node();
// indicators of whether the node is a top or bottom node
bool Top;
bool Bot;
// pointers for tree structure
Node *Parent;
Node *LeftC;
Node *RightC;
std::list<Node*> getNodesList();
};
What I want is be able to get a list of pointers to the nodes in my tree in a certain order. I tried the following code to do this :
std::list<Node*> Node::getNodesList(){
if (Bot) return (std::list<Node*>(1,this));
else {
std::list<Node*> temp (1,this);
temp.splice(temp.end(), LeftC->getNodesVector()); // Combine with left childrens
temp.splice(temp.end(), RightC->getNodesVector()); // Combine with right childrens
return temp;
}
}
The splice function doesn't work and give me an error.
So my questions are :
Why isn't the splice function working to combine the lists?
Is there a more efficient way to return the list of pointers to the nodes?
Since I do not know the exact error you have, just a quick glance at your code tells me that your Node class probably doesn't know what getNodesVector() is since it isn't defined in your class.
Let's say I'm using a non-standard linked-list class, List.h. This class is functioning, template'd and has the typical features of add/remove to front and add/remove to back, isEmpty(), etc.
This list does not have any begin() and end() functionality. Also, does a linked-list class have to include iterator functionality? Or is that something I can create on my own when I create a new List?
I'm used to working with STL, so I would usually use this code:
typedef vector<OBJECT>::iterator QuoteIt;
for(QuoteIt i = deposits.begin(); i != deposits.end(); ++i)
Anyway, lets say I create a new "List".
List<int>deposits;
or even a List of Objects
List<OBJECT>deposits;
So let's say I addToBack() 20 different integers, so that creates the appropriate # of new nodes.
Now, how can I traverse this list so I can find a sum of all these ints? Is that possible, or does my current functionality prevent that? I would have to implement some sort of iterator to my List Class?
Now I know I could keep an outside variable, every time I do an addToBack() call to keep track of my sums. However, I want the code to be compatible with Lists of Objects as well. (I want to be able to search one value in a node, and retrieve another value in the same node eventually)
I'm so used to working with stl::list and creating a for loop with iterators, I really dont' know how to get this working with other classes.
btw here is the code for List():
template<class NODETYPE>
class List{
public:
List();
~List();
void insertAtFront(const NODETYPE &);
void insertAtBack(const NODETYPE &);
bool removeFromFront( NODETYPE &);
bool removeFromBack( NODETYPE &);
bool isEmpty() const;
private:
ListNode< NODETYPE > *firstPtr; //pointer to first node
ListNode< NODETYPE > *lastPtr;
//Function to allocate a new node
ListNode< NODETYPE > *getNewNode ( const NODETYPE &);
};
//default constructor
template <class NODETYPE>
List< NODETYPE > ::List()
: firstPtr(0),
lastPtr(0)
{
cout<<"Creating Nodes! \n\n!"<<endl;
}
//deconstructor
template <class NODETYPE>
List<NODETYPE>::~List(){
if(!isEmpty() ){
cout<<"Destroying nodes!"<<endl;
ListNode<NODETYPE> *currentPtr=firstPtr;
ListNode<NODETYPE> *tempPtr;
while( currentPtr !=0){
tempPtr = currentPtr;
currentPtr=currentPtr->nextPtr;
delete tempPtr;
}
}
cout<<"All nodes destroyed! \n\n";
}
template <class NODETYPE>
bool List <NODETYPE>::removeFromFront( NODETYPE & value){
if ( isEmpty() )
return false;
else{
ListNode<NODETYPE> *tempPtr = firstPtr;
if (firstPtr== lastPtr)
firstPtr=lastPtr = 0;
else
firstPtr=firstPtr->nextPtr;
value = tempPtr->data;
delete tempPtr;
return true;
}
}
template <class NODETYPE>
bool List<NODETYPE>::removeFromBack(NODETYPE &value)
{
if (isEmpty())
return false;
else{
ListNode< NODETYPE> *tempPtr = lastPtr;
if( firstPtr == lastPtr)
firstPtr = lastPtr = 0;
else{
ListNode<NODETYPE> *currentPtr=firstPtr;
//Finds second to last element
while(currentPtr->nextPtr !=lastPtr)
currentPtr=currentPtr->nextPtr;
lastPtr = currentPtr;
currentPtr->nextPtr=0;
}
value = tempPtr->data;
delete tempPtr;
return true;
}
}
//Checks to see if list is empty
template< class NODETYPE>
bool List< NODETYPE >::isEmpty() const{
return firstPtr == 0;
}
//returns a pointer to newly created Node
template<class NODETYPE>
ListNode<NODETYPE> *List<NODETYPE>::getNewNode(const NODETYPE &value){
return new ListNode<NODETYPE>(value);
}
In response to:
Now, how can I traverse this list so I can find a sum of all these ints? Is that possible, or does my current functionality prevent that? I would have to implement some sort of iterator to my List Class?
You need to implement a way to iterate over your list that does not (as a side-effect) destroy your list.
In response to:
Now, how can I traverse this list so I
can find a sum of all these ints? Is
that possible, or does my current
functionality prevent that? I would
have to implement some sort of
iterator to my List Class?
No matter how you design a linked list, you must have some sort of pointer to the beginning of the list, and you have to have a way of knowing when you are at the end (e.g. when "next" is null, or by having a pointer to the end). By exposing those data one way or another, you can always set up a list traversal:
Start at the beginning. (In your case, get a hold of firstPtr.)
If you are not at the end, move to the next element. (In your case, get ->nextPtr.)
Using that pattern to accumulate a value as you visit each element you should be able to handle your task with ease.
If your list does not give you public access to its beginning, then it is certainly not a general-purpose list!
You can approach this many ways. You can either choose to create your own iterator or give public access to the list's head.
Option 1 is compatible with stl lists so you might want to go that route. An iterator is essentially a ptr that overrides the inc and dec operators to go to the next or previous position in the list.
If you studied basic data structures at all, you would know that traversing a list is trivial.
Node<type> t = head;
while (t != NULL)
{
// process node here
t = t->next;
}
The code can differ depending on if you use dummy nodes at all.
Since there is no functionality to just get the node without removing it from the list, you can't simply make an "add-on" iterator without changing the List class. The least you would need to do is to either
friend the external ListIterator class
friend free begin and end functions
add begin and end functions to the List class
Without any of those three, you can't achieve what you want.
Your list seems to have 2 ways of iterating it (forwards and backwards)
List<int>deposits;
.. add stuff:
int o;
int sum = 0;
while(deposits.removeFromFront(o)) {
sum+=o;
}
The bad thing though, is that iterating it, you also destroy the list,
you could provide public accessors to List::firstPtr and ListNode::nextPtr in which case you could do:
List<int>deposits;
.. add stuff:
int sum = 0;
for(ListNode<int> *ptr = deposits.firstPtr; ptr ; ptr = ptr->nextPtr)
sum+=ptr->data;
However, use an existing STL container if you can.