Return void messing up reference parameter value - java

I wrote this code with the intention of chain being incremented each time recurse() is called. It does this, however (from what I saw with the debugger) each time recurse() reaches a return;, it decrements the value of b. This is project euler #14 if you want background on what I'm trying to do.
http://projecteuler.net/problem=14
private static void euler14()
{
int currentstart=1000000;
int longest = 0;
int current=0;
Integer chain=0;
for(int i = currentstart; i>0; i--)
{
recurse(i,chain);
if(chain > current)
{
current=chain;
longest=i;
}
chain = 0;
}
System.out.print("Euler 14: " + longest + "\n");
}
private static void recurse(int a, Integer b)
{
b++;
if(a==1)
{
return;
}
else if(a%2==0)
{
recurse((a/2), b);
}
else if(a%2==1)
{
recurse(((a*3)+1), b);
}
return;
}

Although the reference to Integer is passed (by value) to recurse, the object itself is immutable. When you do b++, the incremented value is assigned to b which is local to recurse. As soon as you return, the value goes back to the unchanged copy of b in the caller.
You can make b a static int variable, and drop it from the parameter list of recurse to fix the problem:
private static int b = 0;
private static void recurse(int a) {
b++;
if(a==1) {
return;
}
if(a%2==0) {
recurse((a/2), b);
} else if(a%2==1) {
recurse(((a*3)+1), b);
}
}

In order to see updates to b in your main method your need to return them back, when you reach end of recursion:
private static int recurse(int a, int b) {
b++;
if(a==1) return b;
else if(a%2==0) return recurse((a/2), b);
else if(a%2==1) return recurse(((a*3)+1), b);
return b;
}
And in your main method you update your chain with new value:
chain = recurse(i,chain);

Since your method currently doesn't have a return value, you can use a return value for the number of steps. Simply add 1 to each recursive step:
private static int recurse(int a) {
if(a==1) {
return 1;
}
if(a%2==0) {
return 1 + recurse(a/2);
} else if(a%2==1) {
return 1 + recurse((a*3)+1);
}
}

Related

Referring to an instance that refers to an instance

