{"id":103307,"date":"2020-01-08T07:00:00","date_gmt":"2020-01-08T15:00:00","guid":{"rendered":"http:\/\/devblogs.microsoft.com\/oldnewthing\/?p=103307"},"modified":"2020-01-07T20:39:09","modified_gmt":"2020-01-08T04:39:09","slug":"20200108-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200108-00\/?p=103307","title":{"rendered":"Tree-walking algorithms: Incrementally performing a postorder walk of an N-ary tree"},"content":{"rendered":"<p>We continue <a href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200107-00\/?p=103304\"> our exploration<\/a> of algorithms for walking incrementally through an <var>N<\/var>-ary tree by perform a postorder walk through the tree.<\/p>\n<p>Recall that our goal is to follow the red arrows through the tree, as if we are walking along the outside of the tree with our left hand touching it.<\/p>\n<table style=\"text-align: center;\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\">\n<tbody>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2199\ufe0e<\/td>\n<td style=\"border: solid 1px black; width: 2em;\">A<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2196\ufe0e<\/td>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td>&nbsp;<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2199\ufe0e<\/td>\n<td style=\"width: 2em;\">\u2571<\/td>\n<td style=\"width: 2em;\">\u2502<\/td>\n<td style=\"width: 2em;\">\u2572<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2196\ufe0e<\/td>\n<td>&nbsp;<\/td>\n<\/tr>\n<tr>\n<td>&nbsp;<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2199\ufe0e<\/td>\n<td style=\"border: solid 1px black; width: 2em;\">B<\/td>\n<td style=\"width: 2em; color: red;\">\u21b7<\/td>\n<td style=\"border: solid 1px black; width: 2em;\">C<\/td>\n<td style=\"width: 2em; color: red;\">\u21b7<\/td>\n<td style=\"border: solid 1px black; width: 2em;\">D<\/td>\n<td style=\"width: 2em; color: red; text-align: left;\">\u00a0\u2191<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; color: red; text-align: right; font-family: '';\">\u2199\ufe0e<\/td>\n<td style=\"text-align: right; width: 2em;\">\u2571<\/td>\n<td style=\"width: 2em; color: red;\">\u21b7<\/td>\n<td style=\"text-align: left; width: 2em; font-family: '';\">\u2572<span style=\"color: red;\">\u2196\ufe0e<\/span><\/td>\n<td style=\"width: 2em; color: red;\">\u2192<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2934\ufe0e\u2193\ufe0e<\/td>\n<td style=\"width: 2em;\">\u2502<\/td>\n<td style=\"width: 2em; color: red; text-align: left;\">\u00a0\u2191<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2193\ufe0e<\/td>\n<td style=\"border: solid 1px black; width: 2em;\">E<\/td>\n<td style=\"width: 2em; color: red;\">\u2191\u2193<\/td>\n<td style=\"border: solid 1px black; width: 2em;\">F<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2196\ufe0e<\/td>\n<td style=\"width: 2em; color: red; text-align: right;\">\u2193\u00a0<\/td>\n<td style=\"border: solid 1px black; width: 2em;\">G<\/td>\n<td style=\"width: 2em; color: red; text-align: left;\">\u00a0\u2191<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 2em; color: red; text-align: right;\">\u2937<\/td>\n<td style=\"width: 2em; color: red;\">\u2192<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2934\ufe0e\u2937\ufe0e<\/td>\n<td style=\"width: 2em; color: red;\">\u2192<\/td>\n<td style=\"width: 2em; color: red; font-family: '';\">\u2934\ufe0e<\/td>\n<td style=\"width: 2em; color: red; text-align: right;\">\u2937<\/td>\n<td style=\"width: 2em; color: red;\">\u2192<\/td>\n<td style=\"width: 2em; color: red; text-align: left; font-family: '';\">\u2934\ufe0e<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>As with the preorder walk, we have two possible stopping places. We could stop at a leaf node (a node with no children), or we could stop at a parent node. However, the actions to take are the same in both cases, since we are always on the &#8220;upward path&#8221;.<\/p>\n<p>We have just finished enumerating a subtree, so we need to enumerate the next subtree, or move up to the parent if there are no more subtrees.<\/p>\n<p>Therefore, we first try to move to the next sibling. If that works, then treat that subtree as a new root by going deep to the first leaf node.<\/p>\n<p>If there is no next sibling, then we have finished processing all the children of a node, so move up to the parent node and enumerate it.<\/p>\n<pre>class PostorderWalker\r\n{\r\n  private TreeCursor cursor;\r\n\r\n  public PostorderWalker(TreeNode node)\r\n  {\r\n    cursor = new TreeCursor(node);\r\n    GoDeep();\r\n  }\r\n\r\n  public bool MoveNext()\r\n  {\r\n    if (cursor.TryMoveToNextSiblingChild()) {\r\n      GoDeep();\r\n      return true;\r\n    }\r\n\r\n    if (cursor.TryMoveToParent()) {\r\n      return true;\r\n    }\r\n    return false;\r\n  }\r\n\r\n  public TreeNode Current =&gt; cursor.Current;\r\n\r\n  private void GoDeep()\r\n  {\r\n    while (cursor.TryMoveToFirstChild()) { }\r\n  }\r\n}\r\n<\/pre>\n<p>Next time, we&#8217;ll look at in-order enumeration.<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>This time, we report on the way back up.<\/p>\n","protected":false},"author":1069,"featured_media":111744,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[25],"class_list":["post-103307","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>This time, we report on the way back up.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103307","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/users\/1069"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/comments?post=103307"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/103307\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media\/111744"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/media?parent=103307"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=103307"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=103307"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}