Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I get a horrific stackoverflowerror, and figured it was my deep recursion causing it (well, the debugger helped with that...). Can anyone guide me in turning my recursion into a loop?
H<V>.Pair currPair = (H<V>.Pair) arr[startPos];
if (arr[startPos] == null) {
return null;
}
if (currPair.key.equals(key)) {
return currPair.value;
} else {
return find(gNL(startPos, ++stepNum, key), key, stepNum);
}
}
More specifically, return find(getNextLocation(startPos, ++stepNum, key), key, stepNum); causes the recursion.
This seems to be equivalent:
private V find(int startPos, String key, int stepNum) {
Hashtable<V>.Pair p;
boolean finished = false;
do {
p = (Hashtable<V>.Pair) arr[startPos];
if (p == null || p.key.equals(key)) {
finished = true;
} else {
startPos = getNextLocation(startPos, ++stepNum, key);
}
} while( ! finished);
return p == null ? null : p.value;
}
I believe this gets you there:
private V find(int startPos, String key, int stepNum) {
Hashtable<V>.Pair currPair = arr[startPos];
while ((currPair != null) && !currPair.key.equals(key)) {
stepNum++;
int nextPos = getNextLocation(startPos, stepNum, key);
currPair = arr[nextPos];
}
return (currPair == null)
? null
: currPair.value;
}
The "trick" is to put the conditions you used to end recursion into the loop condition. Note that because your algorithm doesn't use the intermediate results in any way as some other recursive algorithms do, the translation is quite straightforward. This will not work every time with all recursive algorithms, sometimes you'll need to add a data structure to hold your intermediate results.
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
I was practicing linked-list problem: search element using recursion in Java and was just curious to know which approach is better?
A:
protected boolean searchElement(Node current, int element){
boolean res = false;
if(current != null){
if(current.getData() == elem) res = true;
else function(current.getNext(),elem);
}
else res = false;
return res;
}
B:
protected boolean searchElement(Node current, int elem){
if(current != null){
if(current.getData() == elem) return true;
else search(current.getNext(), elem);
}
return false;
}
Unless there's specific Java-hackish bytecode injection optimization reasons for using end-recursion/tail-call strategy in recursive functions, I would even go for this (fail-fast-fail-early):
protected boolean function(arguments){
if(!condition_1) return false;
if(condition_2) return true;
return function(arguments);
}
BTW you may have an error in your pseudo code:
In both A and B, the handling of
else function(arguments);
looks inconsequential. It will run the function, but both implementations will return false, no matter what function() does (unless it throws an uncaught exception/throwable). This indicates either
a mistake in programming,
or some side-effects (changing exterior state variables such as static or member variables), which recursive functions rather should NOT do
If this is only a mistake in programming/design, I suggest you always translate pseudocode into real code. This way the compiler will usually tell you such things, make them more evident. Amp up your clean code / code smell warning settings.
Oh, and another note to consider: you can always replace recursive functions with a loop and some variables/lists, which usually drastically increases speed (no creation and release of stack frames when running) but often reduces readability (multiple variables to mess up, instead of cleanly assigned parameters).
For your example, as the impact of the call to function() is unclear, I cannot present you a meaningful example here.
I prefer handling the special cases first, then the recursion (as far as feasible).
This in a code style with several returns - which many do not find good style.
But it prevents nested conditions and else.
protected boolean searchElement(Node current, int element) {
if (current == null) {
return false;
}
if (current.getData() == elem) {
return true;
}
return search(current.getNext(), elem);
}
Case: terminating condition on null node.
Case: found.
Recursion, here last, so called tail recursion.
Tail recursion can be easily transformed to iteration.
protected boolean searchElement(Node current, int element) {
while (current != null) {
if (current.getData() == elem) {
return true;
}
current = current.getNext();
}
return false;
}
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 5 years ago.
Improve this question
Below is the code I have written to build a key using two strings. If either of them is null, empty or blank use the other string to build the key. However if both of them does not qualify, return an empty string. I would like to write a better and efficient piece of code. Here is my sample code
if (!StringAssistant.isBlank(string1) && !StringAssistant.isBlank(string2)) {
return StringAssistant.append(string1, string2);
}
if (StringAssistant.isBlank(string1) && !StringAssistant.isBlank(string2)) {
return string2;
}
if (!StringAssistant.isBlank(string1) && StringAssistant.isBlank(string2)) {
return string1;
}
return "";
You may do something as "simple" as :
return StringAssistant.append(StringAssistant.isBlank(string1)?"":string1,StringAssistant.isBlank(string2)?"":string2);
Simply append the two string and return the value
return string1+string2;
or if you want to use your StringAssistant.append
return return StringAssistant.append(string1, string2);
Notice that the empty string doesn't has an impact on the return value. So if you append the string and return it will result the same.
If the string can be null then you need to handle the null value separately. if either string is null then you can return an empty string. You can handle it in your append method.
You can refactor the code as shown below, I suggest you evaluate the isBlank for the both the strings first (so that for large strings you would get the results quicker):
boolean string1Blank = !StringAssistant.isBlank(string1);
boolean string2Blank = !StringAssistant.isBlank(string2);
if(string1Blank && string2Blank) {
return StringAssistant.append(string1, string2);
} else if(string1Blank) {
return string2;
} else if(string2Blank) {
return string1;
} else {
return "";
}
below the code is using a private method to add to the variable count. Below that variable are conditionals which by my understanding, will not run until the recursion stack traces upword. Am I correct? My test is failing, and I am trying to see if it is because my code is wrong or I'm using recursion wrong.
public boolean containsRightRedEdge() {
int count = 0;
count += containsRightRedEdge(root);
if(count > 0) return true;
return false;
}
private int containsRightRedEdge(Node n) {
if (n == null) return 0;
if (isRed(n.right)) {
return 1;
}
return containsRightRedEdge(n.left) + 0 + containsRightRedEdge(n.right);
}
I would say you are using recursion pretty much correctly, but your choice of method names could be less confusing, and your logic could be simplified.
I am not too familiar with the algorithm you're trying to implement, but you might try something like this:
public boolean containsRightRedEdge(Node root) {
return getNumRightRedEdges(root) > 0;
}
private int getNumRightRedEdges(Node n) {
if (n == null) return 0;
if (isRedEdge(n)) return 1;
return getNumRightRedEdges(n.left) + getNumRightRedEdges(n.right);
}
Generally a recursive method shouldn't have the same name as a non-recursive method. These method names communicate more clearly what each one does. Also your base cases might be wrong as you've got them written currently based on how I'm interpreting the algo should work. Of course, I don't know the code inside isRed() so I'm probably making wrong assumptions here.
The code above in my question, is the correct way to use recursion in this instance. I just had a typo which is now resolved. Leaving the question for other peoples reference.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 8 years ago.
Improve this question
I have an Object Collection with 5 fields:
id;
entityType;
entityId;
brandId;
productId;
To sort an ArrayList of Collection I have written the following Comparaor.
Comparator<Collection> collectionComparator = new Comparator<Collection>() {
#Override
public int compare(Collection collection1, Collection collection2) {
if(collection1.getId().equals(collection2.getId())) {
if(collection1.getEntityType().equals(collection2.getEntityType())) {
if(collection1.getEntityId().equals(collection2.getEntityId())) {
if(collection1.getBrandId().equals(collection2.getBrandId())) {
return collection1.getProductId().compareTo(collection2.getProductId());
} else {
return collection1.getBrandId().compareTo(collection2.getBrandId());
}
} else {
return collection1.getEntityId().compareTo(collection2.getEntityId());
}
} else {
return collection1.getEntityType().compareTo(collection2.getEntityType());
}
}
return collection1.getId().compareTo(collection2.getId());
}
};
Is this the right way to implement Comparator on the object which has multiple fields to compare?
Your method might be correct, but it is inefficient (unnecessarily calls equals) and difficult to read. It could be rewritten something like this:
public int compare(Collection c1, Collection c2)
{
int n;
n = c1.id.compareTo(c2.id);
if (n != 0) return n;
n = c1.entityType.compareTo(c2.entityType);
if (n != 0) return n;
n = c1.brandId.compareTo(c2.brandId);
if (n != 0) return n;
return c1.productId.compareTo(c2.productId);
}
Even better is to use a library method which abstracts all this logic away so you don't have to think about it. E.g. using apache.commons.lang CompareToBuilder
public int compare(Collection c1, Collection c2)
{
return new CompareToBuilder()
.append(c1.id, c2.id)
.append(c1.entityType, c2.entityType)
.append(c1.brandId, c2.brandId)
.append(c1.productId, c2.productId)
.toComparison();
}
First, Collection is a class from java.util package, so it's probably not the best idea to name your own class Collection too, although it is certainly possible.
Second, JDK8 have some neat ways to create comparators, check here: jdk8 comparators
Esspecially section 6 and 9.
EDIT: Without JKD8:
When comparing by 5 different attributes, I wouldn't hardcode the comparasion like that, you can always create your own comparator chainer (something like point 9 from previous link) and chain 5 separate comparators together.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Intersection of 2 binary trees throws Stack Overflow error
Java Binary Search Trees
I need to return a new OrderedSet that contains the overlapping elements of the two binary trees. I think it is the private OrderedSet that is throwing the error, at least that is what eclipse is telling me.
private OrderedSet<E> resultIntersect = new OrderedSet<E>();
public OrderedSet<E> intersection(OrderedSet<E> other) {
OrderedSet<E> result = new OrderedSet<E>();
result = resultIntersect;
return result;
}
private void intersection(OrderedSet<E> other, TreeNode t) {
if (other.contains(t.data)) {
resultIntersect.insert(t.data);
}
if(t.left != null)
intersection(other, t.left);
if(t.right != null)
intersection(other, t.right);
}
**EDIT
I can't seem to get it to return correctly. How can I get the private method to return the result correctly?
public OrderedSet<E> intersection(OrderedSet<E> other) {
OrderedSet<E> result = new OrderedSet<E>();
result = intersection(other, root, result);
return result;
}
private OrderedSet<E> intersection(OrderedSet<E> other, TreeNode t, OrderedSet<E> result) {
if (other.contains(t.data)) {
result.insert(t.data);
}
if (t.left != null && t.right != null)
return intersection(other, t.left, result) + intersection(other, t.right, result);
if (t.left != null)
intersection(other, t.left, result);
if (t.right != null)
return intersection(other, t.right, result);
else
return result;
}
I answered in your other question, but for completeness, here it is again.
Although you don't mention it, and your posted code did not include it, I'm guessing OrderedSet<E> resultIntersection is a field in OrderedSet<E>. In which case when you create a new instance of OrderedSet<E> it creates another instance of an OrderedSet<E> to assign to resultIntersection. That then has it's own resultIntersection that needs an instance of OrderedSet<E> creating, and so on...
The fix would be to remove resultIntersection and find some other way of implementing intersection. It's generally bad practice to have methods passing data around by manipulating shared state when it's not necessary, as it makes the logic more difficult to follow and can lead to multi-threading issues.