{"id":382738,"date":"2024-06-29T04:28:06","date_gmt":"2024-06-29T04:28:06","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=382738"},"modified":"-0001-11-30T00:00:00","modified_gmt":"2024-06-29T04:28:06","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=382738","title":{"rendered":"<span>Algorithms in Go: Iterative Postorder Traversal<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>This is the next article in the series <a href=\"https:\/\/habr.com\/en\/post\/545986\/\" rel=\"noopener noreferrer nofollow\">Algorithms in Go<\/a>. In this part, we discuss the postorder traversal of a binary tree. What does postorder traversal mean? It means that at first, we process the left subtree of the node, then the right subtree of the node, and only after that we process the node itself. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/b80\/0fd\/e70\/b800fde707f92c58262829ffbc90cb03.png\" width=\"871\" height=\"311\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/b80\/0fd\/e70\/b800fde707f92c58262829ffbc90cb03.png\"\/><figcaption><\/figcaption><\/figure>\n<p>Why would we need to do it in this order? This approach solves an entire class of algorithmic problems related to the binary trees. For example, to find the longest path between two nodes we need to traverse the tree in a postorder manner. In general, postorder traversal is needed when we cannot process the node without processing its children first. In this manner, for example, we can calculate the height of the tree. To know the height of a node, we need to calculate the height of its children and increment it by one.<\/p>\n<p>Let&#8217;s start with a recursive approach. We need to process the left child, then the right child and finally we can process the node itself. For simplicity, let&#8217;s just save the values into slice <code>out<\/code>.<\/p>\n<pre><code class=\"go\">var out []int var f func(root *TreeNode) f = func(root *TreeNode) {   if root == nil {     return   }   f(root.Left)   f(root.Right)   out = append(out, root.Val) }<\/code><\/pre>\n<p>In this case, the recursive function pretty much embodies the definition of the postorder traversal. We deal with the left subtree, then the right subtree and finally process the root value. <\/p>\n<p>Now, how can we convert this function into an iterative version? <\/p>\n<p>We can solve this problem with the following approach:<\/p>\n<ol>\n<li>\n<p>Push the root node into the stack.<\/p>\n<\/li>\n<li>\n<p>Push the left child into the stack.<\/p>\n<\/li>\n<li>\n<p>Pop the left child from the stack and process it.<\/p>\n<\/li>\n<li>\n<p>Push the right child into the stack.<\/p>\n<\/li>\n<li>\n<p>Pop the right child from the stack and process it<\/p>\n<\/li>\n<li>\n<p>Pop the root node and process it.<\/p>\n<\/li>\n<\/ol>\n<p>Let&#8217;s consider the following tree:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/90c\/ef2\/23f\/90cef223f0b9b9a1af27c304f6b0949a.png\" width=\"502\" height=\"412\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/90c\/ef2\/23f\/90cef223f0b9b9a1af27c304f6b0949a.png\"\/><figcaption><\/figcaption><\/figure>\n<p>We push the root node <code>1<\/code>into the stack. At the next step, we put its left child <code>2<\/code>\u00a0into the stack.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/08d\/edd\/602\/08dedd6027feb16bdedc8483679c273e.png\" width=\"901\" height=\"511\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/08d\/edd\/602\/08dedd6027feb16bdedc8483679c273e.png\"\/><figcaption><\/figcaption><\/figure>\n<p>At the next iteration, we have node <code>2<\/code>\u00a0at the top of the stack, therefore we try to put its left child into the stack. As the left child is not present, we skip this step and push its right child <code>4<\/code>\u00a0into the stack.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/f95\/80d\/fca\/f9580dfca6d855a7f71e926d308ddf40.png\" width=\"1131\" height=\"511\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f95\/80d\/fca\/f9580dfca6d855a7f71e926d308ddf40.png\"\/><figcaption><\/figcaption><\/figure>\n<p>After this stage, we have three nodes in our stack. The top node <code>4<\/code>\u00a0does not have any children, so we process its value and pop it from the stack. <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a8e\/e05\/479\/a8ee05479a28e3325f5f2537b17c1610.png\" width=\"901\" height=\"511\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a8e\/e05\/479\/a8ee05479a28e3325f5f2537b17c1610.png\"\/><figcaption><\/figcaption><\/figure>\n<p>Now, we have the same nodes in the stack as at the previous step. However, we have already processed all children of the node <code>2<\/code>, therefore we can process node <code>2<\/code>\u00a0and pop it from the stack.<\/p>\n<p>After this iteration, we have a single node in the stack which is node <code>1<\/code>. We haven&#8217;t processed its right child yet, so we put it into the stack. We proceed in the same manner and process the right subtree of node <code>1<\/code>.<\/p>\n<p>How can we encode this algorithm? We need to have some check that ensures that we don&#8217;t process a node twice. When we process a node, there are two possible situations:<\/p>\n<ol>\n<li>\n<p>We just met this node and need to push its children into the stack.<\/p>\n<\/li>\n<li>\n<p>We have already processed its children and now are returning back to process the node itself.<\/p>\n<\/li>\n<\/ol>\n<p>We can save the last processed node into the variable <code>prev<\/code>. If the right child of the current node is equal to <code>prev<\/code>\u00a0it means that we already processed both of its children and now need to process the value of the current node. For the left child, we need to check one more condition: it is possible that the current node doesn&#8217;t have the right child. In this case, we need to check whether <code>prev<\/code>\u00a0node is equal to the left child. If that&#8217;s the case, then we already processed the left child of the current node and we don&#8217;t have the right child at all, therefore we can process the value of the current node. <\/p>\n<p>Let&#8217;s encode this algorithm in Go<\/p>\n<pre><code class=\"go\">var out []int prev := root stack := []*TreeNode{root}  for len(stack) > 0 {   node := stack[len(stack)-1]   if node.Left != nil &amp;&amp; node.Left != prev &amp;&amp; node.Right != prev {     stack = append(stack, node.Left)   } else if node.Right != nil &amp;&amp; node.Right != prev {     stack = append(stack, node.Right)   } else {     prev = node     stack = stack[:len(stack)-1]     out = append(out, node.Val)   } }  return out<\/code><\/pre>\n<p>In this post, we implemented the postorder traversal of the binary tree. This is one of the most popular algorithmic patterns that solve an entire class of problems. More algorithmic patterns such as <a href=\"https:\/\/habr.com\/en\/post\/531444\/\" rel=\"noopener noreferrer nofollow\">Sliding Window<\/a> or <a href=\"https:\/\/habr.com\/en\/post\/543618\/\" rel=\"noopener noreferrer nofollow\">Matrix Spiral <\/a>can be found in the series <a href=\"https:\/\/habr.com\/en\/post\/545986\/\" rel=\"noopener noreferrer nofollow\">Algorithms in Go.<\/a> <\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/545980\/\"> https:\/\/habr.com\/ru\/articles\/545980\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>This is the next article in the series <a href=\"https:\/\/habr.com\/en\/post\/545986\/\" rel=\"noopener noreferrer nofollow\">Algorithms in Go<\/a>. In this part, we discuss the postorder traversal of a binary tree. What does postorder traversal mean? It means that at first, we process the left subtree of the node, then the right subtree of the node, and only after that we process the node itself. <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>Why would we need to do it in this order? This approach solves an entire class of algorithmic problems related to the binary trees. For example, to find the longest path between two nodes we need to traverse the tree in a postorder manner. In general, postorder traversal is needed when we cannot process the node without processing its children first. In this manner, for example, we can calculate the height of the tree. To know the height of a node, we need to calculate the height of its children and increment it by one.<\/p>\n<p>Let&#8217;s start with a recursive approach. We need to process the left child, then the right child and finally we can process the node itself. For simplicity, let&#8217;s just save the values into slice <code>out<\/code>.<\/p>\n<pre><code class=\"go\">var out []int var f func(root *TreeNode) f = func(root *TreeNode) {   if root == nil {     return   }   f(root.Left)   f(root.Right)   out = append(out, root.Val) }<\/code><\/pre>\n<p>In this case, the recursive function pretty much embodies the definition of the postorder traversal. We deal with the left subtree, then the right subtree and finally process the root value. <\/p>\n<p>Now, how can we convert this function into an iterative version? <\/p>\n<p>We can solve this problem with the following approach:<\/p>\n<ol>\n<li>\n<p>Push the root node into the stack.<\/p>\n<\/li>\n<li>\n<p>Push the left child into the stack.<\/p>\n<\/li>\n<li>\n<p>Pop the left child from the stack and process it.<\/p>\n<\/li>\n<li>\n<p>Push the right child into the stack.<\/p>\n<\/li>\n<li>\n<p>Pop the right child from the stack and process it<\/p>\n<\/li>\n<li>\n<p>Pop the root node and process it.<\/p>\n<\/li>\n<\/ol>\n<p>Let&#8217;s consider the following tree:<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>We push the root node <code>1<\/code>into the stack. At the next step, we put its left child <code>2<\/code>\u00a0into the stack.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>At the next iteration, we have node <code>2<\/code>\u00a0at the top of the stack, therefore we try to put its left child into the stack. As the left child is not present, we skip this step and push its right child <code>4<\/code>\u00a0into the stack.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>After this stage, we have three nodes in our stack. The top node <code>4<\/code>\u00a0does not have any children, so we process its value and pop it from the stack. <\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>Now, we have the same nodes in the stack as at the previous step. However, we have already processed all children of the node <code>2<\/code>, therefore we can process node <code>2<\/code>\u00a0and pop it from the stack.<\/p>\n<p>After this iteration, we have a single node in the stack which is node <code>1<\/code>. We haven&#8217;t processed its right child yet, so we put it into the stack. We proceed in the same manner and process the right subtree of node <code>1<\/code>.<\/p>\n<p>How can we encode this algorithm? We need to have some check that ensures that we don&#8217;t process a node twice. When we process a node, there are two possible situations:<\/p>\n<ol>\n<li>\n<p>We just met this node and need to push its children into the stack.<\/p>\n<\/li>\n<li>\n<p>We have already processed its children and now are returning back to process the node itself.<\/p>\n<\/li>\n<\/ol>\n<p>We can save the last processed node into the variable <code>prev<\/code>. If the right child of the current node is equal to <code>prev<\/code>\u00a0it means that we already processed both of its children and now need to process the value of the current node. For the left child, we need to check one more condition: it is possible that the current node doesn&#8217;t have the right child. In this case, we need to check whether <code>prev<\/code>\u00a0node is equal to the left child. If that&#8217;s the case, then we already processed the left child of the current node and we don&#8217;t have the right child at all, therefore we can process the value of the current node. <\/p>\n<p>Let&#8217;s encode this algorithm in Go<\/p>\n<pre><code class=\"go\">var out []int prev := root stack := []*TreeNode{root}  for len(stack) > 0 {   node := stack[len(stack)-1]   if node.Left != nil &amp;&amp; node.Left != prev &amp;&amp; node.Right != prev {     stack = append(stack, node.Left)   } else if node.Right != nil &amp;&amp; node.Right != prev {     stack = append(stack, node.Right)   } else {     prev = node     stack = stack[:len(stack)-1]     out = append(out, node.Val)   } }  return out<\/code><\/pre>\n<p>In this post, we implemented the postorder traversal of the binary tree. This is one of the most popular algorithmic patterns that solve an entire class of problems. More algorithmic patterns such as <a href=\"https:\/\/habr.com\/en\/post\/531444\/\" rel=\"noopener noreferrer nofollow\">Sliding Window<\/a> or <a href=\"https:\/\/habr.com\/en\/post\/543618\/\" rel=\"noopener noreferrer nofollow\">Matrix Spiral <\/a>can be found in the series <a href=\"https:\/\/habr.com\/en\/post\/545986\/\" rel=\"noopener noreferrer nofollow\">Algorithms in Go.<\/a> <\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/545980\/\"> https:\/\/habr.com\/ru\/articles\/545980\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-382738","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/382738","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=382738"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/382738\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=382738"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=382738"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=382738"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}