understanding this recursive function in a BST tree - java

I'm having a hard time understanding this code for the ranking of nodes by size. Rank returns the size of all the nodes less than the key.
http://algs4.cs.princeton.edu/32bst/BST.java.html
how is the result returned for rank(key, x.left)???
code:
public int rank(Key key) {
return rank(key, root);
}
// Number of keys in the subtree less than key.
private int rank(Key key, Node x) {
if (x == null) return 0;
int cmp = key.compareTo(x.key);
if (cmp < 0) return rank(key, x.left);
else if (cmp > 0) return 1 + size(x.left) + rank(key, x.right);
else return size(x.left);
}
// is the symbol table empty?
public boolean isEmpty() {
return size() == 0;
}
// return number of key-value pairs in BST
public int size() {
return size(root);
}
// return number of key-value pairs in BST rooted at x
private int size(Node x) {
if (x == null) return 0;
else return x.N;
}

Note that rank does not return an entry (a node value) but rather a value that represents the comparison between given Key and that of the candidate Node's left subtree (the left-most value for a node in a binary search tree).
The value it returns stems from an implementation of the standard Comparable interface: negative integer if first element is lesser than second, positive if it is greater, 0 if they are equal.
In this particular case, the exact number returned indicates the distance (difference) between both keys being compared, which might be useful for the code using the comparison result--usually, sort algorithms.

Related

Why does my code not work? It passed 8 out of 600 cases on GFG. The Question is "leaf at same level"

My Approach is this- I used an arraylist. I checked all the nodes of the Binary Tree, to find those whose left and right node are null, which signifies that they are a leaf, then I found out their levels and added them to an arraylist.
After this I used the Arraylist in the function boolean check to check whether all the elements of the array list are same of not, if they are i return true (all leaves are at the same level) otherwise I return false.
class Solution {
boolean check(Node root) {
int c = 0;
ArrayList<Integer> a = new ArrayList<>();
for (int x : a) {
if (x != (a.get(0)))
return false;
}
return true;
}
public void che(Node root, int level, ArrayList<Integer> a) {
if (root == null) return;
if (root.left == null && root.right == null) {
a.add(level);
}
che(root.right, level + 1, a);
che(root.left, level + 1, a);
}
}
This is the link for the Question
The che function is never called.
It is however not necessary to collect data in an array list. Instead make the recursive function return the height of the subtree it is called on. In the same function compare the height that is returned for the left and right subtree. If they are different, return a special value to indicate failure (like -2), otherwise return that common height plus one.
This allows the function to abort the search as soon as a height difference is found, avoiding the unnecessary traversal of the rest of the tree.
Here is how that would look:
class Solution
{
boolean check(Node root) {
return height(root) > -2;
}
private int height(Node root) {
if (root == null) return -1;
int left = height(root.left);
if (left == -2) return -2;
int right = height(root.right);
if (left == -1 || right == -1 || left == right) {
return 1 + Math.max(left, right);
}
return -2;
}
}

Finding the 'maximum' character in a linked list Java recursively

