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

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.

Related

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}}

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

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"?

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;
}
}

Search function in Binary Tree Java

I am in the process of creating a binary tree for a project I've been working on where I insert people into a binary tree by name (the tree iterates through each character to determine which is bigger when inserting). Is there a way to make my tree search through the tree to find a person who match the name given to the program. This is my code so far
lass Node {
private String person;
private Node left;
private Node right;
public Node(String person) {
this.person = person;
left = null;
right = null;
}
//setters
protected void setLeft(Node left) {
this.left = left;
}
protected void setRight(Node right) {
this.right = right;
}
//getters
protected String getPerson() {
return person;
}
protected Node getLeft() {
return left;
}
protected Node getRight() {
return right;
}
}
public class BinaryTree {
private static Node root;
public BinaryTree() {
root = null;
}
public void insert(String person) {
root = insert(person, root);
}
//Check if node is leaf
public static boolean isLeaf() {
if(root.getLeft() == null && root.getRight() == null)
return false;
else
return true;
}
// Search tree for entered value
public static void searchTree(String search, Node tNode) {
// Not sure what to put into the part to make the method search through people in the tree
}
private Node insert(String person, Node tree) {
if(tree == null)
tree = new Node(person);
else {
int count = 1;
int x = 0;
while(person.toLowerCase().charAt(x) == tree.getPerson().toLowerCase().charAt(x) && count != tree.getPerson().length()) {
count = count + 1;
x = x + 1;
}
if(person.toLowerCase().charAt(x) != tree.getPerson().toLowerCase().charAt(x)) {
if(person.toLowerCase().charAt(x) < tree.getPerson().toLowerCase().charAt(x))
tree.setLeft(insert(person, tree.getLeft()));
else
tree.setRight(insert(person, tree.getRight()));
} else {
tree.setRight(insert(person, tree.getRight()));
}
}
return tree;
}
Can you please suggest how I should create a method to search through the tree
I Would suggest you to do these steps. These steps will give you a start.
Start from root and compare the Name to be searched with root using compareToIgnoreCase().
Depending upon the result move left or right.
Continue till either node becomes null or you find a match.
If you're trying to implement a binary search tree, you need to change the code in your setters to determine whether to add a person to the left or right node (by comparing the strings lexicographically) every time those methods are called. If the tree is not ordered, you'd have to search every node. When it's ordered, you'll be able to search in log n time.

Depth first search of tree with more than 2 child nodes in Java

I have an application which has a tree structure where each parent has 3 or more child nodes. Each node contains an integer value. I am trying to see if a given integer value is present in the tree. How do I do a Depth First Search on the tree? I understand that we start at the root and then explore as far as possible in each branch of the tree. I am having trouble implementing this in Java though. Would I need some sort of other data structure to do the traversal?
It would be helpful if someone could give a sample implementation.
The tree structure is as follows. I need to implement the findNode function:
public class Tree{
public Node{
Node [] children;
int val;
public Node[] getChildren(){
return children;
}
public getVal(int i){
return children[i].val;
}
}
public boolean findNode(int val){
}
}
iterative:
public boolean findNode(Node node, int value) {
Deque<Node> stack = new ArrayDeque<Node>();
stack.push(node);
while (!stack.isEmpty()) {
Node n = stack.pop();
if (n.getVal() == value)
return true;
for (Node child : n.getChildren())
stack.push(child);
}
return false;
}
recursive:
public boolean findNode(Node node, int value) {
if (node.getVal() == value)
return true;
for (Node n : node.getChildren()) {
if (findNode(n, value))
return true;
}
return false;
}
public int getVal() {
return val;
}
You do not need the getVal(int i) method. The node argument is the root of the tree.
Not tested, but show the structure of the algorithm at least. If you want BFS instead just replace the Stack with LinkedList.
public boolean findNodeDFS(Node root, int value) {
Stack<Node> nodes = new Stack<>(){{
add(root);
}};
while (!nodes.isEmpty()) {
Node current = nodes.pop();
if (current.getValue() == value) {
return true;
}
nodes.addAll(Arrays.asList(current.getChildren()));
}
return false;
}

Categories