Get Random Node from Tree - java

My method is suppose to return a random node from a BST, however it is not working correctly and I am unsure of why. The method is suppose to traverse the tree using preorder traversal while incrementing the counter. Once the counter is equal to the randomly generated number, it is suppose to return the node.
// get random node
public Node getRandomNode(Node root) {
// get random value between 0 to size of BST
Random ran = new Random();
int ranNum = ran.nextInt(size + 1);
Node temp = root;
System.out.println("random number is: " + ranNum);
root = getRandomNode(ranNum, temp);
return root;
}
int count = 0;
public Node getRandomNode(int ranNum, Node temp) {
// traverse through the tree and increment count until count is the
// random number,
// in which case return the node it is on
if (temp != null && count != ranNum) {
count++;
temp = getRandomNode(ranNum, temp.left);
System.out.println(temp.data);
temp = getRandomNode(ranNum, temp.right);
}
// if count is equal to the randomly generated number
return temp;
}
EDIT:
Using BFS
public Node getRandomNode(int ranNum, int count, Node temp) {
if(temp == null)
return null;
Queue<Node> q = new LinkedList<Node>();
q.add(temp);
count++;
while(!q.isEmpty() && count != ranNum) {
Node n = q.remove();
System.out.println(" " + n.data);
if(count == ranNum) {
System.out.println("final node: " + n.data);
return n;
}
if(n.left != null) {
q.add(n.left);
count++;
}
if(n.right != null) {
q.add(n.right);
count++;
}
}
return temp;
}

Your problem is in your recursive calls. Assume the random number is 1, you would expect the returned result to be the first node reached from the left subtree. Your code will say temp = getRandomNode(ranNum, temp.left);, and at this point the temp variable holds the correct answer, then you say temp = getRandomNode(ranNum, temp.right);, and at this point your temp variable holds an incorrect answer.
EDIT:
I decided to try to quickly fix your BFS implementation (quick = untested). Note that I'm trying to keep my code as close to yours as I can, so I'm avoiding making any changes to your algorithm.
public Node getRandomNode(Node temp, int ranNum) {
if(temp == null)
return null;
Queue<Node> q = new LinkedList<Node>();
q.add(temp);
int count = 0;
while(!q.isEmpty() && count <= ranNum) {
Node current = q.remove();
System.out.println(" " + result.data);
if(count == ranNum) {
System.out.println("final node: " + n.data);
return n;
}
if(n.left != null) {
q.add(n.left);
}
if(n.right != null) {
q.add(n.right);
}
count++
}
return null;
}
EDIT2:
Decided to fix your other version as well (still trying to stick very close to your original design).
// get random node
public Node getRandomNode(Node root) {
// get random value between 0 to size of BST
Random ran = new Random();
int ranNum = ran.nextInt(size + 1);
System.out.println("random number is: " + ranNum);
return getRandomNode(ranNum, root);
}
int count = 0;
public Node getRandomNode(int ranNum, Node node) {
// traverse through the tree and increment count until count is the
// random number,
// in which case return the node it is on
if (node == null || count == ranNum) {
return node;
}
count++;
temp = getRandomNode(ranNum, temp.left);
if (temp != null) {
return temp;
}
return getRandomNode(ranNum, temp.right);
}

Your implementation is not totally random because you are retrieving the random node based on a count (randomly picked) but not randomly traversed!
the tree should return null if and only if the tree is empty.
because you have generated the random based on the size of the tree.
the Tree has two paths either right or left ...going either way should be random too ! And should be thru one of them per method call(unless the the branch has been exhausted ).
I changed the count variable from field to a method parameter 'cause it seems to be a temp and has nothing to do with class
thus you don't have to reset the count each use of the class as well it is a good practice.
* another concern that you check for null what if the one of the side has a less
number than the other that would make the the function exits because the node is
null if this occurred on the left side traverse it the right would replace the temp but what if it happened on the other way it may return null !
by the way consider this as pseudo code I have never tested it :)
public Node getRandomNode(Node root) {
Random ran = new Random();
int ranNum = ran.nextInt(size + 1);
Node temp = root;
System.out.println("random number is: " + ranNum);
root = getRandomNode(ranNum, temp,0);
return root;
}
public Node getRandomNode(int ranNum, Node temp, int count ) {
// traverse through the tree and increment count until count is the
// random number,
// in which case return the node it is on
if (temp != null && count != ranNum) {
count++;
Random pathRan = new Random();
int pathNo= pathRan.nextInt(2);
Node temp2 = null;
if(pathNo == 0){//if 0 go to left
temp2 = getRandomNode(ranNum, temp.left,count);
if(temp2 == null){//this means that this path has nodes less than count ,so try the right.
temp2 = getRandomNode(ranNum, temp.right,count);
}
}else{//go to right
temp2 = getRandomNode(ranNum, temp.right,count);
if(temp2 == null){//this means that this path has nodes less than count ,so try the left.
temp2 = getRandomNode(ranNum, temp.left,count);
}
}
return temp2;
}
// if count is equal to the randomly generated number
return temp;
}

