C++ how should I structure a tree - c++

I am currently working on a large data tree. I need to navigate the tree, return a subnode and change its value.
class Node {
short value;
std::vector<Node> children;
Node walk(int step) {
return children[step];
}
}
Will the return of the Walk function create a copy of the child Node or do I have to return a pointer? How should I Link the Nodes?
also another question:
what's the difference between these two and which should I use to create new nodes:
Node newNode;
// or
Node newNode = *new Node();
Edit
I tried std::vector<Node*> children; but this lead to memory leaks when deleting. Would Node& walk(int step) work too without using pointers?

To prevent memory leaks and keep your code clean, you can use shared pointers. Return weak pointer from walk function. We must return the weak pointer so as not to make the client the owner of a particular node.
#include<memory>
#include<vector>
class Node;
using NodePtr = std::shared_ptr<Node>;
using NodeWPtr = std::weak_ptr<Node>;
class Node {
short value;
std::vector<NodePtr> children;
NodeWPtr walk(int step) {
//Your Algorithm.
return children[step];
}
};
Node newNode = *new Node(); creates a Node on the heap and then copies it to a node on the stack. This however, has memory leak and it does not do anything significantly different than just creating a node directly on the stack.
Node newNode; creates Node object on the stack. I would suggest you use this as it directly describes your intent.
Some people have suggested the use of std::unique_ptr instead of std::shared_ptr because std::shared_ptr has a large overhead. However, if we do use std::unique_ptr, we would have to return an std::observer_ptr from the walk function which is not fully implemented in the latest c++ compilers as far as I know.
EDIT
The following 2 class designs are noteworthy of consideration according to the discussions in the comments.
//Without storing any pointers in the vector
class Node {
short value;
std::vector<Node> children;
Node* walk(int step) {
//Your Algorithm.
return &children[step];
}
};
or
//Using unique_ptr
class Node;
using NodePtr = std::unique_ptr<Node>;
class Node {
short value;
std::vector<NodePtr> children;
Node* walk(int step) {
//Your Algorithm.
return children[step].get();
}
};

Related

Why do we need, One parameter is required in adding a node in binary tree; where as two parameters are required in adding a node in linked list?(C++)

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.

Freeing memory Binary trees

I have a function that creates a binary tree(*build_tree)* (Huffman).
I also need a function that free's the memory that build tree allocated.
It's my first time working with binary trees so I'm kind of confused.
Should I create a loop that goes through each node in the tree and deletes it?
Should I consider if the node is a leaf or a parent node?
void free_memory(NodePtr root)
{
delete root;
}
struct HuffmanNode
{
//some stuff
HuffmanNode *left;
HuffmanNode *right;
};
Would appreciate it if someone could help me get started :)
If you use smart pointers the problem will solve itself. If each node contains a private SP to it's children and you delete a node all it's children will also be freed. Obviously your class destructor, which will get called by the SP when it cleans up will need to free any other non RIIA allocated resources if any exist.
class Node
{
private:
std:unique_ptr<Node> left;
std:unique_ptr<Node> right;
}
I'm using std::unique_ptr<> here because I'm assuming that these are private and not exposed to other parts of your program. If you want other things to reference nodes using these pointers then you should use std::shared_ptr<>.
If you're not using SP then the class destructor needs to do the work itself and you have to be much more careful about memory leaks. Each class destructor deletes its children, which in turn will call the destructor in each child.
class Node
{
private:
NodePtr left;
NodePtr right;
~Node()
{
delete left;
delete right;
// Delete any other resources allocated by the node.
}
}
You can also do as #OldProgrammer suggests and traverse the tree bottom up deleting nodes as you go. Remember you have to do this bottom up. If you did it top down then you would loose the reference to the (as yet) undeleted child nodes and leak memory. As you can see the code for recursive deletion (as referenced in #unluddite's answer) is a lot more complex.
There is a memory overhead for doing (anything) recursively. See: Is a recursive destructor for linked list, tree, etc. bad?. If your tree is very large then you should consider this and test accordingly.
My recommendation would be for the first solution if you are OK with using SP.
If you implement a post-order tree traversal and delete the node and data at the process step, you will ensure that each node of your tree is visited and the data deleted.
You can see a recursive and iterative example here with the relevant code reproduced below.
Recursive solution:
void postOrderTraversal(BinaryTree *p) {
if (!p) return;
postOrderTraversal(p->left);
postOrderTraversal(p->right);
// this is where we delete
delete p->data;
delete p;
}
One possible iterative solution:
void postOrderTraversalIterative(BinaryTree *root) {
if (!root) return;
stack<BinaryTree*> s;
s.push(root);
BinaryTree *prev = NULL;
while (!s.empty()) {
BinaryTree *curr = s.top();
if (!prev || prev->left == curr || prev->right == curr) {
if (curr->left)
s.push(curr->left);
else if (curr->right)
s.push(curr->right);
} else if (curr->left == prev) {
if (curr->right)
s.push(curr->right);
} else {
// this is where we delete
delete curr->data;
delete curr;
s.pop();
}
prev = curr;
}
}

