Problem with Stack based Euler-Tree-traversal
I want a function that traverses a binary tree with the Euler traversal (this is how it works). Of course this is easily achievable with recursion - I know how that works. But now I want to implement an iterative version of this algorithm using a stack instead of recursion. My idea was to store the direction we are traversing on the stack as well. My code is not working and I can somehow not wrap my mind around this problem. Can you give me any hints on how to tackle this issue? Here is my code so far:
#define LEFT (struct Node*) 0xBADF00D
#define RIGHT (struct Node*) 0xDEADBEEF
struct Node {
int data;
struct Node* parent;
struct Node* left;
struct Node* right;
};
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
s.push(RIGHT);
s.push(root);
s.push(LEFT);
while(!s.empty()) {
struct Node* direction = s.top(); s.pop();
struct Node* node = s.top(); s.pop();
visit(node);
if(direction == LEFT) {
if(node->left) {
s.push(node->left);
s.push(RIGHT);
s.push(node->left);
s.push(LEFT);
}
}
if(direction == RIGHT) {
if(node->right) {
s.push(node->right);
s.push(RIGHT);
s.push(node->right);
s.push(LEFT);
}
}
}
}
algorithm data-structures tree binary-tree tree-traversal
add a comment |
I want a function that traverses a binary tree with the Euler traversal (this is how it works). Of course this is easily achievable with recursion - I know how that works. But now I want to implement an iterative version of this algorithm using a stack instead of recursion. My idea was to store the direction we are traversing on the stack as well. My code is not working and I can somehow not wrap my mind around this problem. Can you give me any hints on how to tackle this issue? Here is my code so far:
#define LEFT (struct Node*) 0xBADF00D
#define RIGHT (struct Node*) 0xDEADBEEF
struct Node {
int data;
struct Node* parent;
struct Node* left;
struct Node* right;
};
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
s.push(RIGHT);
s.push(root);
s.push(LEFT);
while(!s.empty()) {
struct Node* direction = s.top(); s.pop();
struct Node* node = s.top(); s.pop();
visit(node);
if(direction == LEFT) {
if(node->left) {
s.push(node->left);
s.push(RIGHT);
s.push(node->left);
s.push(LEFT);
}
}
if(direction == RIGHT) {
if(node->right) {
s.push(node->right);
s.push(RIGHT);
s.push(node->right);
s.push(LEFT);
}
}
}
}
algorithm data-structures tree binary-tree tree-traversal
The easiest way to convert a recursive function into an iterative one is to use a stack in your loop to mimic recursive calls. In fact, that's exactly what happens when you recursively call the same function, except now you're using a stack explicitly instead of using the call stack for your computation.
– Jochem Kuijpers
Nov 21 '18 at 1:10
A suggestion: instead of the unsafe pointer casts, declare two otherwise unused global variables of type Node.
– David Eisenstat
Nov 21 '18 at 3:50
add a comment |
I want a function that traverses a binary tree with the Euler traversal (this is how it works). Of course this is easily achievable with recursion - I know how that works. But now I want to implement an iterative version of this algorithm using a stack instead of recursion. My idea was to store the direction we are traversing on the stack as well. My code is not working and I can somehow not wrap my mind around this problem. Can you give me any hints on how to tackle this issue? Here is my code so far:
#define LEFT (struct Node*) 0xBADF00D
#define RIGHT (struct Node*) 0xDEADBEEF
struct Node {
int data;
struct Node* parent;
struct Node* left;
struct Node* right;
};
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
s.push(RIGHT);
s.push(root);
s.push(LEFT);
while(!s.empty()) {
struct Node* direction = s.top(); s.pop();
struct Node* node = s.top(); s.pop();
visit(node);
if(direction == LEFT) {
if(node->left) {
s.push(node->left);
s.push(RIGHT);
s.push(node->left);
s.push(LEFT);
}
}
if(direction == RIGHT) {
if(node->right) {
s.push(node->right);
s.push(RIGHT);
s.push(node->right);
s.push(LEFT);
}
}
}
}
algorithm data-structures tree binary-tree tree-traversal
I want a function that traverses a binary tree with the Euler traversal (this is how it works). Of course this is easily achievable with recursion - I know how that works. But now I want to implement an iterative version of this algorithm using a stack instead of recursion. My idea was to store the direction we are traversing on the stack as well. My code is not working and I can somehow not wrap my mind around this problem. Can you give me any hints on how to tackle this issue? Here is my code so far:
#define LEFT (struct Node*) 0xBADF00D
#define RIGHT (struct Node*) 0xDEADBEEF
struct Node {
int data;
struct Node* parent;
struct Node* left;
struct Node* right;
};
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
s.push(RIGHT);
s.push(root);
s.push(LEFT);
while(!s.empty()) {
struct Node* direction = s.top(); s.pop();
struct Node* node = s.top(); s.pop();
visit(node);
if(direction == LEFT) {
if(node->left) {
s.push(node->left);
s.push(RIGHT);
s.push(node->left);
s.push(LEFT);
}
}
if(direction == RIGHT) {
if(node->right) {
s.push(node->right);
s.push(RIGHT);
s.push(node->right);
s.push(LEFT);
}
}
}
}
algorithm data-structures tree binary-tree tree-traversal
algorithm data-structures tree binary-tree tree-traversal
edited Nov 20 '18 at 21:08
Phoony
asked Nov 20 '18 at 21:01
PhoonyPhoony
312
312
The easiest way to convert a recursive function into an iterative one is to use a stack in your loop to mimic recursive calls. In fact, that's exactly what happens when you recursively call the same function, except now you're using a stack explicitly instead of using the call stack for your computation.
– Jochem Kuijpers
Nov 21 '18 at 1:10
A suggestion: instead of the unsafe pointer casts, declare two otherwise unused global variables of type Node.
– David Eisenstat
Nov 21 '18 at 3:50
add a comment |
The easiest way to convert a recursive function into an iterative one is to use a stack in your loop to mimic recursive calls. In fact, that's exactly what happens when you recursively call the same function, except now you're using a stack explicitly instead of using the call stack for your computation.
– Jochem Kuijpers
Nov 21 '18 at 1:10
A suggestion: instead of the unsafe pointer casts, declare two otherwise unused global variables of type Node.
– David Eisenstat
Nov 21 '18 at 3:50
The easiest way to convert a recursive function into an iterative one is to use a stack in your loop to mimic recursive calls. In fact, that's exactly what happens when you recursively call the same function, except now you're using a stack explicitly instead of using the call stack for your computation.
– Jochem Kuijpers
Nov 21 '18 at 1:10
The easiest way to convert a recursive function into an iterative one is to use a stack in your loop to mimic recursive calls. In fact, that's exactly what happens when you recursively call the same function, except now you're using a stack explicitly instead of using the call stack for your computation.
– Jochem Kuijpers
Nov 21 '18 at 1:10
A suggestion: instead of the unsafe pointer casts, declare two otherwise unused global variables of type Node.
– David Eisenstat
Nov 21 '18 at 3:50
A suggestion: instead of the unsafe pointer casts, declare two otherwise unused global variables of type Node.
– David Eisenstat
Nov 21 '18 at 3:50
add a comment |
2 Answers
2
active
oldest
votes
Think of a simple binary tree to start with :
1
2 3
Euler traversal for this is : 1 2 1 3 1
You see the pattern here:
root, root->left, root, root->right, root
So your stack order should be:
root
root->left
root
root->right
root
But what if your root is a leaf? then don't push anything just print the value.
Also once you push the nodes on left, right make sure you set them as 0
for the root so that you don't keep pushing them forever.
With that said, the code in cpp would be:
Edit:
The previous code I posted has a bug. The correct code is below:
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
while(!s.empty()) {
struct Node* node = s.pop();
visit(node);
if(node->right) {
s.push(node);
s.push(node->right);
}
if(node->left) {
s.push(node);
s.push(node->left);
}
node->left = 0;
node->right = 0;
}
}
Without destroying the tree:
But yes, even though the code is simple this destroys the tree which is not desired. To tackle this problem I am going to use two properties for leaves of the tree in a euler tree traversal.
If the leaf is left child of the parent and the right child of that parent is null
( or )
if the leaf is right child
-after this leaf is printed then print the parent nodes all the way up the root.
If the leaf is left child and the right child is not null
-after this leaf is printed then print only its immediate parent.
To illustrate look at the below tree.
1
2 3
4 5 6 7
If the leaf is 5
then after it is printed, then print all the parents upto 1
.
If the leaf is 4
then after it is printed, then print just its immediate parent 2
.
To simplify implementation I am going to use a parent stack in addition to the current stack.
void eulerTree(struct Node* root) {
stack<struct Node*> s;
s.push(root);
struct Node* original = root;
stack<struct Node*> p;
while(!s.empty()) {
struct Node* node = s.top();
s.pop();
visit(node);
if ( !node->right && !node->left && !p.empty() ) {
struct Node* pNode = p.top();
if ( pNode->left == node && !pNode->right || pNode->right == node ) {
while ( !p.empty() ) {
visit(p.top());
p.pop();
}
p.push(original);
} else {
visit(pNode);
}
}
if(node->left || node->right) {
p.push(node);
}
if(node->right) {
s.push(node->right);
}
if(node->left) {
s.push(node->left);
}
}
}
This code works, but you should really be able to do this without destroying the tree
– Matt Timmermans
Nov 21 '18 at 3:59
@MattTimmermans I agree. I added code for traversal without destroying the tree.
– SomeDude
Nov 21 '18 at 16:54
add a comment |
A recursive implementation might look like this:
void euler(Node *n) {
visit(n);
if (n->left) {
euler(n->left);
visit(n);
}
if (n->right) {
euler(n->right);
visit(n);
}
}
Now whenever this makes a recursive call, the call stack is used to remember where we are in the code and what we're doing. Then we start again at the top and when we're done, that information is popped of the stack and we continue where we left off.
If you're going to do it iteratively with your own stack, you have to do the same job yourself. You have to remember enough to continue where you left off.
We have to remember which node we were working on of course, but also there are two recursive calls so, so there are 2 possible places we might have to return to. When we return from a recursive call, then either:
- We have just done the
n->left
call and should continue on to checkn->right
; OR - We have just done the
n->right
call and should continue with the final visit ofn
We could store some extra information on the stack to distinguish these two cases, but that is not necessary for this particular algorithm. From the descriptions above, you can see that we can distinguish these cases based on the node we're returning from -- it's either n->left
or n->right
.
So, just storing the waiting node in the stack, we can write an iterative version like this:
int state=0; // 0 => initial visit, 1 => just did left, 2 => just did right
Node *n = root;
while (n) {
visit(n);
if (n->left && state<1) {
stack.push(n);
n=n->left;
state=0;
continue;
}
if (n->right && state<2) {
stack.push(n);
n=n->right;
state=0;
continue;
}
if (stack.empty())
break; // done
Node *child=n;
n = stack.pop();
state = (child == n->left ? 1 : 2);
}
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53401458%2fproblem-with-stack-based-euler-tree-traversal%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
Think of a simple binary tree to start with :
1
2 3
Euler traversal for this is : 1 2 1 3 1
You see the pattern here:
root, root->left, root, root->right, root
So your stack order should be:
root
root->left
root
root->right
root
But what if your root is a leaf? then don't push anything just print the value.
Also once you push the nodes on left, right make sure you set them as 0
for the root so that you don't keep pushing them forever.
With that said, the code in cpp would be:
Edit:
The previous code I posted has a bug. The correct code is below:
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
while(!s.empty()) {
struct Node* node = s.pop();
visit(node);
if(node->right) {
s.push(node);
s.push(node->right);
}
if(node->left) {
s.push(node);
s.push(node->left);
}
node->left = 0;
node->right = 0;
}
}
Without destroying the tree:
But yes, even though the code is simple this destroys the tree which is not desired. To tackle this problem I am going to use two properties for leaves of the tree in a euler tree traversal.
If the leaf is left child of the parent and the right child of that parent is null
( or )
if the leaf is right child
-after this leaf is printed then print the parent nodes all the way up the root.
If the leaf is left child and the right child is not null
-after this leaf is printed then print only its immediate parent.
To illustrate look at the below tree.
1
2 3
4 5 6 7
If the leaf is 5
then after it is printed, then print all the parents upto 1
.
If the leaf is 4
then after it is printed, then print just its immediate parent 2
.
To simplify implementation I am going to use a parent stack in addition to the current stack.
void eulerTree(struct Node* root) {
stack<struct Node*> s;
s.push(root);
struct Node* original = root;
stack<struct Node*> p;
while(!s.empty()) {
struct Node* node = s.top();
s.pop();
visit(node);
if ( !node->right && !node->left && !p.empty() ) {
struct Node* pNode = p.top();
if ( pNode->left == node && !pNode->right || pNode->right == node ) {
while ( !p.empty() ) {
visit(p.top());
p.pop();
}
p.push(original);
} else {
visit(pNode);
}
}
if(node->left || node->right) {
p.push(node);
}
if(node->right) {
s.push(node->right);
}
if(node->left) {
s.push(node->left);
}
}
}
This code works, but you should really be able to do this without destroying the tree
– Matt Timmermans
Nov 21 '18 at 3:59
@MattTimmermans I agree. I added code for traversal without destroying the tree.
– SomeDude
Nov 21 '18 at 16:54
add a comment |
Think of a simple binary tree to start with :
1
2 3
Euler traversal for this is : 1 2 1 3 1
You see the pattern here:
root, root->left, root, root->right, root
So your stack order should be:
root
root->left
root
root->right
root
But what if your root is a leaf? then don't push anything just print the value.
Also once you push the nodes on left, right make sure you set them as 0
for the root so that you don't keep pushing them forever.
With that said, the code in cpp would be:
Edit:
The previous code I posted has a bug. The correct code is below:
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
while(!s.empty()) {
struct Node* node = s.pop();
visit(node);
if(node->right) {
s.push(node);
s.push(node->right);
}
if(node->left) {
s.push(node);
s.push(node->left);
}
node->left = 0;
node->right = 0;
}
}
Without destroying the tree:
But yes, even though the code is simple this destroys the tree which is not desired. To tackle this problem I am going to use two properties for leaves of the tree in a euler tree traversal.
If the leaf is left child of the parent and the right child of that parent is null
( or )
if the leaf is right child
-after this leaf is printed then print the parent nodes all the way up the root.
If the leaf is left child and the right child is not null
-after this leaf is printed then print only its immediate parent.
To illustrate look at the below tree.
1
2 3
4 5 6 7
If the leaf is 5
then after it is printed, then print all the parents upto 1
.
If the leaf is 4
then after it is printed, then print just its immediate parent 2
.
To simplify implementation I am going to use a parent stack in addition to the current stack.
void eulerTree(struct Node* root) {
stack<struct Node*> s;
s.push(root);
struct Node* original = root;
stack<struct Node*> p;
while(!s.empty()) {
struct Node* node = s.top();
s.pop();
visit(node);
if ( !node->right && !node->left && !p.empty() ) {
struct Node* pNode = p.top();
if ( pNode->left == node && !pNode->right || pNode->right == node ) {
while ( !p.empty() ) {
visit(p.top());
p.pop();
}
p.push(original);
} else {
visit(pNode);
}
}
if(node->left || node->right) {
p.push(node);
}
if(node->right) {
s.push(node->right);
}
if(node->left) {
s.push(node->left);
}
}
}
This code works, but you should really be able to do this without destroying the tree
– Matt Timmermans
Nov 21 '18 at 3:59
@MattTimmermans I agree. I added code for traversal without destroying the tree.
– SomeDude
Nov 21 '18 at 16:54
add a comment |
Think of a simple binary tree to start with :
1
2 3
Euler traversal for this is : 1 2 1 3 1
You see the pattern here:
root, root->left, root, root->right, root
So your stack order should be:
root
root->left
root
root->right
root
But what if your root is a leaf? then don't push anything just print the value.
Also once you push the nodes on left, right make sure you set them as 0
for the root so that you don't keep pushing them forever.
With that said, the code in cpp would be:
Edit:
The previous code I posted has a bug. The correct code is below:
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
while(!s.empty()) {
struct Node* node = s.pop();
visit(node);
if(node->right) {
s.push(node);
s.push(node->right);
}
if(node->left) {
s.push(node);
s.push(node->left);
}
node->left = 0;
node->right = 0;
}
}
Without destroying the tree:
But yes, even though the code is simple this destroys the tree which is not desired. To tackle this problem I am going to use two properties for leaves of the tree in a euler tree traversal.
If the leaf is left child of the parent and the right child of that parent is null
( or )
if the leaf is right child
-after this leaf is printed then print the parent nodes all the way up the root.
If the leaf is left child and the right child is not null
-after this leaf is printed then print only its immediate parent.
To illustrate look at the below tree.
1
2 3
4 5 6 7
If the leaf is 5
then after it is printed, then print all the parents upto 1
.
If the leaf is 4
then after it is printed, then print just its immediate parent 2
.
To simplify implementation I am going to use a parent stack in addition to the current stack.
void eulerTree(struct Node* root) {
stack<struct Node*> s;
s.push(root);
struct Node* original = root;
stack<struct Node*> p;
while(!s.empty()) {
struct Node* node = s.top();
s.pop();
visit(node);
if ( !node->right && !node->left && !p.empty() ) {
struct Node* pNode = p.top();
if ( pNode->left == node && !pNode->right || pNode->right == node ) {
while ( !p.empty() ) {
visit(p.top());
p.pop();
}
p.push(original);
} else {
visit(pNode);
}
}
if(node->left || node->right) {
p.push(node);
}
if(node->right) {
s.push(node->right);
}
if(node->left) {
s.push(node->left);
}
}
}
Think of a simple binary tree to start with :
1
2 3
Euler traversal for this is : 1 2 1 3 1
You see the pattern here:
root, root->left, root, root->right, root
So your stack order should be:
root
root->left
root
root->right
root
But what if your root is a leaf? then don't push anything just print the value.
Also once you push the nodes on left, right make sure you set them as 0
for the root so that you don't keep pushing them forever.
With that said, the code in cpp would be:
Edit:
The previous code I posted has a bug. The correct code is below:
void eulerTree(struct Node* root)
{
stack<struct Node*> s;
s.push(root);
while(!s.empty()) {
struct Node* node = s.pop();
visit(node);
if(node->right) {
s.push(node);
s.push(node->right);
}
if(node->left) {
s.push(node);
s.push(node->left);
}
node->left = 0;
node->right = 0;
}
}
Without destroying the tree:
But yes, even though the code is simple this destroys the tree which is not desired. To tackle this problem I am going to use two properties for leaves of the tree in a euler tree traversal.
If the leaf is left child of the parent and the right child of that parent is null
( or )
if the leaf is right child
-after this leaf is printed then print the parent nodes all the way up the root.
If the leaf is left child and the right child is not null
-after this leaf is printed then print only its immediate parent.
To illustrate look at the below tree.
1
2 3
4 5 6 7
If the leaf is 5
then after it is printed, then print all the parents upto 1
.
If the leaf is 4
then after it is printed, then print just its immediate parent 2
.
To simplify implementation I am going to use a parent stack in addition to the current stack.
void eulerTree(struct Node* root) {
stack<struct Node*> s;
s.push(root);
struct Node* original = root;
stack<struct Node*> p;
while(!s.empty()) {
struct Node* node = s.top();
s.pop();
visit(node);
if ( !node->right && !node->left && !p.empty() ) {
struct Node* pNode = p.top();
if ( pNode->left == node && !pNode->right || pNode->right == node ) {
while ( !p.empty() ) {
visit(p.top());
p.pop();
}
p.push(original);
} else {
visit(pNode);
}
}
if(node->left || node->right) {
p.push(node);
}
if(node->right) {
s.push(node->right);
}
if(node->left) {
s.push(node->left);
}
}
}
edited Nov 21 '18 at 16:53
answered Nov 20 '18 at 23:02
SomeDudeSomeDude
4,39531428
4,39531428
This code works, but you should really be able to do this without destroying the tree
– Matt Timmermans
Nov 21 '18 at 3:59
@MattTimmermans I agree. I added code for traversal without destroying the tree.
– SomeDude
Nov 21 '18 at 16:54
add a comment |
This code works, but you should really be able to do this without destroying the tree
– Matt Timmermans
Nov 21 '18 at 3:59
@MattTimmermans I agree. I added code for traversal without destroying the tree.
– SomeDude
Nov 21 '18 at 16:54
This code works, but you should really be able to do this without destroying the tree
– Matt Timmermans
Nov 21 '18 at 3:59
This code works, but you should really be able to do this without destroying the tree
– Matt Timmermans
Nov 21 '18 at 3:59
@MattTimmermans I agree. I added code for traversal without destroying the tree.
– SomeDude
Nov 21 '18 at 16:54
@MattTimmermans I agree. I added code for traversal without destroying the tree.
– SomeDude
Nov 21 '18 at 16:54
add a comment |
A recursive implementation might look like this:
void euler(Node *n) {
visit(n);
if (n->left) {
euler(n->left);
visit(n);
}
if (n->right) {
euler(n->right);
visit(n);
}
}
Now whenever this makes a recursive call, the call stack is used to remember where we are in the code and what we're doing. Then we start again at the top and when we're done, that information is popped of the stack and we continue where we left off.
If you're going to do it iteratively with your own stack, you have to do the same job yourself. You have to remember enough to continue where you left off.
We have to remember which node we were working on of course, but also there are two recursive calls so, so there are 2 possible places we might have to return to. When we return from a recursive call, then either:
- We have just done the
n->left
call and should continue on to checkn->right
; OR - We have just done the
n->right
call and should continue with the final visit ofn
We could store some extra information on the stack to distinguish these two cases, but that is not necessary for this particular algorithm. From the descriptions above, you can see that we can distinguish these cases based on the node we're returning from -- it's either n->left
or n->right
.
So, just storing the waiting node in the stack, we can write an iterative version like this:
int state=0; // 0 => initial visit, 1 => just did left, 2 => just did right
Node *n = root;
while (n) {
visit(n);
if (n->left && state<1) {
stack.push(n);
n=n->left;
state=0;
continue;
}
if (n->right && state<2) {
stack.push(n);
n=n->right;
state=0;
continue;
}
if (stack.empty())
break; // done
Node *child=n;
n = stack.pop();
state = (child == n->left ? 1 : 2);
}
add a comment |
A recursive implementation might look like this:
void euler(Node *n) {
visit(n);
if (n->left) {
euler(n->left);
visit(n);
}
if (n->right) {
euler(n->right);
visit(n);
}
}
Now whenever this makes a recursive call, the call stack is used to remember where we are in the code and what we're doing. Then we start again at the top and when we're done, that information is popped of the stack and we continue where we left off.
If you're going to do it iteratively with your own stack, you have to do the same job yourself. You have to remember enough to continue where you left off.
We have to remember which node we were working on of course, but also there are two recursive calls so, so there are 2 possible places we might have to return to. When we return from a recursive call, then either:
- We have just done the
n->left
call and should continue on to checkn->right
; OR - We have just done the
n->right
call and should continue with the final visit ofn
We could store some extra information on the stack to distinguish these two cases, but that is not necessary for this particular algorithm. From the descriptions above, you can see that we can distinguish these cases based on the node we're returning from -- it's either n->left
or n->right
.
So, just storing the waiting node in the stack, we can write an iterative version like this:
int state=0; // 0 => initial visit, 1 => just did left, 2 => just did right
Node *n = root;
while (n) {
visit(n);
if (n->left && state<1) {
stack.push(n);
n=n->left;
state=0;
continue;
}
if (n->right && state<2) {
stack.push(n);
n=n->right;
state=0;
continue;
}
if (stack.empty())
break; // done
Node *child=n;
n = stack.pop();
state = (child == n->left ? 1 : 2);
}
add a comment |
A recursive implementation might look like this:
void euler(Node *n) {
visit(n);
if (n->left) {
euler(n->left);
visit(n);
}
if (n->right) {
euler(n->right);
visit(n);
}
}
Now whenever this makes a recursive call, the call stack is used to remember where we are in the code and what we're doing. Then we start again at the top and when we're done, that information is popped of the stack and we continue where we left off.
If you're going to do it iteratively with your own stack, you have to do the same job yourself. You have to remember enough to continue where you left off.
We have to remember which node we were working on of course, but also there are two recursive calls so, so there are 2 possible places we might have to return to. When we return from a recursive call, then either:
- We have just done the
n->left
call and should continue on to checkn->right
; OR - We have just done the
n->right
call and should continue with the final visit ofn
We could store some extra information on the stack to distinguish these two cases, but that is not necessary for this particular algorithm. From the descriptions above, you can see that we can distinguish these cases based on the node we're returning from -- it's either n->left
or n->right
.
So, just storing the waiting node in the stack, we can write an iterative version like this:
int state=0; // 0 => initial visit, 1 => just did left, 2 => just did right
Node *n = root;
while (n) {
visit(n);
if (n->left && state<1) {
stack.push(n);
n=n->left;
state=0;
continue;
}
if (n->right && state<2) {
stack.push(n);
n=n->right;
state=0;
continue;
}
if (stack.empty())
break; // done
Node *child=n;
n = stack.pop();
state = (child == n->left ? 1 : 2);
}
A recursive implementation might look like this:
void euler(Node *n) {
visit(n);
if (n->left) {
euler(n->left);
visit(n);
}
if (n->right) {
euler(n->right);
visit(n);
}
}
Now whenever this makes a recursive call, the call stack is used to remember where we are in the code and what we're doing. Then we start again at the top and when we're done, that information is popped of the stack and we continue where we left off.
If you're going to do it iteratively with your own stack, you have to do the same job yourself. You have to remember enough to continue where you left off.
We have to remember which node we were working on of course, but also there are two recursive calls so, so there are 2 possible places we might have to return to. When we return from a recursive call, then either:
- We have just done the
n->left
call and should continue on to checkn->right
; OR - We have just done the
n->right
call and should continue with the final visit ofn
We could store some extra information on the stack to distinguish these two cases, but that is not necessary for this particular algorithm. From the descriptions above, you can see that we can distinguish these cases based on the node we're returning from -- it's either n->left
or n->right
.
So, just storing the waiting node in the stack, we can write an iterative version like this:
int state=0; // 0 => initial visit, 1 => just did left, 2 => just did right
Node *n = root;
while (n) {
visit(n);
if (n->left && state<1) {
stack.push(n);
n=n->left;
state=0;
continue;
}
if (n->right && state<2) {
stack.push(n);
n=n->right;
state=0;
continue;
}
if (stack.empty())
break; // done
Node *child=n;
n = stack.pop();
state = (child == n->left ? 1 : 2);
}
edited Nov 21 '18 at 4:15
answered Nov 21 '18 at 3:44
Matt TimmermansMatt Timmermans
20.6k11733
20.6k11733
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53401458%2fproblem-with-stack-based-euler-tree-traversal%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
The easiest way to convert a recursive function into an iterative one is to use a stack in your loop to mimic recursive calls. In fact, that's exactly what happens when you recursively call the same function, except now you're using a stack explicitly instead of using the call stack for your computation.
– Jochem Kuijpers
Nov 21 '18 at 1:10
A suggestion: instead of the unsafe pointer casts, declare two otherwise unused global variables of type Node.
– David Eisenstat
Nov 21 '18 at 3:50