Postorder Traversal of Tree iterative method - data-structures

I am trying to implement postorder traversal of tree using 2 stacks using iterative method. I have implementated the right algorithm. But still didn't getting output, getting error as, Segmentation fault (core dumped).
Where I have done wrong can anyone tell me ?
void postorder_iterative(struct node *root)
{
struct node *stack1[15],*stack2[15];
int top1=-1,top2 =-1;
root = stack1[++top1];
while(top1>=0)
{
root = stack1[top1--];
stack2[++top2] =root;
if(root->left != NULL)
stack1[++top1] = root->left;
if(root->right != NULL)
stack1[++top1] = root->right;
}
while(top2>=0)
printf("%c\t",stack2[top2--]->data);
}

You are reading an undefined value with this statement, in the first iteration of the loop:
root = stack1[top1--];
This first stack element is undefined, because you never initialised it. It was supposed to get initialised here:
root = stack1[++top1];
But this does not put anything in the stack. Instead it overwrites root with an undefined value.
It should have been the reversed:
stack1[++top1] = root;
This fixes the issue.
Don't forget to print a new line character once you have printed the list, so nothing is pending in the buffer.

Related

Modified height-balanced tree algorithm

I need to find if a binary tree is height-balanced but instead of considering the paths from root to leaf I need to consider the paths from root to a node that has either left or right child null.
This is the logic of my algorithm in pseudo-code:
bool isBalanced=true //to know if the tree is balanced or not a flag is used
void findBalance(root,currentDepth,shortestPathDepth){
if(root==null){
return;
}
if(root->left_child=null or root->right_child=null) //if the last node of a path has been found
if(shortestPathDepth=-1) //if this is the first end of a path that has been found
shortestPathDepth=currentDepth //it will be used as comparison value for all the other paths
else //if the end of a path was already found before
if(currentDepth>shortestPathDepth+1) // if the condition of height-balance is not fulfilled
isBalanced=false;
return;
//traverse the rest of the nodes keeping track of the depth of the nodes and the value of the path that
//will be used for the condition
findBalance(root->left,currentDepth+1,shortestPathDepth);
findBalance(root->right,currentDepth+1,shortestPathDepth);
I'm looking for help to understand what is wrong with this logic.
Edit
The real code:
void findBalance(Node node,int currentDepth,int* pathDepth,int* flag){
if(node==nullptr || *flag==0){
return;
}
if(node->left==nullptr || node->right==nullptr){
if(*pathDepth==-1){
*pathDepth=currentDepth;
}
else{
if(currentDepth>pathDepth+1){
*flag=0;
}
}
}
findBalance(node->left,currentDepth+1,pathDepth,flag);
findBalance(node->right,currentDepth+1,pathDepth,flag);
}
bool isBalanced(Node root){
if(root==nullptr){
return true;
}
int flag=1;
int pathDepth=-1;
findBalance(u,0,&pathDepth,&flag);
return flag;
}

Segmentation fault after calling reset on unique_ptr

I'm getting a segmentation fault while calling reset on unique_ptr:
Node* tree::left_rotate(Node* node) {
Node* temp = node->right.get();
node->right.reset(temp->left.get());
temp->left.reset(node); // **Here is segmentation fault happens**
if(node->right.get()) {
node->right->parent = node;
}
temp->parent = node->parent;
if(node->parent) {
if(node == node->parent->left.get()) {
node->parent->left.reset(temp);
node->parent = node->parent->left.get();
} else if(node == node->parent->right.get()) {
node->parent->right.reset(temp);
node->parent = node->parent->right.get();
}
}
return temp;
}
Node has the following structure:
class Node {
public:
int data;
Node* parent;
std::unique_ptr<Node> left;
std::unique_ptr<Node> right;
public:
Node() : data(0) {
}
explicit Node(int d) : data(d),
parent(nullptr),
left(nullptr),
right(nullptr) {}
};
gdb reports:
Thread 1 received signal SIGSEGV, Segmentation fault. 0x00404ae5 in
std::unique_ptr >::~unique_ptr (
this=0xfeeefefa, __in_chrg=)
at C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/unique_ptr.h:273
273 if (__ptr != nullptr)
The report from one stack-frame upper:
#2 0x004047e8 in std::default_delete<Node>::operator() (this=0xfe1de4,
__ptr=0xfeeefeee)
at C:/Program Files (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/lib/gcc/i686-w64-mingw32/8.1.0/include/c++/bits/unique_ptr.h:81
81 delete __ptr;
So it seems here is double deletion. How this issue can be solved? Maybe it worths to have a temp pointer as a shared_ptr?
Node* temp = node->right.get();
temp is a raw pointer to the node's right node
node->right.reset(temp->left.get());
the node's right node is reset to the temp's left node, thus the original node's right node (to which temp points) gets deleted. That means that the temp raw pointer is now pointing to a deleted node.
temp->left.reset(node); // **Here is segmentation fault happens**
As temp is deleted, dereferencing it to get it's left node lead to bad things.
A quick thought, maybe use release() instead of get() at the first place to take over ownership of the node's right node ?

Implementing an Iterative Single Stack Binary Tree Copy Function

As a thought exercise I am trying to implement an iterative tree (binary or binary search tree) copy function.
It is my understanding that it can be achieved trivially:
with a single stack
without using a wrapper (that contains references to the copy and original nodes)
without a node having a reference to it's parent (would a parent reference in a node be counter to a true definition of a tree [which I believe is a DAG]?)
I have written different implementations that meet the inverse of the above constraints but I am uncertain how to approach the problem with the constraints.
I did not see anything in Algorithms 4/e and have not seen anything online (beyond statements of how trivial it is). I considered using the concepts from in order and post order of a current/previous var but I did not see a way to track accurately when popping the stack. I also briefly considered a hash map but I feel this is still just extra storage like the extra stack.
Any help in understanding the concepts/idioms behind the approach that I am not seeing is gratefully received.
Thanks in advance.
Edit:
Some requests for what I've tried so far. Here is the 2 stack solution which I believe is supposed to be able to turn into the 1 stack the most trivially.
It's written in C++. I am new to the language (but not programming) and teaching myself using C++ Primer 5/e (Lippman, Lajole, Moo) [C++11] and the internet. If any of the code from a language perspective is wrong, please let me know (although I'm aware Code Review Stack Exchange is the place for an actual review).
I have a template Node that is used by other parts of the code.
template<typename T>
struct Node;
typedef Node<std::string> tree_node;
typedef std::shared_ptr<tree_node> shared_ptr_node;
template<typename T>
struct Node final {
public:
const T value;
const shared_ptr_node &left = m_left;
const shared_ptr_node &right = m_right;
Node(const T value, const shared_ptr_node left = nullptr, const shared_ptr_node right = nullptr) : value(value), m_left(left), m_right (right) {}
void updateLeft(const shared_ptr_node node) {
m_left = node;
}
void updateRight(const shared_ptr_node node) {
m_right = node;
}
private:
shared_ptr_node m_left;
shared_ptr_node m_right;
};
And then the 2 stack implementation.
shared_ptr_node iterativeCopy2Stacks(const shared_ptr_node &node) {
const shared_ptr_node newRoot = std::make_shared<tree_node>(node->value);
std::stack<const shared_ptr_node> s;
s.push(node);
std::stack<const shared_ptr_node> copyS;
copyS.push(newRoot);
shared_ptr_node original = nullptr;
shared_ptr_node copy = nullptr;
while (!s.empty()) {
original = s.top();
s.pop();
copy = copyS.top();
copyS.pop();
if (original->right) {
s.push(original->right);
copy->updateRight(std::make_shared<tree_node>(original->right->value));
copyS.push(copy->right);
}
if (original->left) {
s.push(original->left);
copy->updateLeft(std::make_shared<tree_node>(original->left->value));
copyS.push(copy->left);
}
}
return newRoot;
}
I'm not fluent in c++, so you'll have to settle with pseudocode:
node copy(treenode n):
if n == null
return null
node tmp = clone(n) //no deep clone!!!
stack s
s.push(tmp)
while !s.empty():
node n = s.pop()
if n.left != null:
n.left = clone(n.left)
s.push(n.left)
if n.right != null:
n.right = clone(n.right)
s.push(n.right)
return tmp
Note that clone(node) is not a deep-clone. The basic idea is to start with a shallow-clone of the root, then iterate over all children of that node and replace those nodes (still references to the original node) by shallow copies, replace those nodes children, etc.. This algorithm traverses the tree in a DFS-manner. In case you prefer BFS (for whatever reason) you could just replace the stack by a queue. Another advantage of this code: it can be altered with a few minor changes to work for arbitrary trees.
A recursive version of this algorithm (in case you prefer recursive code over my horrible prosa):
node copyRec(node n):
if n.left != null:
n.left = clone(n.left)
copyRec(n.left)
if n.right != null:
n.right = clone(n.right)
copyRec(n.right)
return n
node copy(node n):
return copyRec(clone(n))
EDIT:
If you want to have a look at working code, I've created an implementation in python.