I am not sure if the title to this question is correct.
I have this school assignment where we have to create two classes.
In one class, we define relationships between people e.g. A knows B, and in the other class we ask questions about that, e.g. does A know B?
The first class below defines relationships and gives methods, the second class inquires about them.
I am sure that my mistake lies somewhere in the public boolean 'knowsWithDegree'. Are you able to help?
public class SocialGraph {
private HashMap<String, List<String>> map = new HashMap<String, List<String>>();
public SocialGraph() { // empty constructor
map = new HashMap<String, List<String>>();
}
public void addIndividual(String a) {
if (!map.containsKey(a)) {
map.put(a, new ArrayList<String>());
} else {
}
}
public boolean hasKnowsArrow(String a, String b) {
if (map.containsKey(a)) {
return map.get(a).contains(b);
} else {
return false;
}
}
public void addKnowsArrow(String a, String b) {
if ((!map.containsKey(a) || !map.containsKey(b)) || (hasKnowsArrow(a, b))) {
} else {
map.get(a).add(b);
}
}
public void removeKnowsArrow(String a, String b) {
if ((!map.containsKey(a) || !map.containsKey(b)) || (!hasKnowsArrow(a, b))) {
} else {
map.get(a).remove(b);
}
}
public boolean knowsWithDegree(String a, String b, int x) {
Object[] keys = map.keySet().toArray();
int y;
y = 0;
if (map.get(a).contains(b)) {
y = 1;
} else {
if ((map.get(a).contains(map.get(keys[0]).contains(b))) || (map.get(a).contains(map.get(keys[1]).contains(b))) ||
(map.get(a).contains(map.get(keys[2]).contains(b))) || (map.get(a).contains(map.get(keys[3]).contains(b)))) {
y = 2;
}
}
if (x == y) {
return true;
} else
return false;
}
}
public class SocialGraphTest {
public static void main(String[] args) {
SocialGraph socialGraph = new SocialGraph();
socialGraph.addIndividual("Anne");
socialGraph.addIndividual("Daisy");
socialGraph.addIndividual("Bob");
socialGraph.addIndividual("Charlie");
socialGraph.addKnowsArrow("Anne", "Bob");
socialGraph.addKnowsArrow("Anne", "Daisy");
socialGraph.addKnowsArrow("Bob", "Daisy");
socialGraph.addKnowsArrow("Bob", "Charlie");
System.out.println(socialGraph.hasKnowsArrow("Anne", "Bob")); //should be true
System.out.println(socialGraph.hasKnowsArrow("Anne", "Daisy"));//should be true
System.out.println(socialGraph.hasKnowsArrow("Bob", "Daisy"));//should be true
System.out.println(socialGraph.hasKnowsArrow("Bob", "Charlie"));//should be true
System.out.println(socialGraph.hasKnowsArrow("Anne", "Charlie")); //should be false
System.out.println ();
System.out.println (socialGraph.knowsWithDegree ("Anne", "Daisy", 1));
System.out.println (socialGraph.knowsWithDegree ("Anne", "Charlie", 2));
System.out.println (socialGraph.knowsWithDegree ("Anne", "Daisy", 3));
}
}
}
Here is an example using recursion:
public boolean knowsWithDegree(String a, String b, int x) {
return knowsWithDegreeRecursive(a, b, x, new HashSet<>());
}
private boolean knowsWithDegreeRecursive(String a, String b, int x, Set<String> visited) {
if (x < 1) {
// x must be at least 1
return false;
}
if (map.get(a).contains(b)) {
// If a knows b, then the number of degrees should be 1
return x == 1;
}
if (x == 1) {
// Since the degree is 1 and a does not know b, then a does not know b to the specified degree
return false;
}
// Go through each person that a knows
for (String c : map.get(a)) {
if (visited.contains(c)) {
// We've already checked this person
continue;
}
// Mark c as visited so we don't check them again
visited.add(c);
// See if this person knows b, with one fewer degree
// e.g. if we're seeing if a knows b with a degree of 2, then c should know b with a degree of 1
boolean knowsWithDegree = knowsWithDegreeRecursive(c, b, x - 1, visited);
// If c knows b with the degree minus 1, then a knows b with the specified degree
if (knowsWithDegree) {
return true;
}
}
// a does not know b to the specified degree
return false;
}
If the order of the knowsArrows doesn't matter, I would recommend using HashSet in your map over ArrayList.

Why do I keep getting stack overflow errors? Why does my function return at the first value? when start does != the last value

