Working on a University assignment which requires comparing nodes in a tree and making a count of nodes which meet a certain condition. I can see how I could do this iteratively, traversing the tree with a stack etc, but I'm certain the lecturers are looking for a recursive solution and I'm struggling to wrap my head around this particular implementation.
My current (flawed) implementation is:
public int traverseIncrement(User user, User reference) {
if(user == null)
return 0;
int count = 1;
if (user.getLeft() != null) {
if(user.getLevel() > reference.getLevel()) {
count += traverseIncrement(user.getLeft(), reference);
}
}
if (user.getRight() != null) {
if(user.getLevel() > reference.getLevel()) {
count += traverseIncrement(user.getRight(), reference);
}
}
return count;
}
There are two obvious problems, the first being that the first node is never evaluated and the second being that I am always one higher than the required output. Any nudge in the right direction would be helpful!
I think the two problems are related. Rather than assume the count is 1 then recurse depending upon whether the condition is met, you should set count depending upon the condition, then recurse. In other words, leave the evaluation of a given node up to the call that is handling that node.
Also, you can eliminate the check for left or right being null since your function already checks on entry.
public int traverseIncrement(User user, User reference) {
if(user == null)
return 0;
int count = (user.GetLevel() > reference.getLevel()) ? 1 : 0;
count += traverseIncrement(user.getLeft(), reference);
count += traverseIncrement(user.getRight(), reference);
return count;
}
Related
public int FirstNineIndexFromStart() {
if (first != null) {
if(this.first.item == 9.0)
return 0;
int index = 0;
for (Node i = this.first; i != null; i = i.next) {
if (i.item == 9.0)
return index;
index+=1;
}
return index;
}
return -1;
}
The goal of the project is to check the first index that the number 9 is at in a list from the start.
The two conditionals that must be met are that, if a list begins with the number 9, return the position number 0. If the list does not contain a 9 at all, return a -1.
Everything runs fine - EXCEPT if a 9 is not in the list. My test code gives me the wrong answer. It is not spitting out a -1 to be accounted for. Can someone please tell me how to make sure that, if a 9 is not present, it returns a -1?
I cannot use functions for this either. So, I cannot use contains().
If the loop completes, the number was not found. Change the second return index; to return -1;.
Note that there's no need for a special case for the first item. The loop should do the job just fine.
As we all know, when inserting into a complete binary tree we have to fill all the children for all the leafs from left to right. I have the following method that inserts a node into a complete binary tree.
//fields
private T item;
private int size;
private CBTree<T> left, right;
//add method
public void add(T item)
{
if(left == null)
{
left = new CBTree<T>(item);
size += left.size;
}
else if(right == null)
{
right = new CBTree<T>(item);
size += right.size;
}
else if(!((left.left != null) && (left.right != null)) &&
((right.left == null) || (right.right == null)))
{
left.add(item);
}
else
{
right.add(item);
}
}
The problem with this implementation is that after the 11th node it adds the 12th node to the left child of 8 instead of 6. I understand that this is happening because the following line is reassigning the root of this tree to be the left child of the root.
left.add(item);
So it is changing the root to 2. Is there a way to change the root back to its original value? I am trying to accomplish this without using stacks and queues.
It's not sufficient to just check children of children to determine which side to go to, because as soon as the tree reaches height 4 that won't work any more, since children of children of the root won't change from that point forward yet we can still go either left or right.
2 approaches come to mind:
Have a complete variable at each node.
A node with no children is complete.
A node with 2 complete children of equal size is complete.
Whenever update the tree (insert or delete) you update this variable for each affected node as well.
Mathematically determine whether a subtree is complete based on the size.
A tree of size 2^n - 1 is complete (for some n).
Note: this will only work if we're not allowed to freely delete elements without keeping the tree complete.
For either approach, when doing an insertion, we go left (left.add(item)) if either of these conditions are true:
the left subtree is not complete
the left and right subtrees are of the same size (both complete, meaning we're increasing the height with this insertion)
I'll leave the implementation details to you.
Note: you need to also update size when doing left.add(item); and right.add(item);. You could probably just stick a size++ in the add function, since we're adding 1 element so size increases by 1 no matter what.
Thanks to Dukeling's answer, the correct way to implement the method was to mathematically determine if the subtree was full. Here is the code:
//fields
private T item;
private int size;
private CBTree<T> left, right;
//add method
public void add(T item)
{
if(left == null)
{
left = new CBTree<T>(item);
}
else if(right == null)
{
right = new CBTree<T>(item);
}
else if(leftFull())
{
right.add(item);
}
else
{
left.add(item);
}
size++;
}
//Checks if the left subtree is full
public boolean leftFull()
{
int used, leafs = 1;
while(leafs <= size + 1)
{
leafs *= 2;
}
leafs /= 2;
used = (size + 1) % leafs;
if(used >= (leafs / 2))
{
return true;
}
else
{
return false;
}
}
I am writing a program for a recursive binary search. I have an input file with a series of sorted numbers, which I added to an ArrayList. The program searches to see if a key given by user input is in the ArrayList.
public static int binarySearch(int key, int median){
if(key == (int)array.get(median)){
return key;
}else if(key < (int)array.get(median)){
binarySearch(key,median-1);
}else if(key > (int)array.get(median)){
binarySearch(key,median+1);
}
return -1;
}
For example, let's say the key is 90. I debugged and placed watches at key and array.get(median). After stepping through the program, I discovered that even when key and array.get(median) are equal to 90, the program continues through the loop without ever returning the key. I know that recursion isn't ideal for this, but it's what I need to use.
This does not look like a correct binary search, as a binary search uses a divide and conquer approach. You only divide your list initially once and then check every element from there on. It would be better to then just divide your list again and so on, see https://en.wikipedia.org/wiki/Binary_search_algorithm
Anyway, to get your code running, why you do not get an result is most likely because you do not return the result of the recursion, but instead -1.
Remove the return -1 and set a return before your recursive binarySearch calls. And you are missing a exit condition when you do not find the element.
Example (still not a correct binary search):
public static int binarySearch(int key, int median){
if (median < 0 || median > array.size() - 1) { // element not found
return -1;
}
if (key == (int)array.get(median)){
return key;
} else if(key < (int)array.get(median)){
return binarySearch(key,median-1);
} else{
return binarySearch(key,median+1);
}
}
If all you care about is whether it is in the data structure...
public static boolean binarySearch(int key, int median){
if(key == (int)array.get(median)){
return true;
}else if(key < (int)array.get(median)){
return binarySearch(key,median-1);
}else if(key > (int)array.get(median)){
return binarySearch(key,median+1);
}
}
your code could be better written, but copied to to get across the important part of it
You should change your code like this:
public static int binarySearch(int key, int median){
if(key == (int)array.get(median)){
return key;
}else if(key < (int)array.get(median)){
return binarySearch(key,median-1);
}else if(key > (int)array.get(median)){
return binarySearch(key,median+1);
}
return -1;
}
If you do this your recursion would end but I will leave it to you to test out your binary search code. There are some things like the start index and the end index that you are ignoring in this method The return statements should be added because if you don't the control moves to the next statement in the method which is undesirable. Hope that helps!
The code posted is not a Binary Search and is, in fact, a Linear Search using recursion. A Binary Search divides the search space in half each step, binary meaning "two halves" in context. The result is that this Linear Search runs in O(n) and not the expected O(lg n) bounds of a Binary Search
Problems/issues (other than it not being a Binary Search):
The values from the recursive cases are lost as they are not themselves returned. The result of a recursive case must be used in some way (or why call the function at all?). In this case the value should be returned directly, eg. return binarySearch(..). This causes "continues through the loop without ever returning the key" - it actually does find the key, but discards the recursive result.
The code does not correctly detect the out-of-bounds terminal condition. This may result in an IndexOutOfBoundsException when the key is not found.
The step-left/right approach might never terminate correctly without further logic. For example, when the list is {1,3,5,7} and the value being sought is 4 the original code will ping-pong between indices 1 (value 3) and 2 (value 4). This will result in a StackOverflowError being thrown.
The key is returned. This makes little sense as the key is already known and it also prevents -1 from being detectable. Return the index found instead, or a boolean if only an existence test is required.
Take some time to understand and fix these issues .. and then read on for a spoiler if needed.
Consider this rewrite fixing the issues outlined above. Note that it is overly complex1 while still employing an inferior algorithm and O(n) performance. In any case;
// By taking in the List we make this function universal and not
// dependent upon a static field. It should probably take in a List<Integer>
// but I don't know what the actual type of "array" is. A more advanced
// implementation would take in List<Comparable> and then be modified to work
// with any objects that correctly implement said interface.
public static int linearSearch(int key, List list, int index, int step) {
if (index < 0 || index >= list.size()) {
// Base case: not found, out of bounds
return -1;
}
int x = (int)list.get(index);
if (key < x && step <= 0) { // need to look left, NOT looking right
// Recursive case: look left, returning result
return linearSearch(key, list, index - 1, -1);
} else if (key > x && step >= 0){ // need to look right, NOT looking left
// Recursive case: look right, returning result
return linearSearch(key, list, index + 1, +1);
} else if (key == x) {
// Base case: found key, return index found
return index;
} else {
// Base case: key not equal, refusing to ping-pong
return -1;
}
}
And then consider the use of this helper/wrapper function;
// Returns the index in "array" where key was found, or -1 if it was not found
public static int linearSearch(int key) {
// Have to start somewhere, might as well be the middle..
// ..but it does NOT make the time complexity any better
// ..and it is still NOT a Binary Search.
return linearSearch(key, array, array.size() / 2, 0);
}
1 Alternatively, since it is a Linear Search it could be rewritten without the extra left/right movement and have the same complexity bounds. (It is also trivial to modify this simpler code to a recursive Binary Search.)
public static int linearSearch(int key, List list, int index) {
if (index >= list.size() {
// Base case: end of list
return -1;
}
int x = (int)list.get(index);
if (key < x) {
// Recursive case: not there yet, keep looking
return linearSearch(key, list, index + 1);
} else if (key == x) {
// Base case: found key, return index
return index;
} else { // -> key > x
// Base case: read past where the key would be found
return -1;
}
}
Here's binary search for ArrayList<Integer> :)
public int binarySearch(List<Integer> list, int find) {
int mid = list.size() / 2;
int val = list.get(mid);
if (val == find) {
return val;
} else if (list.size() == 1) {
return -1;
}
return val > find ?
binarySearch(list.subList(0, mid), find) :
binarySearch(list.subList(mid, list.size()), find);
}
I'm trying to create a method in Java to count Nodes in a Binary Search Tree that contain a certain value and print out their contents. Each Node contains an Article object which has a title, and I want to find and print Articles in the tree containing a keyword in the title. However, I don't want the program to print out more than 10 of these (a 1-letter keyword could cause the program to stall or crash, for example). The code is here:
public int traverse(String key) {
if (root == null) {
System.out.println("Empty Tree!");
return 0;
} else {
int n = traverseHelper(root, key, 0);
return n;
}
}
public int traverseHelper(Node t, String key, int n) {
if (t == null) {
return n;
} else {
if (t.data.getTitle().indexOf(key) >= 0 && n <= 10) {
System.out.println(t.data);
n++;
}
return traverseHelper(t.left, key, n) + traverseHelper(t.right, key, n);
}
}
I'm trying to keep a running count of how many times the program has printed the data, but I'm not entirely sure how. Currently the program prints all occurrences, or very close to it. I know something is wrong with my recursive approach (I'm never any good at recursion anyway), so a good explanation of what I'm doing wrong would be greatly appreciated. This is homework, though, so I don't expect an explicit solution.
A couple other things: the traverse function's purpose is to print out the Articles, so I will most likely change it to a void method later. It currently should return the final count of articles printed. Also, the tree is set up like any other BST, but I'll give any clarification of my code if necessary.
Thanks!
Since you count with n you can only pass n to one of the leafs or you can nest them like this:
public int traverseHelper(Node t, String key, int n) {
if (t == null) {
return n;
} else {
if (t.data.getTitle().indexOf(key) >= 0 && n <= 10) {
System.out.println(t.data);
n++;
}
return traverseHelper(t.left, key, traverseHelper(t.right, key, n));
}
}
Nesting like this reduces stack usage slightly since you don't have the extra adding and the left becomes a tail call. Java don't have tail call optimization but it doesn't hurt to write as if it had.
The issue I see is with the n variable.
You do
return traverseHelper(t.left, key, n) + traverseHelper(t.right, key, n);
So if n was 5 to begin with, your method would return 10 (5 from each branch) even if no items were found.
Make the function return only the number of items found in the subtree.
I have a n-ary tree which contains key values (integers) in each node. I would like to calculate the minimum depth of the tree. Here is what I have come up with so far:
int min = 0;
private int getMinDepth(Node node, int counter, int temp){
if(node == null){
//if it is the first branch record min
//otherwise compare min to this value
//and record the minimum value
if(counter == 0){
temp = min;
}else{
temp = Math.min(temp, min);
min = 0;
}
counter++;//counter should increment by 1 when at end of branch
return temp;
}
min++;
getMinDepth(node.q1, counter, min);
getMinDepth(node.q2, counter, min);
getMinDepth(node.q3, counter, min);
getMinDepth(node.q4, counter, min);
return temp;
}
The code is called like so:
int minDepth = getMinDepth(root, 0, 0);
The idea is that if the tree is traversing down the first branch (branch number is tracked by counter), then we set the temp holder to store this branch depth. From then on, compare the next branch length and if it smaller, then make temp = that length. For some reason counter is not incrementing at all and always staying at zero. Anyone know what I am doing wrong?
I think you're better off doing a breadth-first search. Your current implementation tries to be depth-first, which means it could end up exploring the whole tree if the branches happen to be in an awkward order.
To do a breadth-first search, you need a queue (a ArrayDeque is probably the right choice). You'll then need a little class that holds a node and a depth. The algorithm goes a little something like this:
Queue<NodeWithDepth> q = new ArrayDeque<NodeWithDepth>();
q.add(new NodeWithDepth(root, 1));
while (true) {
NodeWithDepth nwd = q.remove();
if (hasNoChildren(nwd.node())) return nwd.depth();
if (nwd.node().q1 != null) q.add(new NodeWithDepth(nwd.node().q1, nwd.depth() + 1));
if (nwd.node().q2 != null) q.add(new NodeWithDepth(nwd.node().q2, nwd.depth() + 1));
if (nwd.node().q3 != null) q.add(new NodeWithDepth(nwd.node().q3, nwd.depth() + 1));
if (nwd.node().q4 != null) q.add(new NodeWithDepth(nwd.node().q4, nwd.depth() + 1));
}
This looks like it uses more memory than a depth-first search, but when you consider that stack frames consume memory, and that this will explore less of the tree than a depth-first search, you'll see that's not the case. Probably.
Anyway, see how you get on with it.
You are passing the counter variable by value, not by reference. Thus, any changes made to it are local to the current stack frame and are lost as soon as the function returns and that frame is popped of the stack. Java doesn't support passing primitives (or anything really) by reference, so you'd either have to pass it as a single element array or wrap it in an object to get the behavior you're looking for.
Here's a simpler (untested) version that avoids the need to pass a variable by reference:
private int getMinDepth(QuadTreeNode node){
if(node == null)
return 0;
return 1 + Math.min(
Math.min(getMinDepth(node.q1), getMinDepth(node.q2)),
Math.min(getMinDepth(node.q3), getMinDepth(node.q4)));
}
Both your version and the one above are inefficient because they search the entire tree, when really you only need to search down to the shallowest depth. To do it efficiently, use a queue to do a breadth-first search like Tom recommended. Note however, that the trade-off required to get this extra speed is the extra memory used by the queue.
Edit:
I decided to go ahead and write a breadth first search version that doesn't assume you have a class that keeps track of the nodes' depths (like Tom's NodeWithDepth). Once again, I haven't tested it or even compiled it... But I think it should be enough to get you going even if it doesn't work right out of the box. This version should perform faster on large, complex trees, but also uses more memory to store the queue.
private int getMinDepth(QuadTreeNode node){
// Handle the empty tree case
if(node == null)
return 0;
// Perform a breadth first search for the shallowest null child
// while keeping track of how deep into the tree we are.
LinkedList<QuadTreeNode> queue = new LinkedList<QuadTreeNode>();
queue.addLast(node);
int currentCountTilNextDepth = 1;
int nextCountTilNextDepth = 0;
int depth = 1;
while(!queue.isEmpty()){
// Check if we're transitioning to the next depth
if(currentCountTilNextDepth <= 0){
currentCountTilNextDepth = nextCountTilNextDepth;
nextCountTilNextDepth = 0;
depth++;
}
// If this node has a null child, we're done
QuadTreeNode node = queue.removeFirst();
if(node.q1 == null || node.q2 == null || node.q3 == null || node.q4 == null)
break;
// If it didn't have a null child, add all the children to the queue
queue.addLast(node.q1);
queue.addLast(node.q2);
queue.addLast(node.q3);
queue.addLast(node.q4);
// Housekeeping to keep track of when we need to increment our depth
nextCountTilNextDepth += 4;
currentCountTilNextDepth--;
}
// Return the depth of the shallowest node that had a null child
return depth;
}
Counter is always staying at zero because primitives in java are called by value. This means if you overwrite the value in a function call the caller won't see the change. Or if you're familiar with C++ notation it's foo(int x) instead of foo(int& x).
One solution would be to use an Integer object since objects are call-by-reference.
Since you're interested in the minimum depth a breadth first solution will work just fine, but you may get memory problems for large trees.
If you assume that the tree may become rather large an IDS solution would be the best. This way you'll get the time complexity of the breadth first variant with the space complexity of a depth first solution.
Here's a small example since IDS isn't as well known as its brethren (though much more useful for serious stuff!). I assume that every node has a list with children for simplicity (and since it's more general).
public static<T> int getMinDepth(Node<T> root) {
int depth = 0;
while (!getMinDepth(root, depth)) depth++;
return depth;
}
private static<T> boolean getMinDepth(Node<T> node, int depth) {
if (depth == 0)
return node.children.isEmpty();
for (Node<T> child : node.children)
if (getMinDepth(child, depth - 1)) return true;
return false;
}
For a short explanation see http://en.wikipedia.org/wiki/Iterative_deepening_depth-first_search