Why does this LinkedList sorting algorithm work?

I've been working on an algorithm to add elements to a linked list, and sort it when it adds the element. My code works, and I know why for the most part, but I was surprised to see this code worked for adding elements at the end of the list. Here's the code:
public void add(int value)
{
Node currentNode;
Node previousNode;
Node newNode;
if(firstNode == null)
{
firstNode = new Node(value,firstNode);
}
else
{
currentNode = firstNode;
previousNode = null;
while(currentNode != null && value > currentNode.getValue())
{
previousNode = currentNode;
currentNode = currentNode.getNextNode();
}
if(previousNode == null)
{
firstNode = new Node(value, firstNode);
}
else
{
newNode = new Node(value,currentNode);
previousNode.setNextNode(newNode);
}
}
}
So I know this would work for adding to the beginning or the middle, but how does it add to the end? I mean, if the while loop traverses to the end of the list, then currentNode is the last node, previous node is one before, so wouldn't:
newNode = new Node(value,currentNode);
previousNode.setNextNode(newNode);
never add the element to the end? Wouldn't it always add the new node between previous and current?
previousNode, as name suggests, points to a node behind current node.
When you reach the end, (This happens when value you are trying to insert is larger than any of the current elements) currentNode becomes null, but previousNode is pointing to last node. Hence previousNode.setNextNode(newNode) works fine.

