{"id":111765,"date":"2025-11-05T07:00:00","date_gmt":"2025-11-05T15:00:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/oldnewthing\/?p=111765"},"modified":"2025-11-05T08:31:59","modified_gmt":"2025-11-05T16:31:59","slug":"20251105-00","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/oldnewthing\/20251105-00\/?p=111765\/","title":{"rendered":"Non-recursively deleting a binary tree in constant space: Traversal with parent pointers"},"content":{"rendered":"<p>As a challenge, a colleague of mine told me to find a non-recursive constant-space algorithm for deleting a binary tree.\u00b9<\/p>\n<p>After a moment&#8217;s thought, I was able to come up with an algorithm. It is often the case that solving a problem is easier once you are told that a solution exists.<\/p>\n<p>When I asked the Internet for a non-recursive constant-space algorithm, it seems that <a title=\"Free a binary tree\" href=\"https:\/\/codegolf.stackexchange.com\/questions\/478\/free-a-binary-tree\/489#489\"> everybody uses an algorithm different from the one I found<\/a>, so let&#8217;s look at that one first.<\/p>\n<p>The idea behind that algorithm is to start with the algorithm for <a title=\"Tree-walking algorithms: Incrementally performing an inorder walk of a binary tree\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200109-00\/?p=103309\"> iteratively traversing a binary tree<\/a> in which each node also remembers its parent. The linked article does an inorder walk, so we&#8217;ll <a title=\"Tree-walking algorithms: Incrementally performing a postorder walk of an N-ary tree\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20200108-00\/?p=103307\"> adapt the N-ary postorder walk<\/a>.<\/p>\n<pre>struct Node\r\n{\r\n    Node* left;\r\n    Node* right;\r\n    Node* parent;\r\n    Data d;\r\n};\r\n\r\nvoid DeleteTree(Node* node)\r\n{\r\n    while (node) {\r\n        \/\/ Go left as far as you can.\r\n        while (node-&gt;left) {\r\n            node = node-&gt;left;\r\n        }\r\n\r\n        \/\/ If you can't go left, try going right one step,\r\n        \/\/ and then continue the leftward descent.\r\n        if (node-&gt;right) {\r\n            node = node-&gt;right;\r\n            continue;\r\n        }\r\n\r\n        \/\/ At the bottom. Delete the node and head back up.\r\n        while (node) {\r\n            auto parent = node-&gt;parent;\r\n            delete node;\r\n            if (!parent) {\r\n                return; \/\/ all done\r\n            }\r\n            \/\/ If we came from the left child,\r\n            \/\/ then go to the right child if there is one.\r\n            if (node == parent-&gt;left &amp;&amp; parent-&gt;right) {\r\n                node = parent-&gt;right;\r\n                break;\r\n            } else {\r\n                \/\/ No more children, so keep walking up.\r\n                node = parent;\r\n            }\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>The only tricky part is that our N-ary postorder walk wants a <code>NextSibling<\/code>, but we don&#8217;t have that. We synthesize it by realizing that in a binary tree, each parent has only two children, so if you are a child, you are either the left child (in which case the next sibling is the right child, if you have one) or the right child (in which case there is no next sibling). You can figure out which one you are by seeing if you are your parent&#8217;s left child.<\/p>\n<p>Next time, we&#8217;ll figure out where to get the parent pointer when we don&#8217;t have one.<\/p>\n<p>\u00b9 You might be in need of such an algorithm if your tree can get very deep, so a recursive algorithm would exceed available stack space. The constant space requirement is important because this ensures that you don&#8217;t run into a low-memory error when trying to free up memory. C++ destructors are <code>noexcept<\/code> by default, and even if you mark them as potentially-throwing, throwing an exception from a destructor that is called due to unwinding is <a href=\"https:\/\/en.cppreference.com\/w\/cpp\/language\/destructor#Exceptions\"> considered a fatal error that results in immediate termination of the program<\/a>. <a title=\"Clean-up functions can't fail because, well, how do you clean up from a failed clean-up?\" href=\"https:\/\/devblogs.microsoft.com\/oldnewthing\/20080107-00\/?p=23913\"> Clean-up functions cannot fail<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>First assume that you have a parent pointer.<\/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-111765","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-oldnewthing","tag-code"],"acf":[],"blog_post_summary":"<p>First assume that you have a parent pointer.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111765","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=111765"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/posts\/111765\/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=111765"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/categories?post=111765"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/oldnewthing\/wp-json\/wp\/v2\/tags?post=111765"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}