How to find max value(not key) in an AVL tree? - java

I build a simple AVL tree as following, each node has key and value. Now I want to implement a method that could return the key of node which has the largest value. For example, if I have a tree like:
(7,1)
/ \
(4,3) (13,8)
/ \ / \
(2,4) (6,3) (11,8) (15,2)
/ \ / / \ / \
(1,9)(3,0)(5,16)(9,2)(12,3)(14,3)(16,5)
/ \
(8,19)(10,4)
The method would return 8, as the node (8,19) has the largest value. Following is my avl tree and node constructor. I do try to implement this method by hand but somehow it doesn't work. I'd be grateful if someone coule help me.
public class AVLTreeImp<T extends Comparable<? super T>,V> implements AVLTree<T,V>{
private Node<T, V> root;
public class Node<T extends Comparable<? super T>,V> implements AVLTree.Node{
T key;
V value;
Node<T,V> left;
Node<T,V> right;
Node<T,V> parent;
int height;
public Node(){
this.key = null;
this.left = null;
this.right = null;
this.parent = null;
this.height = 0;
this.value = null;
}
public Node(T key, V value, Node<T,V> left, Node<T,V> right){
this.key = key;
this.left = left;
this.right = right;
this.parent = null;
this.height = 0;
this.value = value;
}
}
public AVLTreeImp(){
this.root = null;
}
#Override
public void insert(T key, V value){
root = insert(root,key,value);
}
private Node<T,V> insert(Node<T,V> node, T key, V value){
if (node == null){
node = new Node<T,V>(key, value,null,null);
}else{
if (key.compareTo(node.key) < 0){
node.left = insert(node.left, key, value);
if (!(isBalanced(node))) {
if (key.compareTo(node.left.key) < 0) {
node = leftLeftRotation(node);
} else {
node = leftRightRotation(node);
}
}
}else if (key.compareTo(node.key) > 0){
node.right = insert(node.right,key,value);
if (!(isBalanced(node))){
if (key.compareTo(node.right.key) > 0){
node = rightRightRotation(node);
}else{
node = rightLeftRotation(node);
}
}
}
}
regenerateHeight(node);
return node;
}
Below is my implementation of this method, I'm not sure what's wrong with this.
public Integer findMax(){
Node<Integer,Integer> result = (Node<Integer,Integer>)root;
result.value = 0;
return findMax((Node<Integer, Integer>) root,result);
}
private Integer findMax(Node<Integer,Integer> node,Node<Integer,Integer> result){
if (node == null){
return result.key;
}
if (node.value > result.value ||
(node.value == result.value && node.key.compareTo(result.key) < 0)){
result = node;
}
findMax(node.left,result);
findMax(node.right,result);
return result.key;
}

You have a balanced BST! That means operations like the following are efficient,
Insert/Remove
Max/Min key
Membership Query
But turns out, as comment suggested, you’d have to traverse the entire tree to find an element matching your criteria, which is a O(N) op, not optimal. Worse, your structure is recursive!
You can,
Maintain a priority queue keyed by your “value”
Build another tree keyed by your “value”
They are both far more efficient than a full tree look up.
However, without further context, I find you usage of the tree questionable? Why is your tree keyed by something you’re not operating on?

Your recursive findMax method is incorrect. You are assigning result = node;
but this is only local assignment not updating result when calling findMax(node.left,result); and findMax(node.right,result);
. This should work:
public Integer findMax(){
Node<Integer,Integer> result = (Node<Integer,Integer>)root;
result = findMax((Node<Integer, Integer>) root,result);
return result.key;
}
private Node<Integer,Integer> findMax(Node<Integer,Integer> node,Node<Integer,Integer> result){
if (node == null){
return result;
}
if (node.value > result.value ||
(node.value == result.value && node.key.compareTo(result.key) < 0)){
result = node;
}
result = findMax(node.left,result);
result = findMax(node.right,result);
return result;
}
More about passing java parameters here Is Java "pass-by-reference" or "pass-by-value"?

Related

How to push nodes from a Binary Tree into an Array?

I am struggling with pushing values from a Binary Search Tree into an array, but I also need them to be sorted. Here are the instructions of what is needed.
The toArray method should create and return an array containing every element in the tree in sorted order ("in order"). The capacity of this array should equal the number of elements it contains. This method should make use of the recursive private helper method toArray(BSTNode, List) to generate the array. This array will need be created as an array of Comparable objects and cast to an array of E objects. You can use Collection's toArray(E[]) method to help with the array generation.
Therefore here is my code I have so far:
public E[] toArray()
{
List<E> lista = new ArrayList<E>();
toArray(root, lista);
E[] good = (E[]) lista.toArray();
return good;
}
private void toArray(BSTNode<E> node, List<E> aList)
{
if(node.left != null)
{
aList.add(node.left.data);
}
}
Here is the rest of the code for references, but I am more focused on the toArray methods more than anything. I can't figure out how to sort them into an array. Please help.
public class BinarySearchTree<E extends Comparable<E>>
{
private BSTNode<E> root; // root of overall tree
private int numElements;
// post: constructs an empty search tree
public BinarySearchTree()
{
root = null;
}
// post: value added to tree so as to preserve binary search tree
public void add(E value)
{
root = add(root, value);
}
// post: value added to tree so as to preserve binary search tree
private BSTNode<E> add(BSTNode<E> node, E value)
{
if (node == null)
{
node = new BSTNode<E>(value);
numElements++;
}
else if (node.data.compareTo(value) > 0)
{
node.left = add(node.left, value);
}
else if (node.data.compareTo(value) < 0)
{
node.right = add(node.right, value);
}
return node;
}
// post: returns true if tree contains value, returns false otherwise
public boolean contains(E value)
{
return contains(root, value);
}
// post: returns true if given tree contains value, returns false otherwise
private boolean contains(BSTNode<E> node, E value)
{
if (node == null)
{
return false;
}
else
{
int compare = value.compareTo(node.data);
if (compare == 0)
{
return true;
}
else if (compare < 0)
{
return contains(node.left, value);
}
else
{ // compare > 0
return contains(node.right, value);
}
}
}
public void remove(E value)
{
root = remove(root, value);
}
private BSTNode<E> remove(BSTNode<E> node, E value)
{
if(node == null)
{
return null;
}
else if(node.data.compareTo(value) < 0)
{
node.right = remove(node.right, value);
}
else if(node.data.compareTo(value) > 0)
{
node.left = remove(node.left, value);
}
else
{
if(node.right == null)
{
numElements--;
return node.left;// no R child; replace w/ L
}
else if(node.left == null)
{
numElements--;
return node.right; // no L child; replace w/ R
}
else
{
// both children; replace w/ max from L
node.data = getMax(node.left);
node.left = remove(node.left, node.data);
}
}
return node;
}
private E getMax(BSTNode<E> node)
{
if(node.right == null)
{
return node.data;
}
else
{
return getMax(node.right);
}
}
public void clear()
{
root = null;
numElements--;
}
public boolean isEmpty()
{
if(numElements == 0)
{
return true;
}
else
{
return false;
}
}
public int size()
{
return numElements;
}
//My toArray Methods will go here.
public Iterator<E> iterator()
{
return new Iterator<>(root);
}
public static class Iterator<E>
{
private Stack<BSTNode<E>> stack;
public Iterator(BSTNode<E> node)
{
this.stack = new Stack<>();
while (node != null)
{
stack.push(node);
node = node.left;
}
}
public boolean hasNext()
{
return !stack.isEmpty();
}
public E next()
{
BSTNode<E> goodDays = stack.pop();
E result = goodDays.data;
if (goodDays.right != null)
{
goodDays = goodDays.right;
while (goodDays != null)
{
stack.push(goodDays);
goodDays = goodDays.left;
}
}
return result;
}
}
private static class BSTNode<E>
{
public E data;
public BSTNode<E> left;
public BSTNode<E> right;
public BSTNode(E data)
{
this(data, null, null);
}
public BSTNode(E data, BSTNode<E> left, BSTNode<E> right)
{
this.data = data;
this.left = left;
this.right = right;
}
}
}
Wait, this is a Binary Search Tree so it's already sorted.
Then you need to walk the tree.
Given you have something like:
4
/ \
2 6
\ / \
3 5 9
To insert it you have to:
Given a tree root
A. If the tree is null, there's nothing to insert.
B. If is not null:
B.1 Insert everything on the left
B.2 Insert the tree root
B.3 Insert everything on the right
Which would look like this:
void walkAndInsert(tree, array) {
if (tree == null) {//A
return
} else { //B
walkAndInsert(tree.left) //B.1
array.add(tree.root) //B.2
walkAndInsert(tree.right) //B.3
}
}
So applying these steps on the array:
Is tree null? No, then execute step #B (insert all left, root and all right)
//B
tree =
4
/ \
2 6
\ / \
3 5 9
array =[]
We take the left branch and repeat the process (step #B.1, insert all the left):
Is tree null? No, then execute #B
//B.1
tree =
2
\
3
array =[]
Since the left branch is null, the next execution would like like this:
Is tree null ? yes, then return
//A
tree =
array = []
This will conclude step B.1, we can go now to step B.2, insert root
//B.2
tree =
2
\
3
array =[2]
Followed by step B.3 insert all from right
Is tree null? No (there's a 3 there),
//B.3
tree =
3
array =[2]
Then execute #B.1 on this tree
Is the tree empty? Yes, this concludes this B.1
//A
tree =
array =[2]
Now in B.2 we insert this root
Is tree null? No (there's a 3 there),
//B.2
tree =
3
array =[2,3]
And finally we go to B.3 insert all from right
But there's nothing there, so we just return
//A
tree =
array =[2,3]
This finishes the left branch from our very initial tree.
So after B.1 is finished on our initial tree, we execute B.2 and our data looks like:
// B.2 on the initial tree
tree =
4
/ \
2 6
\ / \
3 5 9
array =[2,3,4]
And we repeat with the right side
Is null? no, then B on the branch with 5, insert 6, and step B on the branch with 9
//B.3
tree =
6
/ \
5 9
array =[2,3,4]
// B.1
tree =
5
array =[2,3,4]
// A
tree =
array =[2,3,4]
// B.2
tree =
5
array =[2,3,4,5]
// B.2
tree =
6
/ \
5 9
array =[2,3,4,5,6]
// B.3
tree =
9
array =[2,3,4,5,6]
// A
tree =
array =[2,3,4,5,6]
// B.2
tree =
9
array =[2,3,4,5,6,9]
Working example of the steps described here
import java.util.*;
import java.lang.reflect.Array;
import static java.lang.System.out;
class Tree<E extends Comparable<E>> {
E root;
Tree<E> left;
Tree<E> right;
void insert(E element) {
if (this.root == null) {
this.root = element;
this.left = new Tree<E>();
this.right = new Tree<E>();
} else if (element.compareTo(this.root) < 0 ) {
left.insert(element);
} else {
right.insert(element);
}
}
E[] toArray() {
List<E> a = new ArrayList<>();
toArray(this, a);
#SuppressWarnings("unchecked")
final E[] r = a.toArray((E[]) Array.newInstance(a.get(0).getClass(), a.size()));
return r;
}
// instance method just to retain the generic type E
private void toArray(Tree<E> t, List<E> list) {
if (t == null || t.root == null) {
return;
} else {
toArray(t.left, list);
list.add(t.root);
toArray(t.right, list);
}
}
public static void main(String ... args) {
Tree<String> t = new Tree<>();
t.insert("hola");
t.insert("adios");
t.insert("fuimonos");
System.out.println(Arrays.toString(t.toArray()));
}
}
I figured it out. I will disclose the code and explain what's going on.
In the public I make a List that will soon be an Array List.
Then I call the toArray helper method (private) to set the values. Root for the top one and lista for the list it will go in.
After make the Array and set the size with numElements. Comparable is in there since at the very top of my code, that's what it extends.
Then put the that array into the lista.
Finally return it.
public E[] toArray()
{
List<E> lista = new ArrayList<E>();
toArray(root, lista);
E[] arr = (E[]) new Comparable[numElements];
lista.toArray(arr);
return arr;
}
In the private I do some recursion.
As long as the node is not empty(null) then the array will search for left nodes continuously until it has no left (left) therefore add that into the array.
Then adds the right ones.
private void toArray(BSTNode<E> node, List<E> aList)
{
if(node != null)
{
toArray(node.left, aList);
aList.add(node.data);
toArray(node.right, aList);
}
}
Sorry if that was hard to understand, I'm not the best at explaining things, however this worked for me.

Issues with Binary TreeNode editing function

I'm having some trouble with my code.
This function's purpose is to traverse through a binary tree and edit it such that branches from a certain point are replaced by new ones housed under the "newNode". Currently, it returns the same value for the tree that it started with (so the current = newNode doesn't actually edit the original tree).
Can anyone explain why this is? Thanks.
public static Node editTree(Node current, Node newNode, String value) {
if (current == null) {
return null;
}
if (current.value.equals(value)) {
current = newNode;
return current;
}
if (!current.isLeaf()) {
editTree(current.getLeft(), newNode, value);
editTree(current.getRight(), newNode, value);
return current;
}
return current;
}
This has to be accomplished in such a way that a tree (the original tree) is first traversed until a certain value is found. Then the node that houses the value is entirely replaced with a new node, which contains its own value and its own left and right nodes. A global variable Node is then set to be equal to the value of the newly edited tree, which is then used to reset the original trees value. The reason it can't be done any other way is because I can't set the values of the left and right nodes in the node class, since it's not permitted.
In the line current = newNode; you are just changing the reference of the current variable in your method. It won't affect the original tree. You need to set newNode as a value to the previous node.
For more information, see Is Java “pass-by-reference” or “pass-by-value”?
Assigning a new value to current will have no effect outside of the method. I think you should use the return value:
public static Node editTree(Node current, Node newNode, String value) {
if (current == null) {
return null;
}
if (current.value.equals(value)) {
return newNode;
}
if (!current.isLeaf()) {
current.setLeft(editTree(current.getLeft(), newNode, value));
current.setRight(editTree(current.getRight(), newNode, value));
}
return current;
}
UPDATE: Complete code, and test results
public class Node {
public final String value;
private Node left;
private Node right;
Node(String value, Node left, Node right) {
this.value = value;
this.left = left;
this.right = right;
}
public Node getLeft() {
return left;
}
public void setLeft(Node left) {
this.left = left;
}
public Node getRight() {
return right;
}
public void setRight(Node right) {
this.right = right;
}
public boolean isLeaf() {
return left == null && right == null;
}
#Override
public String toString() {
return "Node{" + "value=" + value + ", left=" + left + ", right=" + right + '}';
}
}
Test method:
public static void main(String[] args) {
Node tree = new Node("b",
new Node("a", null, null), new Node("c", null, null));
System.out.println(tree);
tree = editTree(tree, new Node("d", null, null), "c");
System.out.println(tree);
}
Results:
Node{value=b, left=Node{value=a, left=null, right=null}, right=Node{value=c, left=null, right=null}}
Node{value=b, left=Node{value=a, left=null, right=null}, right=Node{value=d, left=null, right=null}}

Turning a regular Binary Search Tree into an Balanced Binary Search Tree

I was able to write my own Binary Search Tree, but I am having a lot of trouble figuring out how to turn that into a Balanced Binary Search tree.
Could someone help me implement a Balanced binary search tree code with the regular binary tree.
I think I was successful in changing my TreeNode class to have the necessary changes.
I added another key and another value along with another TreeNode middle to hold the middle pointer when you get to a 3 node in the tree.
I then added another constructor to hold the case if it was a 3 node. I believe I did this right.
public class TreeNode<V>
{
public int key;
public int key1;
public V value;
public V value1;
public TreeNode<V> left;
public TreeNode<V> right;
public TreeNode<V> middle;
public TreeNode(int key, V value)
{
this.key = key;
this.value = value;
this.left = null;
this.right = null;
}
public TreeNode(int key, V value, int key1, V value1)
{
this.key = key;
this.key1 = key1;
this.value = value;
this.value1 = value1;
this.left = null;
this.right = null;
this.middle = null;
}
The tough part comes to when I need to change the actual BST Class. I know the put is going to change quite a bit because we have to check and see if it is a 2 node or a 3 node, as well as check for what the parent node is.
Here is what I have so far:
public class BST<V>
{
private TreeNode<V> root;
public BST()
{
this.root = null;
}
public V get(int key)
{
return get(root, key);
}
private V get(TreeNode<V> current, int key)
{
if (current == null)
return null;
else if (key == current.key)
return current.value;
else if (key < current.key)
return get(current.left, key);
else
return get(current.right, key);
}
public void put(int key, V value)
{
if (root == null)
root = new TreeNode<>(key, value);
else
put(root, key, value);
}
private void put(TreeNode<V> current, int key, V value)
{
if (key == current.key)
{
current.value = value;
return;
}
else if (key < current.key)
{
if (current.left == null)
{
current.left = new TreeNode<>(key, value);
return;
}
else
put(current.left, key, value);
}
else
{
if (current.right == null)
{
current.right = new TreeNode<>(key, value);
return;
}
else
put(current.right, key, value);
}
}
}
My difficultly comes most with the recursion. I understand how basic recursion works, but using it to implement a balanced binary search tree is seeming a much more difficult talk than originally thought.
You only want a binary search tree, correct? If so, there isn't really a need for keys (Which are used for M-ary trees).
This isn't exactly an answer, but hopefully this will help simplify your code at least a little bit.

Writing my own 2-node or 3-node Binary Search Tree

I am supposed to create a Binary Search Tree or B-Tree with a maximum of three nodes. Any one "parent" or "child" node can hold 1 or 2 values making it so that it can either have 2 or 3 "child" pointers on it.
For example: This is okay because there is only a maximum of 2 values in each set
23 30
/ | \
12 25 [35 38]
Where as this is not: because the root has 3 values in it and 4 "child" nodes
12 15 18
/ | | \
4 14 16 20
I was able to write my own Binary Search Tree, but I am having a lot of trouble figuring out how to turn that into a 2node or 3node Binary Search tree.
Could someone help me implement a 2node or 3node binary search tree code with the regular binary tree.
public class TreeNode<K extends Comparable<K>, V>
{
public K key;
public V value;
public TreeNode<K,V> left;
public TreeNode<K,V> right;
public TreeNode(K key, V value)
{
this.key = key;
this.value = value;
this.left = null;
this.right = null;
}
}
The tough part comes to when I need to change the actual BST Class. I know the put is going to change quite a bit because we have to check and see if it is a 2 node or a 3 node.
Here is what I have so far:
public class BST<K extends Comparable<K>, V>
{
private TreeNode<K, V> root;
public BST()
{
this.root = null;
}
public void put(K key, V value)
{
if (root == null)
root = new TreeNode<>(key, value);
else
put(root, key, value);
}
private void put(TreeNode<K, V> current, K key, V value)
{
int n = key.compareTo(current.key);
if (n == 0)
{
current.value = value;
return;
}
else if (n < 0)
{
if (current.left == null)
{
current.left = new TreeNode<>(key, value);
return;
}
else
put(current.left, key, value);
}
else
{
if (current.right == null)
{
current.right = new TreeNode<>(key, value);
return;
}
else
put(current.right, key, value);
}
}
public V get(K key)
{
return get(root, key);
}
private V get(TreeNode<K,V> current, K key)
{
if (current == null)
return null;
else
{
int n = key.compareTo(current.key);
if (n==0)
return current.value;
else if (n < 0)
return get(current.left, key);
else
return get(current.right, key);
}
}
public int size()
{
return size(root);
}
private int size(TreeNode<K,V> current)
{
if(current == null)
return 0;
else
return size(current.left) + size(current.right) + 1;
}
public int depth()
{
return depth(root) - 1;
}
private int depth(TreeNode<K,V> current)
{
if(current == null)
return 0;
else
return Math.max(depth(current.left), depth(current.right)) + 1;
}
}

Insertion in Heap in java

Here is an implementation of a Heap in java without using array but I have some problem in inserting data in it for example when i insert 1,3,2,5,8 it inserts 5,8 two times one as subtree of 3 and another one as subtree of 2.
public class Heap {
private class Node {
private Node left, right,parent;
private int key;
private Node(int key) {
this.key = key;
}
}
private Node root;
public void insert(int key) {
root = insert(root,key,null);
}
private Node insert(Node x, int key,Node parent) {
if(x == null){
x = new Node(key);
x.parent = parent;
return x;
}if(x.left == null){
x.left = insert(x.left, key,x);
}else if (x.right == null) {
x.right = insert(x.right, key,x);
}else{
x.left = insert(x.left, key,x);
x.right = insert(x.right, key,x);
}
return x;
}
}
Problem is
x.left = insert(x.left, key,x);
x.right = insert(x.right, key,x);
you are simply inserting to both sub heaps...
This is not how heap works...
else {
x.left = insert(x.left, key, x);
x.right = insert(x.right, key, x);
}
inserts the key in both sub-trees of x.
You have to decide which branch to take, e.g. by comparing the key to the key at x, and using the right branch if key >= x.key, otherwise take the left branch (if done properly you'll get an ordered tree), or take the branch which is the smallest sub-tree of x.

Categories