Linux Kernel - Red/Black Trees

I'm trying to implement a red/black tree in Linux per task_struct using code from linux/rbtree.h. I can get a red/black tree inserting properly in a standalone space in the kernel such as a module but when I try to get the same code to function with the rb_root declared in either task_struct or task_struct->files_struct, I get a SEGFAULT everytime I try an insert.
Here's some code:
In task_struct I create a rb_root struct for my tree (not a pointer).
In init_task.h, macro INIT_TASK(tsk), I set this equal to RB_ROOT.
To do an insert, I use this code:
rb_insert(&(current->fd_tree), &rbnode);
This is where the issue occurs.
My insert command is the standard insert that is documented in all RBTree documentation for the kernel:
int my_insert(struct rb_root *root, struct mytype *data)
{
struct rb_node **new = &(root->rb_node), *parent = NULL;
/* Figure out where to put new node */
while (*new) {
struct mytype *this = container_of(*new, struct mytype, node);
int result = strcmp(data->keystring, this->keystring);
parent = *new;
if (result < 0)
new = &((*new)->rb_left);
else if (result > 0)
new = &((*new)->rb_right);
else
return FALSE;
}
/* Add new node and rebalance tree. */
rb_link_node(&data->node, parent, new);
rb_insert_color(&data->node, root);
return TRUE;
}
Is there something I'm missing?
Some reason this would work fine if I made a tree root outside of task_struct? If I make rb_root inside of a module this insert works fine. But once I put the actual tree root in the task_struct or even in the task_struct->files_struct, I get a SEGFAULT. Can a root node not be added in these structs?
Any tips are greatly appreciated. I've tried nearly everything I can think of.
Edit:
I get a SEGFAULT on the following line when trying to print and any line that accesses the tree. With this line you should get the understanding of how I'm handling the pointers. rb_entry and rb_first are methods already available in the kernel. current is a pointer to a task struct (current working process) and tree is my root node (not a pointer) which is a member of the task struct (I added). rb_first needs to pass a pointer *rb_root. I'm doing this wrong.
printk(KERN_CRIT "node=%d\n", rb_entry(rb_first(&(current->tree)), struct rb_tree_struct, node)->fd_key);
Could it be the pointer values of root and/or data aren't what you expect? It might be useful to add
printk("%s: root=%p data=%p\n", __func__, root, data);
before the while() loop.

Resources