Related

calculate the length of the path to find maximum value in binary search tree

how can i find the length of the path that we used to find the maximum value in binary search tree (like form A====>B one step and A====>B====>C three steps)
and here's my code to find the maximum value and i have tried every solution in her but i didn't find an answer
public int findMax(){
if(root == null){ // check if the root is not empty
return 0;
}
Node current = root;
while(current.rightChild != null){
current =current.rightChild ;
}
return current.value ;
}
If you want to find the length of the path from root to the largest value, just keep a counter and increment it in the while loop, so that every time you traverse to the next node, the counter increases by one.
Something like this?
class Holder {
int length;
}
public int findMax(Holder holder) {
Node current = root;
Node result = null;
while (current != null) {
result = current;
current = current.rightChild;
if (current != null) {
holder.length++;
}
}
return result.value;
}
Holder.length should hold the length on return.
A binary tree is not guaranteed to be balanced, so you need to look at left and right children. Nicely recusive, something like this:
public int findMax (Node root) {
return findMaxWork (root, 0);
}
public int findMaxWork (Node node, int level) {
int leftMax = level;
if (node.left != null) leftMax = findMaxWork (node.left, level + 1);
int rightMax = level;
if (node.right != null) rightMax = findMaxWork (node.right, level + 1);
return Math.max(leftMax, rightMax);
}

Java - Counting Occurrences in a Linked List

As part of an assignment, I have to write a method that will print out repeating values in a linked list, as well as how many times they occur. Below is the method printRepeats() which uses the helper method countRepeats(ListNode node).
The issue is that the output of my method prints repeating values over and over again. For example, in a list with values 1 1 1 2 3 4 5 6 7 6, the output is 1 (Occurences = 3) 1 (Occurences = 3) 1 (Occurences = 3) 6 (Occurences = 2) 6 (Occurences = 2). Any value that repeats should only print once. Any suggestions? Thanks in advance!
public class LinkedList
{
private ListNode first;
public void printRepeats()
{
String ans = "";
ListNode temp = first;
while(temp != null)
{
if(countRepeats(temp) > 1 && ans.indexOf((int)temp.getValue()) == -1)
{
ans += temp.getValue();
System.out.print(temp.getValue() + " (Occurences = " + countRepeats(temp) + ") ");
}
temp = temp.getNext();
}
if(ans.length() == 0)
System.out.print("None of the elements repeat.");
}
private int countRepeats(ListNode node)
{
ListNode temp = first;
int count = 0;
while(temp != null)
{
if((int)temp.getValue() == (int)node.getValue())
count++;
temp = temp.getNext();
}
return count;
}
}
Considering that you must not use any other data structures than a LinkedList, you could:
Create another ListNode element as the first element of a list called "repeatedElements", that must contain pairs element/repetitions of such element.
When counting the repetitions of a single element, insert the element and the number of repetitions it has in "repeatedElements" list.
Before counting the number of repetitions of an element, sweep the repeatedElements list for the element. If the element is present, DO NOT print the output. If it is not, repeat your code as usual.
The system I described will contain more information than the specifically required (the number of repetitions of each element is stored), but it is likely that it will be needed again.
For counting occurrences you need to maintain track record of visited node also like if you have already count any node then need not to pick again those come on link list. Below program clearly explains this-
import java.util.ArrayList;
public class CustomLinkList {
public static void main(String[] args) {
ListNode linkedList = new ListNode(15);
linkedList.next =new ListNode(67);
linkedList.next.next =new ListNode(15);
linkedList.next.next.next =new ListNode(65);
linkedList.next.next.next.next =new ListNode(13);
linkedList.next.next.next.next.next =new ListNode(98);
linkedList.next.next.next.next.next.next =new ListNode(33);
linkedList.next.next.next.next.next.next.next =new ListNode(29);
linkedList.next.next.next.next.next.next.next.next =new ListNode(15);
ListNode printList = linkedList;
System.out.println("Custom Link List is ::: ");
while (printList.next != null){
System.out.printf("%d ",printList.info);
printList = printList.next;
}
System.out.println();
CustomLinkList.occurancesOfElement(linkedList);
}
public static void occurancesOfElement(ListNode listNode){
ArrayList<Integer> visitedNode = new ArrayList();
while(listNode !=null){
ListNode node = listNode;
int count = 0;
while (node !=null)
{
if(listNode.info == node.info && !visitedNode.contains(node.info)) {
count++;
}
node = node.next;
}
if(!visitedNode.contains(listNode.info))
System.out.println("Occurences of : "+listNode.info+" is "+ count);
visitedNode.add(listNode.info);
listNode = listNode.next;
}
}
}
class ListNode {
int info;
ListNode next;
ListNode(int info){
this.info = info;
next = null;
}
}
class DoublyListNode {
int info;
DoublyListNode previous;
DoublyListNode next;
}
}