I am trying to find the "maximum" value in a linked list recursively using a helper function. I am just starting to learn about these in my class and am pretty confused. We have a custom class that defines the type Node and another function to calculate the size of the Node or linkedlist. I solved this problem when I was comparing integers, but with characters I am lost. Here is my code:
'''
static class Node {
public Node (char item, Node next) { this.item = item; this.next = next; }
public char item;
public Node next;
}
Node first; // this is the only instance variable,
// the access point to the list
// size
//
// a function to compute the size of the list, using a loop
// an empty list has size 0
public int size () {
int count = 0;
for (Node tmp = first; tmp != null; tmp = tmp.next)
count++;
return count;
}
/*
* maxCharacter
*
* a function to compute the 'maximum' character in the list using recursion
* You will want to create a helper function to
* do the recursion
*
* precondition: list is not empty
*
* Examples:
* ["ababcdefb"].maxCharacter() == 'f'
* ["eezzg"].maxCharacter() == 'z'
* ["a"].maxCharacter() == 'a'
*/
public char maxCharacter () {
return maxCharacterHelper(first, first.size());
}
public char maxCharacterHelper(Node first, int index) {
char[] alpha = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
int max = 0;
while(index > 0 )
max = alpha.indexOf(first.item) > max ? first.item : max;
maxCharacterHelper(first, index-1);
return max;
}
'''
If you could explain how I would loop through the list recursively while maintaining the greatest char I would greatly appreciate it.
The golden rule with recursion is "Think of the base case first, then write the recurrence".
In this case, the base is the empty list. In this case, the maximum is the last value you've seen.
The recurrence is just a call to the rest of the list with the highest value you've called.
public static MaxNode(Node n, char currentMax) {
if (n == null) // base case, we're at the end.
return currentMax;
// recurrence
return MaxNode(n.next, currentMax > n.item ? currentMax : n.item);
}
For simple ASCII values, you can treat the maximum using the > operator.
Your while loop is confusing because of indentation and because you never change index. However, I don't think you need it if your intent is to use recursion. Generally with recursion you need to establish a base case from which you cannot recurse. For a linked list the natural base case is where there is no next node, rather than index-based.
if (current.next == null)
return alpha.indexOf(current.item);
Otherwise combine the recursion return with the current value
int remainingMax = maxCharacterHelper(current);
int currentValue = alpha.indexOf(current.item);
return (remainingMax > currentValue) ? remainingMax : currentValue;
Here is how I would put it together
//I made it static because it is not a method of a specific Node
public static int maxCharacterHelper(Node currentNode){
// remaining list includes only current node, so this one has max value
if (current.next == null)
return alpha.indexOf(current.item);
//otherwise take the larger of remaining list and current node
int remainingMax = maxCharacterHelper(current.next);
int currentValue = alpha.indexOf(current.item);
return (remainingMax > currentValue) ? remainingMax : currentValue;
}

Uniquely number nodes of a Binary Tree

