{"id":5,"date":"2013-05-11T11:59:00","date_gmt":"2013-05-11T18:59:00","guid":{"rendered":"http:\/\/samueldotj.com\/blog\/?p=5"},"modified":"2013-08-26T18:57:59","modified_gmt":"2013-08-27T01:57:59","slug":"self-balancing-tree-as-heap","status":"publish","type":"post","link":"http:\/\/samueldotj.com\/blog\/self-balancing-tree-as-heap\/","title":{"rendered":"Self Balancing Tree as Heap"},"content":{"rendered":"<p>Here is my thoughts about how to combine a <a href='http:\/\/en.wikipedia.org\/wiki\/Heap_(data_structure)'>Heap<\/a> and <a href='http:\/\/en.wikipedia.org\/wiki\/AVL_tree'>AVL tree<\/a> and get benefit of both them from a single data structure.<\/p>\n<p>A <a href=\"http:\/\/en.wikipedia.org\/wiki\/Self-balancing_binary_search_tree\">self balancing binary search tree<\/a> such as <a href=\"http:\/\/en.wikipedia.org\/wiki\/AVL_tree\">AVL tree<\/a> can do faster lookup for a item in the tree in O(log n).\u00a0<a href=\"http:\/\/en.wikipedia.org\/wiki\/Heap_(data_structure)\">Heap<\/a>s are mainly used to implement priority queues which needs to find min\/max elements quickly. Heap\u00a0achieves\u00a0this in O(1) time complexity.<\/p>\n<p><a href=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Balanced-BST11.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Balanced-BST11-300x204.png\" alt=\"Balanced BST1\" width=\"300\" height=\"204\" class=\"alignright size-medium wp-image-57\" srcset=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Balanced-BST11-300x204.png 300w, http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Balanced-BST11.png 476w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a> Lets revisit a basic property of binary search tree &#8211; In a binary search tree min element is at the left most leaf position. Similarly in a BST max element is at the right most leaf position. So finding min\/max element in a BST is O(h) where h is the depth of the tree. If the BST is a balanced tree then O(h) is O(log n) in worst case(otherwise the worst case O(n), since we considering only balanced trees here lets ignore the unbalanced cases). The following diagram illustrates a basic property of the BST &#8211; min element is always on the left most node.<\/p>\n<p><div id=\"attachment_64\" style=\"width: 310px\" class=\"wp-caption alignleft\"><a href=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/BST-PointerToMin1.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-64\" src=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/BST-PointerToMin1-300x204.png\" alt=\"Cached pointer to Min element at the root\" width=\"300\" height=\"204\" class=\"size-medium wp-image-64\" srcset=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/BST-PointerToMin1-300x204.png 300w, http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/BST-PointerToMin1.png 473w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><p id=\"caption-attachment-64\" class=\"wp-caption-text\">Cached pointer to Min element at the root<\/p><\/div> Using this basic property, min remove operation can be optimized. The first and simplest optimization comes to mind is store a pointer to min\/max elements. This caching will result in O(1) time complexity for finding min\/max elements. However this would increase the cost of node insert\/delete because the min\/max pointer has to be updated during insert and deletion. The cost of finding and deleting a min node is O(log(n)) which is same as if we havent had the cache pointers. The picture in the right shows\u00a0advantage\u00a0of having cached pointer to find a min element.\u00a0Obviously\u00a0this method cant be used for priority queues where find min\/delete operation is used together.<\/p>\n<p>In the above method the problem was the complexity finding next smallest element in the tree from min element is O(log n). So if we have pointer to next smallest element from all nodes then find and delete opearation would be of complexity O(1).<\/p>\n<p>Lets look at the BST from slightly different angle. Usual declaration of BST in C as follows:<\/p>\n<p>[c]<br \/>\nstruct binary_tree<br \/>\n{<br \/>\n   struct binary_tree *left;<br \/>\n   struct binary_tree *right;<br \/>\n};<br \/>\n[\/c]<\/p>\n<p>When we(me and\u00a0<a href=\"http:\/\/plus.google.com\/105622177928011443688\" target=\"_blank\">+Dilip Simha<\/a>)\u00a0were implementing ADT for AceOS we decided to\u00a0experiment BST in a different way. We saw tree as recursive lists rather than a recursive pointers. <\/p>\n<p>In the following picture you could see 6 lists(not counting sub-lists):<br \/>\n<a href=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Balanced-BST12.png\"><img decoding=\"async\" src=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Balanced-BST12.png\" alt=\"A list is highlighted\" class=\"alignright size-medium wp-image-62\" width=\"220\" \/><\/a><\/p>\n<ol>\n<li>(300, 200, 100, 50)<\/li>\n<li>(300, 400, 500, 600)<\/li>\n<li>(200, 250, 275)<\/li>\n<li>(100, 150)<\/li>\n<li>(400, 350)<\/li>\n<li>(500, 450)<\/li>\n<\/ol>\n<p>Now consider this list is a doubly linked circular list. This is illustrated in the following figure. You may argue that this will make the BST to become cyclic directed graph. But for the sake of simplicity lets continue to call this as balanced BST. In the picture I left out few arrows to keep it cleaner.<\/p>\n<div id=\"attachment_63\" style=\"width: 483px\" class=\"wp-caption aligncenter\"><a href=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Binary-Search-Tree-Doule-Pointer.png\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-63\" src=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Binary-Search-Tree-Doule-Pointer.png\" alt=\"Binary Search Tree with nodes having pointer to parent also\" width=\"473\" height=\"324\" class=\"size-full wp-image-63\" srcset=\"http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Binary-Search-Tree-Doule-Pointer.png 473w, http:\/\/samueldotj.com\/blog\/wp-content\/uploads\/2013\/05\/Binary-Search-Tree-Doule-Pointer-300x205.png 300w\" sizes=\"auto, (max-width: 473px) 100vw, 473px\" \/><\/a><p id=\"caption-attachment-63\" class=\"wp-caption-text\">Binary Search Tree with nodes having pointer to parent also<\/p><\/div>\n<p>[c]<br \/>\ntypedef struct list LIST, * LIST_PTR;<br \/>\nstruct list {<br \/>\n   LIST_PTR next;<br \/>\n   LIST_PTR prev;<br \/>\n};<\/p>\n<p>typedef struct binary_tree<br \/>\n{<br \/>\n   LIST left;<br \/>\n   LIST right;<br \/>\n}BINARY_TREE;<\/p>\n<p>typedef struct avl_tree<br \/>\n{<br \/>\n   int height;    \/*! height of the node*\/<br \/>\n   BINARY_TREE bintree; \/*! low level binary tree*\/<br \/>\n}AVL_TREE;<br \/>\n[\/c]<\/p>\n<p>AVL tree in Ace OS \u00a0is implemented in this way. You can see the data structure declarations below.\u00a0Initially\u00a0we did it for reusing the code. But after implementing this we\u00a0figured out some interesting properties. This balanced tree\/graph can find any node in O(log(n)) and also offers <strong>findmin<\/strong> operation\u00a0in O(1) complexity. This also reduces the complexity of delete\u00a0operation(since we can find right node&#8217;s left most child in O(1) operation). But delete operation might result in balancing the tree.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Here is my thoughts about how to combine a Heap and AVL tree and get benefit of both them from a single data structure. A self balancing binary search tree such as AVL tree can do faster lookup for a item in the tree in O(log n).\u00a0Heaps are mainly used to implement priority queues which [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-5","post","type-post","status-publish","format-standard","hentry","category-ace"],"_links":{"self":[{"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/posts\/5","targetHints":{"allow":["GET"]}}],"collection":[{"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/comments?post=5"}],"version-history":[{"count":5,"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/posts\/5\/revisions"}],"predecessor-version":[{"id":133,"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/posts\/5\/revisions\/133"}],"wp:attachment":[{"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/media?parent=5"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/categories?post=5"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/samueldotj.com\/blog\/wp-json\/wp\/v2\/tags?post=5"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}