How to compare strings and return position in a linked node?

I am trying to write a method that returns the position of a given object in a linked list.
The method signature should be public int getPosition(T anObject).
I am having trouble figuring out this method. Here is what I have so far:
public int getPosition(T anObject) {
int position = 0;
Node currentNode = firstNode;
for(int i = 0; i < length; i++) {
if(anObject.equals(currentNode.data)) {
position = i + 1;
currentNode = currentNode.next;
}
}
return position;
}
My output position isn't changing. It stays at zero.
Here is my driver program.
public class Homework3Driver {
public static void main(String[] args) {
String[] names = {"Abby", "Bobby", "Carla", "Doug"};
LList<String> nameList = new LList(names, 4);
String[] newNames = {"Edgar", "Frank"};
nameList.addAll(newNames);
System.out.println("Output should be 3: " + nameList.getPosition("Carla") + "\n");
System.out.println("Output should be 0 or a negative number: " + nameList.getPosition("George") + "\n");
}
}
An easier solution might be to iterate through the list, counting position and comparing node-by-node until you reach your node.
public int getPosition(T anObject) {
int position = 0;
Node currentNode = firstNode;
while(currentNode != null) {
if(anObject.equals(currentNode.data)) {
break; // we found our node so we can stop searching
}
position++;
currentNode = currentNode.next;
}
// we iterated through the whole list and didn't find the node
if(currentNode == null) {
return -1; // or some other error value
}
return position;
}
Take a moment to think about your logic...
Basically, you want to loop while currentNode is not null AND anObject is not equal to currentNode.data. When either of of those conditions become true, you want to exit the loop
For example...
int position = 0;
Node currentNode = firstNode;
while (currentNode != null && !anObject.equals(currentNode.data)) {
position++;
currentNode = currentNode.next;
}
return currentNode == null ? -1 : position;
Note, there are other ways to achieve it this, but this was just what popped into my head...
Note: This solution will continue to look for items until it gets to the end of the list. This means that it will return the position of the last matching item in the list and may be better suited for a getLastPosition() method.
You have to update the currentNode every iteration of the loop, not only if it matches:
for(int i = 0; i < length; i++)
{
if(anObject.equals(currentNode.data))
{
position = i + 1;
//currentNode = currentNode.next; // NOT HERE
}
currentNode = currentNode.next; // HERE
}

Convert an original binary tree to have it's decorates as the preorder indexes

I've had a go, and it works for the left subtree but not the right.
I'm close but my logic is wrong, can anyone help correct and explain the logic to this.
public static MyNode preOrderNumbering(MyNode n) {
if (n != null) {
n.obj = 0; // Set root decoration to 0;
preOrderHelper(n, 1); // Set decorations according to preorder.
}
return n;
}
public static MyNode preOrderHelper(MyNode n, int counter) {
if (n != null) {
if (n.left != null) {
n.left.obj = counter++; // Set the left object decoration to current count + 1;
preOrderHelper(n.left, counter);
}
if (n.right != null) {
n.right.obj = counter++; // Set the left object decoration to current count + 1;
preOrderHelper(n.right, counter);
}
}
return n;
}
Before:
After:
You need to update the counter with everything that's discovered on the left before going to the right.
Something like this:
public static int preOrderNumbering(MyNode n, int count){
if(n != null){
n.obj = ++count;
count = preOrderNumbering(n.left, count);
count = preOrderNumbering(n.right, count);
}
return count;
}
You're passing counter by value, not by reference (because that's how Java works), so when the recursion unwinds, so will the counter.
You could update the counter by returning the current value from the recursive call.

Counting the nodes in a binary search tree

