3 / \ 1 4 \ \ 2 6 / \ 5 9 / 7
---------50---------- / \ ----25---- ----75---- / \ / \ 10 40 60 90 / / \ / / 2 35 45 55 85 \ 57
---------50---------- / \ ----25---- ----75---- / \ / \ 10 40 60 90 / \ / / 35 45 55 85 \ 57When a node is a leaf, like 2, you simply remove it from its parent.
---------50---------- / \ ----35---- ----75---- / \ / \ 10 40 60 90 / \ / / 2 45 55 85 \ 57When a node with two children is deleted, you must perform the following actions:
---------55---------- / \ ----25---- ----75---- / \ / \ 10 40 60 90 / / \ / / 2 35 45 57 85When a node with two children is deleted, you must perform the following actions:
tree_height = 1 + max(height(root->left), height(root->right))This definition is recursive in that the heights of the left and right subtrees can be computed in the same fashion. By convention the height of an empty tree is -1. These facts lead to the following recursive function for computing a tree's height:
int height (node *root) { if (root == 0) return -1; else return 1 + max(height(root->left_child), height(root->right_child)); }The max function is defined in the math.h library. If you did not use the max function, and I would not expect you to, then the following function would work:
int height (node *root) { int left_height; int right_height; if (root == 0) return -1; else { left_height = height(root->left_child); right_height = height(root->right_child); if (left_height > right_height) return 1 + left_height; else return 1 + right_height; } }
int fact(n) { if (n == 0) return 1; else return n * fact(n-1); }If you wanted to be really careful, you could also ensure that the initial value of n is non-negative. It would be inefficient for every call to fact to check whether n is non-negative so one would write a helper function that would do the recursion and have fact itself perform the check:
int fact_helper(n) { if (n == 0) return 1; else return n * fact_helper(n-1); } int fact(n) { if (n < 0) { fprintf(stderr, "fact(%d): The argument must be non-negative\n", n); exit(1); } return fact_helper(n); }
Data Structure | Key exists | Key does not exist |
---|---|---|
Ordered linked list | 500,000 | 500,000 |
Unbalanced binary search tree | 20 | 20 |
Hash table | 1 | 1 |
For an ordered linked list, a found key will be on average halfway through the list, resulting in n/2 comparisions. For a key that does not exist, you can stop as soon as you reach an element in the list that is greater than the key. For example, if you have the list 1, 3, 8, 15, 20, 25, 30, 40, 55, 80, ... and you want to know if 17 is in the list, then you can stop as soon as you reach 20 because you know that all the remaining elements in the list are greater than 20 and hence greater than 17. Thus you cannot hope to find 17 later in the list and you can stop. On average, you will reach the first greater element halfway through the list, thus also resulting in n/2 comparisions.
For an unbalanced binary tree, since the distribution of the keys is random, the tree will be roughly balanced, and hence finds for both existing and non-existent keys will require O(log_{2} n) which is 19.93 for n = 1,000,000.
For hash tables, the number of comparisons is O(1), so is roughly 1 in a table where the keys are well distributed.