Recursion and Stack Methods include O(n)space complexity. To avoid this additional space overhead we can modify the original tree and convert it to a Threaded Binary Tree using Morris Traversal
binary tree in which every node contains a value greater than left_child and lesser than right_child
Search()
Node* search(Node* root, int query) { if (root == NULL || root->data == query) return root; if (query < root->data) return search(root->left, query); else return search(root->right, query); return root;}
Insert()
Node* insert(Node* root, int data) { if (root == NULL) return createNode(data); if (key < root->data) root->left = insert(root->left, data); else if (data > root->data) root->right = insert(root->right, data); else printf("%d already present\n", data); return root;}
running time O(h) h = height
worst case with n different nodes = O(n)
Max()/Min()
go as far left or right as possible
int getMax(Node* root) { while (node->right != NULL) { root = root->right; } return root->data;}int getMin(Node* root) { while (root->left != NULL) root = root->left; return root->data; }
Delete()
Lazy Node Deletion
Don’t actually delete the node. Keep the data and mark the node as ‘disabled’. Upon a later insertion of the same data, the node can be easily re-enabled.
Actual Node Deletion
3 cases
leaf node (no child)
internal node (one child)
internal node (two children)
Case 1:
just remove it
Case 2:
replace it with it’s child
Case 3:
let D be the node to be deleted
find min() in right subtree and copy its value to D
recursively delete that min() value
Node* delete(Node* root, int data) { // key not found if (root == NULL) return NULL; //recur down the tree if (data < root->data) root->left = delete(root->left, data); else if (data > root->data) root->right = delete(root->right, data); // if data == root->key then root is to be deleted else { // if leaf node if (root->left == NULL && root->right == NULL){ free(root); return NULL; } // if node with left child only else if (root->right == NULL) { Node* temp = root->left; free(root); return temp; } // if node with right child only else if (root->left == NULL) { Node* temp = root->right; free(root); return temp; } // if both children with min node in the right subtree else { Node* temp = getMin(root->right); root->data = temp->data; root->right = delete(root->right, temp->data); } } return root;}
Complexity Analysis
running time of all operations is O(d) (d = depth), apart from traversal which is necessarily O(n) (n = nodes)
HOWEVER:
tree shape depends on the order of insertion, at best if the tree is complete its height is O(logn)
and randomly also it’s around that, but it’s very easy for the trees to become unbalanced to one side
Worst Case running time is O(n) in a completely unbalanced tree