I need to create a recursive method that takes as a parameter the root node of a binary search tree. This recursive method will then return the int value of the total number of nodes in the entire binary search tree.
This is what I have so far:
public class BinarySearchTree<E> extends AbstractSet<E>
{
protected Entry<E> root;
//called by the main method
public int nodes()
{
return nodes(root);
}
//nodes() will count and return the nodes in the binary search tree
private int nodes(Entry<E> current)
{
if(current.element != null)
{
if(current.left == null && current.right == null)
{
if(current.element == root.element)
return 1;
deleteEntry(current);
return 1 + nodes(current.parent);
}
else if(current.left != null && current.right == null)
return nodes(current.left);
else if(current.left == null && current.right != null)
return nodes(current.right);
else if(current.left != null && current.right != null)
return nodes(current.left) + nodes(current.right);
} else return 1;
return 0;
}
The main method calls nodes like so:
System.out.println ("\nThis section finds the number of nodes "
+ "in the tree");
System.out.println ("The BST has " + bst.nodes() + " nodes");
So I was running the search by traveling in order, once I'd get to a node with no children I would delete the current node and return to the parent node and continue. I ran a debug of the method I have above and the program crashes with a NullPointerException() when it finally counts and removes all the nodes on the left and right side of the root node and tries to return 1.
This is for my lab, the method MUST be recursive.
I'm very lost at this point, does anyone know what I'm doing wrong?
You are making this way too complicated. The basic idea of object oriented programming is that you trust objects to do the jobs they know the answers to. So if I'm a parent, I can count myself, and I let my children count themselves, and so forth.
private int nodes(Entry<E> current) {
// if it's null, it doesn't exist, return 0
if (current == null) return 0;
// count myself + my left child + my right child
return 1 + nodes(current.left) + nodes(current.right);
}
You have several issues:
You're deleting nodes as you count them? Is nodes() supposed to clear the tree?
You're treating root==null, root!=null&left==null&&right==null, root!=null&left!=null&right==null, etc as separate cases. They're not. You have three cases, which are not entirely exclusive:
If the current node is not null, add one to the count. (This should always be the case. The only case where it might be false is if the current node == root, and we can detect and sidestep that beforehand.)
If the current node has a left child, add the left child's count.
If the current node has a right child, add the right child's count.
You're traversing back up the tree for some ungodly reason. Looks like it has something to do with deleting nodes...?
But the biggest thing in my opinion is, you're not giving enough autonomy to the Entrys. :P
A node can count its own children. Trust it to.
class Entry<E> {
...
int count() {
int result = 1;
if (left != null) result += left.count();
if (right != null) result += right.count();
return result;
}
}
public int nodes() {
return (root == null) ? 0 : root.count();
}
If your teacher is incompetent, and insists on some node-counting function outside a node, you can do the same thing you were trying to do:
private int nodes(Entry<E> current) {
int result = 1;
if (current.left) result += nodes(current.left);
if (current.right) result += nodes(current.right);
return result;
}
public int nodes() {
return (root == null) ? 0 : nodes(root);
}
But that teacher should be fired, in my opinion. The Entry class is the real tree; BinarySearchTree is really just a container for a reference to the root.
Also notice, i don't give a damn about the parents. If we start counting from the root, and each node counts its children, which count their children, etc etc... then all nodes will be accounted for.
public int countNodes(Node root){
// empty trees always have zero nodes
if( root == null ){
return 0;
}
// a node with no leafes has exactly one node
// note from editor: this pice of code is a micro optimization
// and not necessary for the function to work correctly!
if( root.left == null && root.right == null ){
return 1;
}
// all other nodes count the nodes from their left and right subtree
// as well as themselves
return countNodes( root.left ) + countNodes( root.right ) + 1;
}
After you delete current in: deleteEntry(current);, you use current.parent in return 1 + nodes(current.parent);
May be this's the reason of throwing NullPointerException..
Hey I have a very clean counting implemented for a binary tree:
public class Binary<T> where T: IComparable<T>
{
private Node _root;
public int Count => _root.Count;
public void Insert(T item)
{
Node newNode = new Node(item);
if (_root == null)
_root = newNode;
else
{
Node prevNode = _root;
Node treeNode = _root;
while (treeNode != null)
{
prevNode = treeNode;
treeNode = newNode.Item.CompareTo(treeNode.Item) < 1 ? treeNode.Left : treeNode.Right;
}
newNode.Parent = prevNode;
if (newNode.Item.CompareTo(prevNode.Item) < 1)
prevNode.Left = newNode;
else
prevNode.Right = newNode;
}
}
public class Node
{
public T Item;
public Node Parent;
public Node Left;
public Node Right;
public Node(T item, Node parent = null, Node left = null, Node right = null)
{
Item = item;
Parent = parent;
Left = left;
Right = right;
}
public int Count
{
get
{
int count = 1;
count += Left?.Count ?? 0;
count += Right?.Count ?? 0;
return count;
}
}
}
}
Maybe this helps you to understand how to implement a class for a simple binary tree with a count.
This implementation accesses the count through a count in the corresponding node in the tree.
Let me now if you are not familiar with the markup of .NET 4.6

Categories

Resources