Why should Next() operation of a singly linked list be protected with a critical section?

I'm reading the book Multithreading Applications in Win32
The book says return node->next will be compiled into separate machine instructions that would not be executed as an atomic operation, so Next() should also be protected by the critical section.
My question is, what instructions could it be translated into, to cause a race condition?
typedef struct _Node
{
struct Node *next;
int data;
} Node;
typedef struct _List
{
Node *head;
CRITICAL SECTION critical_sec;
} List;
List *CreateList()
{
List *pList = malloc(sizeof(List));
pList->head = NULL;
InitializeCriticalSection(&pList->critical_sec);
return pList;
}
void DeleteList(List *pList)
{
DeleteCriticalSection(&pList->critical_sec);
free(pList);
}
void AddHead(List *pList, Node *node)
{
EnterCriticalSection(&pList->critical_sec);
node->next = pList->head;
pList->head = node;
LeaveCriticalSection(&pList->critical_sec);
}
void Insert(List *pList, Node *afterNode, Node *newNode)
{
EnterCriticalSection(&pList->critical_sec);
if (afterNode == NULL)
{
AddHead(pList, newNode);
}
else
{
newNode->next = afterNode->next;
afterNode->next = newNode;
}
LeaveCriticalSection(&pList->critical_sec);
}
Node *Next(List *pList, Node *node)
{
Node* next;
EnterCriticalSection(&pList->critical_sec);
next = node->next;
LeaveCriticalSection(&pList->critical_sec);
return next;
}
Edit:
OK, although in this particular case it won't corrupt the singly linked list w/o protecting the Next() operation, a shared structure should be protected as a whole or nothing, generally.
return node->next performs two operations; it first loads the struct pointed to by node into memory, then looks at the node+offsetof(next) to find the pointer next, load that into a register, and then return to the calling program. The contents of node may be manipulated by another thread of execution in the meantime.
Yes, you absolutely need to protect your "next" with a lock in a multithreaded application.
... HOWEVER ...
"Writers" (like add or remove node) MUST be mutually exclusive. Critical section is a good choice.
"Readers" (like "next") can run concurrently with each other.
SUGGESTION:
If you can target Windows Vista or higher, consider using an SRW lock instead:
http://msdn.microsoft.com/en-us/library/aa904937%28VS.85%29.aspx
http://msdn.microsoft.com/en-us/magazine/cc163405.aspx
While I think the answer by sarnold is correct, I just wanted to point out that the sizeof() call in your malloc() call in CreateList appears to have a bug. I believe it should be:
List *pList = malloc(sizeof(List));
The way you had it, you will create enough memory to hold a pointer to a List and not the List structure. (You may also want to cast the return type to (List*) and compare it to NULL before using it..)

How to delete a binary search tree from memory?

I have a BST which is a linked list in C++. How would I delete the whole thing from memory? Would it be done from a class function?
Just delete the children:
struct TreeNode {
TreeNode *l, *r, *parent;
Data d;
TreeNode( TreeNode *p ) { l = nullptr; r = nullptr; parent = p; }
TreeNode( TreeNode const & ) = delete;
~TreeNode() {
delete l; // delete does nothing if ptr is 0
delete r; // or recurses if there's an object
}
};
or if you're using unique_ptr or some such, that's not even needed:
struct TreeNode {
unique_ptr< TreeNode > l, r;
TreeNode *parent;
Data d;
TreeNode( TreeNode *p ) { l = nullptr; r = nullptr; parent = p; }
TreeNode( TreeNode const & ) = delete;
~TreeNode() = default;
};
If you have access to the linked list itself, it's a piece of cake:
// Making liberal assumptions about the kind of naming / coding conventions that might have been used...
ListNode *currentNode = rootNode;
while(currentNode != NULL)
{
ListNode *nextNode = currentNode->Next;
delete currentNode;
currentNode = nextNode;
}
rootNode = NULL;
If this is a custom implemention of a BST, then this may well be how it works internally, if it has tied itself to a particular data structure.
If you don't have access to the internals, then Potatoswatter's answer should be spot on. Assuming the BST is setup as they suggest, then simply deleting the root node should automatically delete all the allocated memory as each parent down the tree will delete its children.
If you are asking how to go about iterating across a binary tree manually, then you would do the following recursive step:
void DeleteChildren(BSTNode *node)
{
// Recurse left down the tree...
if(node->HasLeftChild()) DeleteChildren(node->GetLeftChild());
// Recurse right down the tree...
if(node->HasRightChild()) DeleteChildren(node->GetRightChild());
// Clean up the data at this node.
node->ClearData(); // assume deletes internal data
// Free memory used by the node itself.
delete node;
}
// Call this from external code.
DeleteChildren(rootNode);
I hope I've not missed the point here and that something of this helps.
Perform a post-order traversal of the tree (i.e. visiting children before parents), and delete each node as you visit it.
Whether or not this has anything to do with classes depends entirely on your implementation.
With the limited information provided ....
If you allocated the nodes with new or malloc (or related functions) than you need to traverse over all the nodes and free or delete them.
An alternative is to put shared_ptr's (and weak_ptr's to kill cyclics) in your allocations -- provided you do it correctly you won't have to free the nodes manually
If you used a quality implementation that you picked up on the internet than provided the classes don't leak, you don't have to worry about anything.
Use smart pointers and forget about it.