How would I go about setting an index for each node after generating a binary tree?
(a) (1)
(x) (r) => (2) (3)
(o)(t)(t)(x) (4)(5)(6)(7)
So I can then use a call such as getIndex()at a particular node to return its index.
My tree class:
public class BT<E>{
E value;
BT<E> left, right;
int Index;
public BT(E value)
{
this.value=value;
}
public BT (E value, BT left, BT right)
{
this.value = value;
this.left = left;
this.right = right;
}
Breadth-first traversal.
Queue<BT> queue = new LinkedList<BT>() ;
public void breadth(BT root) {
if (root == null)
return;
queue.clear();
queue.add(root);
int index = 0;
while(!queue.isEmpty()){
BT node = queue.remove();
node.Index = index;
index++;
if(node.left != null) queue.add(node.left);
if(node.right != null) queue.add(node.right);
}
}
Adapted from here.
If you are doing this after the tree is fully created, then something that uses level-order traversal will work. It's not terribly efficient, but it's straight-forward recursion:
/* Method to set index based on level-order traversal of tree */
public void initIndices(BT root) {
int maxIndexSoFar = 0;
for (int d = 1; d <= root.height(); ++d)
maxIndexSoFar = setIndexAtLevel(root, d, maxIndexSoFar);
}
/* Method to set index of all nodes at a given level */
private int setIndexAtLevel(BT node, int level, int index) {
if (tree == null)
return index;
if (level == 1) {
index++;
node.setIndex(index);
return index;
}
else if (level > 1) {
int newIndex = setIndexAtLevel(node.left, level-1, index);
newIndex = setIndexAtLevel(node.right, level-1, newIndex);
return newIndex;
}
return -1;
}
I'll leave you to create the height() method and setIndex() methods. Fair warning, I have not tested this at all, so pardon any typos.
So you are to implement a procedure getIndex(int index) which has to return you the node with that index?
If so, you are looking for an efficient way to represent a binary tree.
You could traverse the tree for each call to getIndex but this wouldn't be efficient...
An efficient solution is to store the complete binary tree in an array, because of the O(1) access it provides. Store a node n at index n in the array and its child nodes at index 2*n and (2*n) - 1. But here the restrictions are that the tree has to be complete and the size of an array is not variable (if the binary tree becomes too big, a bigger array (usually twice as big) should be made and all elements should be copied).
This is a handy solution because :
Node access is in O(1) but a procedure like addNode() would become amortized in O(1). (*)
A node does not have to remember it's child nodes --> this.left becomes this.left() with the implementation of left() provided below.
A possible implementation for left() procedure.
static int[] binaryTreeArray = new int[maxTreeSize]; // BT of integers for example
...
public int left() { // returns integer or ... (type of your nodes)
return binaryTreeArray[(this.Index)*2]; // O(1)
}
(*) An addNode()-like procedure would add nodes in O(1) (binaryTreeArray[index] = nodeValue;) most of the time but when the binaryTreeArray is full it will have to make a bigger array that is usually twice as big (O(n) for the copying). It can be shown that this has an amortized cost of O(1) but this has no added value for this answer.

find closest element in ArrayList

I have a sorted array. Given a key value (not necessarily in the table), I want to find the element in the table that is closes to the key value.
I have considered using a binary search, but I need to return the closest element if the key is not in the table (not -1). What should I try to do?
If there is no matches return -1. This is my current try with binary search:
public static long binarySearch (ArrayList<Long> arr, int first, int last, long key)
{
if (first > last) return -1;
int mid = first + (last - first)/2;
if (arr.get(mid) == key)
return mid;
else if (arr.get(mid) > key)
return binarySearch(arr, first, mid - 1, key);
else
return binarySearch(arr, mid + 1, last, key);
}
Change:
if (first > last) return -1;
to
if (first > last) {
// if either first or last is negative, return the first element.
// if either first or last are greater than arr length, return the last element.
// otherwise, get values in the array for indecies first and last, compare then to
// your key and return the closest.
}
Try something like (untested):
public static Long getClosest(List<Long> sortedList, Long key) {
int index = Collections.binarySearch(sortedList, key);
Long closest;
if (index >= 0) {
closest = sortedList.get(index);
} else {
index = -index - 1;
if (index == 0){
closest = sortedList.get(index);
} else if (index == sortedList.size()){
closest = sortedList.get(index - 1);
} else {
Long prev = sortedList.get(index - 1);
Long next = sortedList.get(index);
closest = ((key - prev) < (next - key)) ? prev : next;
}
}
return closest;
}
As said, this code is untested and you might have to check if it returns the correct value for all the corner cases.
When element at mid position isn't equal to key, You can calculate delta as abs(key-arr.get(mid)) and check whether it is lowest than actual delta (the lowest delta, the closest value You've got). In the end, if You don't find key in array, You return delta instead -1.
Notice, that You can NOT initialise delta with 0, because any later calculated delta will be greater than 0.
This will solve the question, to find the closest value, find the sum of the nearing index in the List, say for example {1,4,6,7,8,19} and key 3. the binary search will have the final subset with 1 and 4,
if (1+4 > 3+3) ? return 1 else return 4
if (first > last)
{
// This makes an Invalid case
return -1;
}
if (first == last)
{
// then get the valueOf(firstIndex)
return arr.get(first-1);
}
if (first + 1 == last)
{
// gets value from the first Index
int fistKey = arr.get(first-1);
// gets value from first Index + 1 i.e next Index
int nextKey = arr.get(first);
// if valueof(firstIndex) + valueOf(nextIndex) > key then,
// key will be closer to valueOf(firstIndex)
// else key will be closer to valueOf(nextIndex)
return ((fistKey + nextKey) > (key + key)) ? fistKey : nextKey;
}
else
{
// assuming List will start its index from 0, then "-1" used for mid calculation
int mid = (last+1)/2;
int keyFromList = arr.get(mid-1);
if (keyFromList == key)
return key;
if (keyFromList > key)
return binarySearch(arr, first, mid , key);
else
return binarySearch(arr, mid, last , key);
}
Fortunately, the Java standard libraries include Arrays.binarySearch which gives you the "insertion point" of an element if it is not included in an array:
Returns: index of the search key, if it is contained in the array;
otherwise, (-(insertion point) - 1). The insertion point is defined as
the point at which the key would be inserted into the array: the
index of the first element greater than the key, or a.length if all
elements in the array are less than the specified key. Note that
this guarantees that the return value will be >= 0 if and only if the
key is found.
With that we can implement your requirement very concisely:
import java.util.Arrays;
public class ClosestValue
{
static long closestValue(long[] sorted, long key)
{
if(sorted.length==1) {return sorted[0];} // trivial case
if(key<sorted[0]) {return sorted[0];} // lower boundary
if(key>sorted[sorted.length-1]) {return sorted[sorted.length-1];} // upper boundary
int pos = Arrays.binarySearch(sorted, key);
if(pos>=0) {return sorted[pos];} // we found an exact match
// we didn't find an exact match, now we have two candidates: insertion point and insertion point-1 (we excluded the trivial case before)
// pos = -ip-1 | +ip -pos => ip = -pos-1
int ip = -pos-1;
long closest;
if(sorted[ip]-key<key-sorted[ip-1]) {closest=sorted[ip];} // < can be <= if smaller value is preferred
else {closest=sorted[ip-1];}
return closest;
}
public static void main(String[] args)
{
System.out.println(closestValue(new long[] {1,4,6,7,8,19},3));
System.out.println(closestValue(new long[] {1,2,4,5},3));
System.out.println(closestValue(new long[] {1,2,4,5},7));
System.out.println(closestValue(new long[] {1,2,4,5},-5));
}
}

