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.
Related
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;
}
I'm having difficulty figuring out how I can return the index of an item in an array via the recursive binarySearch function I have below:
public static <AnyType extends Comparable<AnyType>> int binarySearch
(AnyType[] a, AnyType x)
{
int nMin = 0;
int nMax = a.length - 1;
int nMid = (nMin + nMax) / 2;
int compare = a[nMid].compareTo(x);
if(compare == 0)
return 1;
else if(compare == 1)
return binarySearch(Arrays.copyOfRange(a, 0, a.length/2), x);
else
return binarySearch(Arrays.copyOfRange(a, a.length/2, nMax), x);
}
The requirement is to write a BS function with the function header and not to modify it. My function works fine, however, as I modify the array through each level of recursion, I lose the original index. We are also required to return the index of the item we're searching for. My implementation will always return 1.
Is it even possible to do this without creating another method and calling it from within the binarySearch function?
So after much confusion from pretty much the entire 300 student class, the teacher addressed this during lecture and explained that we could, in fact, create another function to handle anything we needed (position in this case).
So what I did was just write a normal recursive binary search implementation and call that from the function the professor required to have included.
public static <AnyType extends Comparable<AnyType>> int binarySearch
(AnyType[] a, AnyType x)
{
return binarySearch(a, x, 0, a.length);
}
public static <AnyType extends Comparable<AnyType>> int binarySearch
(AnyType[] a, AnyType x, int nMin, int nMax)
{
if(nMin < nMax)
{
int nMid = nMin + (nMax - nMin) / 2;
if(x.comapreTo(a[nMid]) == -1)
return binarySearch(a, x, nMin, nMid);
else if(x.compareTo(a[nMid]) == 1)
return binarySearch(a, x, nMid+1, nMin);
else
return nMid;
}
rteurn -(nMin + 1);
}
Also, as a side note, I think my original question was poorly worded. I wasn't looking for a solution to the problem, I was more or less looking for confirmation in my thinking that the problem was impossible.
Recursive search by copying the array on each recursion is bad for performance.
Pass the entire array on recursion, with additional range values, i.e. start/end indexes to process.
This is faster, and will also allow you to immediately know the actual index of the found element, since index values are unchanged.
Update
If the method signature cannot be changed, then a few changes are needed:
int compare = a[nMid].compareTo(x);
if(compare == 0)
return 1;
If the element at index nMid is equal, that is the index to return, not 1.
else if(compare == 1)
return binarySearch(Arrays.copyOfRange(a, 0, a.length/2), x);
compareTo() returns a "positive integer", not necessarily 1, so test should be compare > 0.
Also, there is no need for the else part, since the if has unconditional return.
else
return binarySearch(Arrays.copyOfRange(a, a.length/2, nMax), x);
First, the last argument of copyOfRange() is exclusive, so it needs to be a.length, not nMax.
Since the recursive call is passing in a range not starting at 0, any index value returned must be offset, i.e. return binarySearch(...) + a.length/2.
Again, no need for else.
In addition to all the above, if the value doesn't exist, the code will eventually fail because copyOfRange() will create an empty array, and code doesn't handle that, causing a[nMid] with a value of 0 to throw an IndexOutOfBoundsException. Need to add code to handle that.
I have a Stack variable (java collection) which holds five integers and I was also given one int variable. Is it possible to sort the numbers in the given stack. I am not able to solve that. Please post here if you have ideas.
Stack<Integer> s = new Stack<Integer>();
s.push(5);s.push(3);s.push(4);s.push(1);s.push(1);
int a;
We should not create any new variable except the one given in the above code snippet and also should not use Collections.sort(s).
Terribly inefficient, but respects the rules :)
Stack<Integer> s=new Stack<Integer>();
s.push(5);s.push(3);s.push(4);s.push(1);s.push(1);
int a = -1;
while (a == -1) { // Here 'a' is used as a kind of boolean that tells us whether we need to keep checking for items to reorder or not.
for (a = 0; a < s.size() - 1; a++) { // Now 'a' becomes stack element's index.
if (s.get(a) > s.get(a + 1)) {
a = s.remove(a); // Here 'a' again changes meaning and holds the value that needs to be reordered.
s.push(a);
a = -1; // And here, 'a' is back to being used as a kind of boolean flag to control the outer loop.
break;
}
}
}
EDIT:
Basically, I take advantage of the fact that I know that Stack extends Vector. So I don't actually have to use only the standard Pop and Push methods to access/remove elements. I can use normal List methods.
And then, I just squeeze the most use I can from a by using it for different purposes at different times (exit flag, loop index, temp storage for value to reorder). Normally a very bad programming practice.
So the algorithm is basically that I loop through the Stack elements. Any time I find an element that is greater than the next, then I remove it, and then place it at the end of the Stack. At that moment, I stop the loop, and reset a to -1 to make sure I start the loop again. I keep doing this until I am able to loop through all the stack items without needing to reorder anything.
EDIT 2:
Here is another alternative that is a bit more complicated to read, but still respects the rules, and performs better following the bubble sort pattern. The principles used are pretty much the same as my first attempt (abusing the Stack as a List + using variable a for multiple uses).
Stack<Integer> s=new Stack<Integer>();
s.push(5);s.push(3);s.push(4);s.push(1);s.push(1);
int a = -1;
while (a < 0) { // keep looping if the previous loop performed at least one swap.
a = 0;
// if 'a' is >= 0, then it simply holds the index.
// if 'a' < 0, then the index can be obtained by applying the bitwise complement operator.
while ((a < 0 ? ~a : a) < (s.size() - 1)) { // loop all items except the last one.
if (s.get(a < 0 ? ~a : a) > s.get((a < 0 ? ~a : a) + 1)) { // if this item is greater than the next, a swap is needed.
s.insertElementAt(s.remove(a < 0 ? ~a : a), (a < 0 ? ~a : a) + 1); // swap this value with the next.
// If this was not done already, flag the fact that a swap was performed by
// applying the bitwise complement operator to 'a'.
// This serves as a flag to let the outer loop know
// that we'll need to perform the stack loop again.
if (a >= 0) {
a = ~a;
}
}
// increment index. Or if the bitwise complement operator was applied,
// then go the opposite way since the value is now negative.
if (a >= 0) {
a++;
} else {
a--;
}
}
}
EDIT 3: Revised my last algorithm to use the bitwise complement operator rather than Math.abs().
Also, I would like to point out that, unlike some other clever attempts, this algorithm doesn't really have any limitations. It won't potentially suffer from a StackOverflowException because of too many recursive calls, because no recursion is used. Memory used is stable. And you can have any int value in the Stack, even negative ones, and it will work fine.
It's possible to do, but you're going to be cheating a little bit - you're going to use a second stack to do it.
I don't mean that you're explicitly declaring another stack; you're going to be recursing through this method.
Bear in mind that this approach has some limitations; it can handle sequential data just fine (that is, it can reverse a stack just fine), but dealing with more jumbled data is a lot trickier as we can only see up to two elements in the future (peek and holder).
This also inverts the approach and doesn't order them in a way you'd prescribe (1 to 5), but figuring out the correct condition from the code should be a trivial matter.
The approach is:
Handle null and empty stacks by returning what was given to us
Handle a stack of size 1 by returning what was given to us
In the process, we pop the stack and store that in the holder variable.
If what's in the stack next is less than the holder variable, we act:
Pop the stack again, multiply it by 10, and add this to the holder. We do the multiplication here so that we can (roughly) store two ints at once.
Push the remainder value (holder % 10) into the stack.
Recurse, repeating the instructions.
Once recursion has exhausted, we push the value we multiplied by 10 back onto the array by dividing the holder by 10.
Otherwise, we put back what we had found and return the stack.
public Stack<Integer> sortStack(Stack<Integer> stack) {
// no-op on empty stacks
if(null == stack || stack.empty()) {
return stack;
}
// pop stack and place in holder
while(true) {
int holder = stack.pop();
// no-op on stacks of size 1
try {
stack.peek();
} catch(EmptyStackException e) {
// Stack only had one element; put it back and return the stack
stack.push(holder);
return stack;
}
if(stack.peek() < holder) {
holder += stack.pop() * 10;
stack.push(holder % 10);
stack = sortStack(stack);
stack.push(holder / 10);
} else {
//put it back
stack.push(holder);
break;
}
}
return stack;
}
Since Stack implements List and Integer implements Comparable just:
Collections.sort(s);
You can use bubble sort to do it, as the following:
Stack<Integer> s = new Stack();
s.push(5);
s.push(3);
s.push(4);
s.push(1);
s.push(1);
int a = 0;
while (a != s.size() - 1) {
if (a != s.size() - 1) {
if (s.elementAt(a) >= s.elementAt(a + 1)) {
a++;
} else {
s.push(s.remove(a));
a = 0;
}
}
}
System.out.println(s.toString());
Here i found the perfect answer from geeksforgeeks which uses recursion.
http://www.geeksforgeeks.org/sort-a-stack-using-recursion/
Just posting the same algorithm here.
Algorithm:
We can use below algorithm to sort stack elements:
sortStack(stack S)
if stack is not empty:
temp = pop(S);
sortStack(S);
sortedInsert(S, temp);
Below algorithm is to insert element is sorted order:
sortedInsert(Stack S, element)
if stack is empty OR element > top element
push(S, elem)
else
temp = pop(S)
sortedInsert(S, element)
push(S, temp)
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 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