C++ linked list memory management

I'm attempting to craft my own basic singly linked list in C++ as a learning exercise, and I'm encountering some difficulty in the memory management department. As it stands I have...
A 'Node' class:
class Node
{
public:
char *value;
Node *next;
Node();
~Node();
};
Node::Node()
{
}
Node::~Node()
{
delete[] value;
}
And then my list (I've omitted certain method calls for brevity):
class LinkedList
{
private:
Node *head;
public:
LinkedList();
~LinkedList();
void Add(char **x);
};
LinkedList::LinkedList()
{
head = 0;
}
LinkedList::~LinkedList()
{
Node *temp;
Node *current = head;
while(current)
{
temp = current;
current = current->next;
delete temp;
}
}
void LinkedList::Add(char **x)
{
Node *nodeToAdd = new Node();
nodeToAdd->value = *x;
nodeToAdd->next = NULL;
Node *current = head;
if(!head)
{
head = nodeToAdd;
return;
}
while(current->next)
{
current = current->next;
}
current->next = nodeToAdd;
}
I'm attempting to use this code as follows (again I've omitted things for brevity):
int main()
{
LinkedList *list = new LinkedList();
char *alpha = "alpha";
char *beta = "beta";
char *charlie = "charlie";
char *delta = "delta";
char *echo = "echo";
list->Add(&alpha);
list->Add(&beta);
list->Add(&charlie);
list->Add(&delta);
list->Add(&echo);
delete list;
}
The last call in main to delete the list produces an error:
Debug Assertion Failed! Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
What am I doing wrong here?
The data pointed to by the various Node::value aren't dynamically allocated, so you shouldn't delete them. Applying the concept of "ownership", nodes should either make their own copies of data, which they own and can delete, or nodes don't own data, so they shouldn't be responsible for deleting it.
You can also implement multiple ownership using reference counting, like Objective-C does (see Objective-C Memory Management Rules for more info) but you have to be careful to avoid ownership cycles. You often find some type of reference counting in third-party smart pointers, such as Boost's smart_ptr library. Since you're doing this for the learning experience, it may make more sense to roll your own than use a library. Of course, you could also use a library for now, letting you focus on whatever you're trying to learn.
One day a student came to Moon and said: “I understand how to make a better garbage collector. We must keep a reference count of the pointers to each cons.”
Moon patiently told the student the following story:
“One day a student came to Moon and said: ‘I understand how to make a better garbage collector...
you are trying to release the memory which is not allocated on heap.
char *alpha = "alpha"; --- not allocated on heap
calling delete[]in Node destructor would lead to heap corruption.
Some points:
1) initialize pointers properly in the constructor:
Node::Node():value(NULL),next(NULL)
{
}
2) Take a ownership of value.
Allocate the memory on heap and copy
the contents
You shouldn't release a pointer use delete[]/delete if it's not created by new operator. There are some actions under the hood for the delete[] operation, like releasing/reclaiming marked memory from a managed pool. Since your pointer doesn't belong to these stuff, there will be a problem. IMHO, the underlying delete[] code is the _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) stuff.
The problem is that you're assuming that you can delete the data inside node, but you're passing in pointers to string literals instead, which you can't delete.
If you're assuming that the Node object controls the lifetime of the data inside it, your Node constructor or the Add function in LinkedList will have to make a copy of the data that it is being passed.
In your destructor, you are trying to array delete (delete [ ]) a static string. You have change your Add function to reserve the string and copy it first. See the code below.
However, if I were you and fairly new to memory management, I'd really use something like CString instead of a raw "char *" as it's much easier to deal with.
void LinkedList::Add(const char *x)
{
Node *nodeToAdd = new Node();
int len=strlen(x);
nodeToAdd->value = new char [len+1]; // room for string + terminating 0
strcpy(nodeToAdd->value,x);
nodeToAdd->next = NULL;
Node *current = head;
if(!head)
{
head = nodeToAdd;
return;
}
while(current->next)
{
current = current->next;
}
current->next = nodeToAdd;
}
value and next in Node class doesn't have memory allocated. You should allocate memory in Node's constructor.