This is the question:
Write a recursive method that removes all consecutively occurring letters from a string of fixed size. E.g. “AAAbbCCCC” becomes “AbC”
My Code:
public static String NoRepeats(String n, int start) {
String x = "";
if(start == n.length()-1) {
return x;
}
if(n.charAt(start) == n.charAt(start+1)) {
return NoRepeats(n, start+1);
}
else {
x += n.charAt(start);
return NoRepeats(n,start+=1);
}
}
ok, so I wasn't sure why it would only return an empty string, So I fiddled around with the syntax.
FYI String n = "AAAABBBBCCCCDDDD"
In my recursive steps I couldn't use 'start ++ or start +1", it only worked when it was 'start +=1'. This will correct it.
This is my new code:
public static String NoRepeats(String n, int start) {
String x = "";
if(start == (n.length()-1)) {
x += n.charAt(start);
return x;
}
if(n.charAt(start) == n.charAt(start+1)) {
return NoRepeats(n, start+=1);
}
else {
x += n.charAt(start);
return x +NoRepeats(n,start+=1);
}
}
I was wondering why did the above returned empty string so I went and modify your codes to see how it's done.
String a = "";
String b = "";
try {
a = Tesst1.NoRepeats("AAAbbCCCC", 0, b);
} catch(Exception e) {
e.printStackTrace();
}
System.out.println(a);
}
public static String NoRepeats(String n, int start, String b) {
if(start == n.length()-1) {
return b += n.charAt(start - 1);
}
if(n.charAt(start) == n.charAt(start+1)) {
return NoRepeats(n, start+1, b);
}
else {
b += n.charAt(start);
return NoRepeats(n,start+1, b);
}
}
This should now yield AbC.
In your code x is local to function. So, with every call you lose the value of x. Also, there was little mistake in first statement.
In classic way, you could use the result of function:
public static String noRepeats(String n, int start) {
return (start == n.length() - 1) ? "" + n.charAt(start) :
(n.charAt(start) == n.charAt(start + 1)) ? noRepeats(n, start + 1) :
n.charAt(start) + noRepeats(n, start + 1);
public static void main(String[] args) {
System.out.println(noRepeats("AAAbbCCCC", 0));
}
Or need some buffer to accumulate new characters:
public static String noRepeats(String n) {
return noRepeats(n, new StringBuilder(), 0);
}
public static String noRepeats(String n, StringBuilder result, int start) {
if(start == n.length() - 1) {
return result.append(n.charAt(start)).toString();
}
if(n.charAt(start) == n.charAt(start + 1)) {
return noRepeats(n, result, start + 1);
}
else {
result.append(n.charAt(start));
return noRepeats(n, result, start + 1);
}
}
public static void main(String[] args) {
System.out.println(noRepeats("AAAbbCCCC"));
}

Java script takes too much time to finish

I don't know how to make my code less time consuming. My task was to make brute force password break. I knew how long password is and which characters it contains. So far i have this method.
public boolean moznosti(char [] arr, String pr, int a, int b) {
if (b == 0) {
char [] heslo = pr.toCharArray();
if(tryOpen(heslo)) {
return false;
}
return true;
}
for (int i = 0; i < a; i++) {
String tmp = pr+arr[i];
if (moznosti(arr, tmp, a, b-1) == false) {
return false;
}
moznosti(arr, tmp, a, b-1);
}
return true;
}
}
where heslo is password. any ideas?
Have a look at your code structure.
You have a for loop which recursively calls your moznosti method, and each time it's called it doing the same thing.
I don't know what your variables mean but assuming a and b are 4. Your first cycle will call your moznosti method 4 times with the same b parameter.
Not that this is causing the time issue but where you have:
if (moznosti(arr, tmp, a, b-1) == false)
Because the moznosti method returns a Boolean value, you don't need to check if it's equal to false or true, the if statement brackets only pass when the condition is true. So in your case this might be more applicable:
if (!moznosti(arr, tmp, a, b-1))
I think the part which is taking most of the time is where you are checking your base case
if (moznosti(arr, tmp, a, b-1) == false)
Okay i did it!
public class BruteForceAttacker extends Thief {
private boolean konec;
#Override
public void breakPassword(int sizeOfPassword) {
moznosti(getCharacters(), "", getCharacters().length, sizeOfPassword);
}
public void moznosti(char [] arr, String pr, int a, int b) {
if (konec != true) {
if (b == 0) {
char [] heslo = pr.toCharArray();
if (tryOpen(heslo)) {
konec = true;
}
return;
}
for (int i = 0; i < a; i++) {
String tmp = pr+arr[i];
moznosti(arr, tmp, a, b-1);
}
}
}
}

How to correctly place a return statement in a recursive method with if\else conditions