Binary Search Tree Iterative Ceiling Method in Java

I'm working on a problem for class I'm stuck on. It involves adding a methods to the Binary Search Tree found here: http://algs4.cs.princeton.edu/32bst/BST.java.html
I need to develop an iterative ceiling method that finds the ceiling for a given key. It cannot be recursive.
Here is my code so far. I understand the basics of the algorithm I am supposed to implement, but I'm finding actually doing so hard to wrap my head around.
Thanks in advance for any help you might be able to offer.
public Key ceiling_i(Key key)
{
Node t = root;
for(int i = 0; i < size(); i++){
int cmp = key.compareTo(t.key);
if(cmp == 0) return t.key;
else if(cmp < 0) t = t.left;
else if(cmp > 0) t = t.right;
}
return null;
}
Edit: The main problem I am having is how to deal with the iterations after the first one. According to my book, "If a given key is greater than the key at the root of a BST,
then the ceiling of key (the largest key in the BST greater
than or equal to key) must be in the right subtree. If key is
less than the key at the root, then the ceiling of key could
be in the left subtree; if not (or if key is equal to the key
at the root), then the key at the root is the ceiling of key." I am not sure how to deal with that in the loop.
Your code is a good start. But your for loop does not make sense to me.
public Key ceiling_i(Key key)
{
Node t = root;
Node t largestVisited = null;
while(t != null) {
int cmp = key.compareTo(t.key);
if(cmp == 0) return t.key;
else if(cmp < 0) { largestVisited = Min(t, largestVisited); t = t.left; }
else if(cmp > 0) { t = t.right; largestVisited = Min(t, largestVisited); }
}
return largestVisited;
}
Node Min(Node a, Node b) { return the node with the smaller key; }
Tip: You could have derived this code by first writing the recursive solution and noticing that it is tail recursive. Tail recursive functions can trivially made non-recursive by just reusing the already existing local variables. No need to open another stack-frame if you won't ever use the old one again.
The code from that book is NOT tail-recursive because the first ceiling() call has operations done on it before the returns.
private Node ceiling(Node x, Key key) {
if (x == null) return null;
int cmp = key.compareTo(x.key);
if (cmp == 0) return x;
if (cmp < 0) {
Node t = ceiling(x.left, key);
if (t != null) return t;
else return x;
}
return ceiling(x.right, key);
}
Change ceilng() so the recursive calls are an "accumulator" type of tail-call. Do this by passing additional parameters which hold the work done so far.
Null or a node is passed as x.left when cmp < 0. What has "accumulated" so far is a larger-than-item node x found at this conditional test.
In the original version after the the first recursive call, t is either null or some tree node. Node x is then used after if t is null. In a modified version an additional parameter will be passed the x node.
In the other conditional test of cmp > 0 with the tail call, there is no new "accumulated" work since x is smaller than the item and is not used in deciding a return value if x.right is null.
Notice what happens if we pass an "accumulated x" to "larger" in a modified ceiling(x, key, larger) function. In this modified function, the condition "if (x == null) return null" is replaced by "if (x == null) return larger" and all the t-value evaluations are removed after the first recursive call. With the second tail-call just pass null to larger.
So the conversion should look something like this:
private Node ceiling (Node x, Key key, Node larger) {
if (x == null) return larger;
int cmp = key.compareTo(x.key);
if (cmp == 0) return x;
if (cmp < 0) {
return ceiling(x.left, key, x);
}
return ceiling(x.right, key, null);
}
Now the function is tail-recursive and can be further converted into an iterative loop form.
private Node ceiling (Node x, Key key) {
Node larger = null;
while (x != null) {
int cmp = key.compareTo(x.key);
if (cmp == 0) return x;
if (cmp < 0) {
larger = x;
x = x.left;
} else {
x = x.right;
}
}
return larger;
}

Categories