I'm writing recursive code that is build with if\else controlling the return statements. However when I compile, I get a 'missing return statement' because all of my returns are in the conditions. I'm adding 'fake' returns(to which the method should never reach) but I was wondering if there is a smarter solution.
for example:
private static boolean compare(int[][] a, int i) {
if (i == a.length - 1) {
return true;
}
else {
if (calcLineSum(a[i], 0, 0) == calcLineSum(a[i + 1], 0, 0)){
compare(a, i + 1);
}
else {
return false;
}
}
return false; //<= = 'fake'
}
private static int calcLineSum(int[] a, int i, int sum) {
if (i == a.length)
return sum;
else {
sum = sum + a[i];
calcLineSum(a, i + 1, sum);
}
return sum; //<= = 'fake'
}
thank you very much for your input!
I think if you replace compare(a,i+1); with return compare(a,i+1); and calcLineSum(a,i+1,sum); with return calcLineSum(a,i+1,sum); it should compile.
Every if and else if should be terminated with a return.
First off; indent your code properly and add braces to all of your conditions. It will seriously save you hours of debugging.
When its properly formatted its easy to spot the error:
private static boolean compare (int[][]a, int i)
{
if(i==a.length-1)
{
return true;
}
else
{
if(calcLineSum(a[i],0,0)==calcLineSum(a[i+1],0,0))
{
compare(a,i+1);
}
else
{
return false;
}
}
return false; <=='fake' return
}
You can clearly see the statement compare(a,i+1); is missing the return. Happy debugging!
It looks like you misunderstand return. In your code
private static int calcLineSum (int[]a, int i, int sum)
{
if(i==a.length)
return sum; // only returns `sum` from this one invocation,
// *not* further up the recursive chain
else {
sum=sum+a[i];
calcLineSum(a,i+1,sum);
// your code is **still going** here; the `return` from
// the recursive call didn't change anything
// also note that `sum` hasn't actually changed here
// sum is passed by value, and changes to it inside the recursive call
// don't actually make any difference out here
}
return sum; // actually used
}
It looks like the correct implementation would be
private static int calcLineSum(int[] a, int i, int sum) {
if (i == a.length) {
return sum;
} else {
return calcLineSum(a, i+1, sum + a[i]);
}
}
Try this approach:
private static boolean compare (int[][]a, int i) {
boolean result = false;
if (i == a.length-1) {
result = true;
} else {
if(calcLineSum(a[i],0,0) == calcLineSum(a[i+1],0,0)) {
result = compare(a,i+1);
}
}
return result;
}
private static int calcLineSum (int[]a, int i, int sum) {
int result = sum;
if (i != a.length) {
result = calcLineSum(a,i+1,sum+a[i]);
}
return result;
}
The issue here is that a method with a non-void return type must be guaranteed to return a value of that type.
Ignoring the specific code, the structure of your compare method is basically:
if() {
return
} else {
if () {
// you don't return anything here,
// so the method might not do what you promised it would,
// namely return a value
} else {
return
}
}
If there is any way the method can run that won't return a value, the compiler will call you out on it.
Your recursion:
private static int calcLineSum (int[]a, int i, int sum)
{
if(i==a.length)
return sum;
else {
sum=sum+a[i];
calcLineSum(a,i+1,sum);
}
return sum; //<=='fake' return
}
You can do it pretty well like this:
private static int calcLineSum (int[]a, int i, int sum)
{
if(i==a.length)
return sum;
sum=sum+a[i];
calcLineSum(a,i+1,sum);
}
All I did was remove the else. If the first condition isn't met, with or withou the else, you will execute these two lines:
sum=sum+a[i];
calcLineSum(a,i+1,sum);
It simplifies your code too.
In addition, you can remove the line
sum=sum+a[i];
writing like this:
private static int calcLineSum (int[]a, int i, int sum)
{
if(i==a.length)
return sum;
calcLineSum(a,i+1,sum+a[i]);
}
with out your last return statement (the ones you call fake); there are indeed condition that do not return anything;
For example in your first method if the following condition is satisfied nothing will be returned :
if (calcLineSum(a[i], 0, 0) == calcLineSum(a[i + 1], 0, 0))
similarly for your second method your else block do not return anything.
as a good coding practice please use { } arround if and else block.

Recursive method not giving the correct value

I want to use a recursive method but am having trouble making it work correctly.
In this program for example, why when I display my b, the value is 0 and not 10?
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
recursivMethod(a+1);
return a;
}
The issue is, while you are calling the method recursively, you're not returning that value. That is, you call recursivMethod correctly, but then immediately return the initial value of a. Try this instead:
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1); //here, you return the result of your recursive call
return a; //instead of just immediately returning a, which should only be done only after a == 10
}
Two points:
When your method calls itself recursively, it's ignoring the returned value:
if(a != 10)
recursivMethod(a+1); // <--- did you mean to do something with the result?
Since recursivMethod() doesn't change a, and returns a at the end, then calling recursivMethod(0) will return 0. This is exactly what happens when you run your code.
This is because you are ignoring the return value of your recursive invocation:
static int recursivMethod(int a) {
if(a != 10)
return recursivMethod(a+1);
return a;
}
try
return recursiveMethod(a+1);
instead
You did never assign a new value to the method local variable a.
Try:
public static void main(String[] args) {
int a = 0;
int b = recursivMethod(a);
System.out.println(b);
}
static int recursivMethod(int a)
{
if(a != 10)
a = recursivMethod(a+1);
return a;
}
You are discarding the result of your recursive call.
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1); // Note the return
return a;
}
static int recursivMethod(int a)
{
if(a != 10)
return recursivMethod(a+1);
}
missing return:
return recursivMethod(a+1);

Categories

Resources