I am doing a book exercise regarding the Ackermann function.
I have one question though. If I declare result but do not initialise it, the compiler complains that "variable result might not have been initialised".
int result;
When I set it to default to 0, it does not complain.
int result = 0;
I thought that when one declares a variable with type int it defaults to 0 automatically.
Here's the complete code:
public class Ackermann {
public static int ack(int m, int n) {
int result = 0;
//int result;
if (m == 0)
result = n + 1;
else if(m > 0 && n == 0)
result = ack(m-1, 1);
else if(m > 0 && n > 0)
result = ack(m-1, ack(m, n-1));
return result;
}
public static void main(String[] args) {
System.out.println(ack(3, 3));
}
}
Local variables are not initialized with default values. See the language specs for the ground truth.
it is very bad practice to not initialize variables. There is popular joke that fits to your case: John got 3 apples from his mother and 5 from his father. How many apples has John? If you are not good programmer, your answer will be 8. If you are good programmer, you will answer that we do not know how many apples had had john before obtaining apples from his Mother. Remember: always initialize variables and do not assume that they will be 0.
Fields in classes default to values (null, 0, false, etc.) Local variables however don't, you have to define them explicitly. A lot of people even disagree with not setting fields explicitly, because setting it shows the reader that you've actually thought about setting it to a value rather than just forgotten to set it, therefore potentially causing a bug somewhere down the line.
Related
I am very new to Java (doing a beginners university module) so sorry for the probably silly question. I am trying to verify whether a ragged array is a 'tridiagonal matrix'.
It is valid if it is of length 3 at the first level and of length n − 1, n, and n − 1 at the second level. I intended to come up with a code to firstly verify the length is 3, then find the longest length array within it for n, then finally verify each length.
For whatever reason my code won't compile but I'm not seeing an error message, just a red exclamation mark on the class. I assume this means there are multiple errors. If anyone could point them out it would be a massive help.
static boolean isValidTridiagonal ( double [][] m)
{
if (double [][]=new double [3][])
{
int n = 0;
for(int i = 0; i < m.length; i++)
{
if(m[i].length > n)
{
n = m[i].length;
if( (m[0].length = n-1) && (m[1].length = n) &&(m[2].length=n-1))
{
return true
}
else
{
return false
}
}
else
{
return false
}
}
Thanks very much!
I agree with Foolish in the comments that it's helpful to use an IDE that can highlight syntax errors and other problems with the code, it really makes a huge difference. Apart from that, another general strategy is to always code in "baby steps": do only the minimal thing to test if the code works, compile and test often. And if you still have troubles, you can always comment out chunks of your code when searching for the offending bits.
Having said that, the errors that I see in your code are:
if (double [][]=new double[3][])
If you want to test the length of the input, you can do if (m.length == 3)
In
if( (m[0].length = n-1) && (m[1].length = n) &&(m[2].length=n-1))
you're not testing for equality, but rather trying to put the values n-1 etc into m[0].length, which is not going to work. What you probably meant was
if( (m[0].length == n-1) && (m[1].length == n) &&(m[2].length==n-1))
In
return true
you're missing a semicolon. The compiler is whiny about things like that and unless you use an IDE or learn to interpret the compiler error messages, it can be really painful to find such errors.
Finally, of course, the answer by vasste provides a much simpler solution to your actual task, so it's worth looking into that :).
Why do you need all that loops? If all arrays cannot be null, than
static boolean isValidTridiagonal(double[][] m) {
return m.length == 3 && m[0].length == m[1].length - 1 && m[2].length == m[0].length;
}
You're missing a few braces at the end but, judging from your indentation, you just forgot to copy them.
You're missing semicolons from the end of the return lines.
The condition within this if statement if (double [][] = new double [3][]) is not a valid expression. You simply want to evaluate the length, which you can do like if (m.length == 3). You did the same thing later on.
The line including (m[0].length = n-1) && (m[1].length = n) && (m[2].length=n-1) is not valid because you are performing assignment (=) in all three cases. An equality check is the double equals operator ==.
You do not return a value in every case. You can fix this by adding return false; after the closing brace of your first if statement, i.e. the last line of the function.
This is enough to get your code to compile. As mentioned in another answer though, your logic is confusing and without actually tracing it through I would speculate that it will not work as you would expect.
If I have understood your requirements correctly, you can rewrite the entire function as:
static boolean isValidTridiagonal ( double [][] m)
{
return m.length == 3 &&
m[0].length + 1 == m[1].length &&
m[2].length + 1 == m[1].length;
}
A proper IDE - Netbeans, Eclipse, etc. - will give you fairly descriptive error messages to show you where you've gone wrong.
This is basically completely stylistic but I wish someone had pointed this out to me earlier. If you ever find yourself writing code in this form:
if( (m[0].length == n-1) && (m[1].length == n) && (m[2].length == n-1))
{
return true;
}
else
{
return false;
}
know that you can save yourself so many lines without losing any readability by instead writing:
return (m[0].length == n-1) && (m[1].length == n) && (m[2].length == n-1);
In this code, I've used a global variable to increase the value of p whenever control touches the base case. But I want to do it without using a global variable. Is that possible?
public class stairCase {
static int p=0;
public static void main(String[] args) {
// TODO Auto-generated method stub
int n = func(14,0);
System.out.println(n);
}
public static int func(int n, int c){
if(n==c){
p++;
return 1;
}
if(n-c>=1){
func(n,c+1);
}
if(n-c>=2){
func(n,c+2);
}
if(n-c>=3){
func(n,c+3);
}
return p;
}}
Your problem is that you're throwing away a major communication resource: the return value. You recur in three places, but ignore the value. Harness that, and you'll solve your problem.
Consider something like this:
if (n < c) return 0 // Jumping too far gives no solution
else if (n == c) return 1 // Jumping to the top step is 1 solution
else
return func(n, c+1) + // Other jumps: sum the solutions from
func(n, c+2) + // each of the reachable steps.
func(n, c+3)
For future programming, please learn about useful variable names and documentation. I would not have followed this decently, had I not solved this problem yesterday in another posting.
You can do a little better with this problem if you reverse your counting. Note that you never change n as you recur -- in that case, why pass it at all? Start c at 14 and count to step 0 (the top).
Converting the code is left as an exercise for the student. :-)
I already searched everywhere for a solution for my problem, but didn't get one. So what I'm trying to do ist use recursion to find out whats a passed integer variable's base to the power of the passed exponent. So for example 3² is 9. My solution really looks like what I found in these forums, but it constantly gives me a stack overflow error. Here is what I have so far.(To make it easier, I tried it with the ints directly not using scanner to test my recursion) Any idea?
public class Power {
public static int exp(int x,int n) {
n = 3;
x = 2;
if (x == 0) {
return 1;
}
else {
return n * exp(n,x-1);
}
}
public static void main(String[] args) {
System.out.println(exp(2,3));
}
}
Well, you've got three problems.
First, inside of the method, you're reassigning x and n. So, regardless of what you pass in, x is always 2, and n is always 3. This is the main cause of your infinite recursion - as far as the method is concerned, those values never update. Remove those assignments from your code.
Next, your base case is incorrect - you want to stop when n == 0. Change your if statement to reflect that.
Third, your recursive step is wrong. You want to call your next method with a reduction to n, not to x. It should read return x * exp(x, n-1); instead.
A friend is doing an online Scala course and shared this.
# Write a recursive function that counts how many different ways you can make
# change for an amount, given a list of coin denominations. For example, there
# are 3 ways to give change for 4 if you have coins with denomiation 1 and 2:
# 1+1+1+1, 1+1+2, 2+2.
If you are attending and still working on a solution, don't read this!
(disclaimer: even if my Python solution may be wrong, I don't want to influence your thinking if you are on the course, one way or the other! I guess it is the thinking that goes into it that yields learning, not just the "solving"...)
That aside...
I thought I'd have a go at it in Python as I don't have the Scala chops for it (I am not on the course myself, just interested in learning Python and Java and welcome "drills" to practice on).
Here's my solution, which I'd like to port to Java using as compact a notation as possible:
def show_change(money, coins, total, combo):
if total == money:
print combo, '=', money
return 1
if total > money or len(coins) == 0:
return 0
c = coins[0]
return (show_change(money, coins, total + c, combo + [c]) +
show_change(money, coins[1:], total, combo))
def make_change(money, coins):
if money == 0 or len(coins) == 0:
return 0
return show_change(money, list(set(coins)), 0, [])
def main():
print make_change(4, [2, 1])
if __name__ == '__main__':
main()
Question
How compact can I make the above in Java, allowing the use of libraries external to the JDK if they help?
I tried doing the porting myself but it was getting very verbose and I thought the usual "there must be a better way of doing this"!
Here my attempt:
import java.util.ArrayList;
import java.util.List;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
public class MakeChange {
static int makeChange(int money, int[] coins) {
if (money == 0 || coins.length == 0) {
return 0;
}
return showChange(money, Ints.asList(coins), 0, new ArrayList<Integer>());
}
static int showChange(int money, List<Integer> coins, int total,
List<Integer> combo) {
if (total == money) {
System.out.printf("%s = %d%n", combo, total);
return 1;
}
if (total > money || coins.isEmpty()) {
return 0;
}
int c = coins.get(0);
List<Integer> comboWithC = Lists.newArrayList(combo);
comboWithC.add(c);
return (showChange(money, coins, total + c, comboWithC) + showChange(money,
coins.subList(1, coins.size()), total, combo));
}
public static void main(String[] args) {
System.out.println(makeChange(4, new int[] { 1, 2 }));
}
}
Specifically, what I dislike a lot is having to do the stuff below just to pass a copy of the list with an element appended to it:
List<Integer> comboWithC = Lists.newArrayList(combo);
comboWithC.add(c);
Please show me how compact and readable Java can be. I am still a beginner in both languages...
Really, almost everything you're doing here is directly convertible to Java, without much extra verbosity.
For example:
def make_change(money, coins):
if money == 0 or len(coins) == 0: return 0
return calculate_change(money, list(set(coins)), 0)
The obvious Java equivalent is:
public static int make_change(int money, int coins[]) {
if (money == 0 || coins.length == 0) return 0;
return calculate_change(money, coins, 0);
}
A few extra words here and there, an extra line because of the closing brace, and of course the explicit types… but beyond that, there's no big change.
Of course a more Python and Javariffic (what is the equivalent word?) version would be:
def make_change(money, coins):
if money == 0 or len(coins) == 0:
return 0
return calculate_change(money, list(set(coins)), 0)
The obvious Java equivalent is:
public static int make_change(int money, int coins[]) {
if (money == 0 || coins.length == 0) {
return 0;
}
return calculate_change(money, coins, 0);
}
So, Java gets one extra closing brace plus a few chars of whitespace; still not a big deal.
Putting the whole thing inside a class, and turning main into a method, adds about 3 more lines. Initializing an explicit array variable instead of using [2, 1] as a literal is 1 more. And System.out.println is a few characters longer than print, and length is 3 characters longer than len, and each comment takes two characters // instead of one #. But I doubt any of that is what you're worried about.
Ultimately, there's a total of one line that's tricky:
return (calculate_change(money, coins, total + c, combo + [c]) +
calculate_change(money, coins[1:], total, combo))
A Java int coins[] doesn't have any way to say "give me a new array with the tail of the current one". The easiest solution is to pass an extra start parameter, so:
public static int calculate_change(int money, int coins[], int start, int total) {
if (total == money) {
return 1;
}
if (total > money || coins.length == start) {
return 0;
}
return calculate_change(money, coins, 0, total + coins[start]) +
calculate_change(money, coins, start + 1 total);
}
In fact, nearly everything can be trivially converted to C; you just need to pass yet another param for the length of the array, because you can't calculate it at runtime as in Java or Python.
The one line you're complaining about is an interesting point that's worth putting a bit more thought into. In Python, you've got (in effect):
comboWithC = combo + [c]
With Java's List, this is:
List<Integer> comboWithC = Lists.newArrayList(combo);
comboWithC.add(c);
This is more verbose. But that's intentional. Java List<> is not meant to be used this way. For small lists, copying everything around is no big deal, but for big lists, it can be a huge performance penalty. Python's list was designed around the assumption that most of the time, you're dealing with small lists, and copying them around is perfectly fine, so it should be trivial to write. Java's List was designed around the assumption that sometimes, you're dealing with huge lists, and copying them around is a very bad idea, so your code should make it clear that you really want to do that.
The ideal solution would be to either use an algorithm that didn't need to copy lists around, or to find a data structure that was designed to be copied that way. For example, in Lisp or Haskell, the default list type is perfect for this kind of algorithm, and there are about 69105 recipes for "Lisp-style lists in Java" or "Java cons" that you should be able to find online. (Of course you could also just write your a trivial wrapper around List that added an "addToCopy" method like Python's __add__, but that's probably not the right answer; you want to write idiomatic Java, or why use Java instead of one of the many other JVM languages?)
(In the process of writing my original question, I answered it, but the information might be useful to others, and I thought of a new question)
For instance:
int x;
if (x = 5) { ... }
Creates an error:
Type mismatch: cannot convert from int to boolean. (Because assignment doesn't return a
boolean value)
However,
int x;
if ((x = 5) == 5) {
System.out.println("hi!");
}
will print out "hi!"
And similarly,
String myString = "";
if ((myString = "cheese").equals("cheese")) {
System.out.println(myString);
}
prints out "cheese"
Sadly,
if ((int x = 5) > 2) { ... }
does not work with an in-line declaration. How come? Can I get around this?
Sadly,
I suspect that most Java developers would heartily disagree with that sentiment ...
if ((int x = 5) > 2) { ... }
does not work with an in-line
declaration. How come?
It does not work because a declaration is not a Java expression, and cannot be used in an Java expression.
Why did the Java designers not allow this? I suspect that it is a combination of the following:
Java's syntactic origins are c and C++, and you cannot do this in C or C++ either,
this would make the Java grammar more complicated and the syntax harder to understand,
this would make it easier to write obscure / cryptic programs in Java, which goes against the design goals, and
it is unnecessary, since you can trivially do the same thing in simpler ways. For instance, your example can be rewriten this to make the declaration of x to a separate statement.
Can I get around this?
Not without declaring x in a preceding statement; see above.
(For what it is worth, most Java developers avoid using assignments as expressions. You rarely see code like this:
int x = ...;
...
if ((x = computation()) > 2) {
...
}
Java culture is to favour clear / simple code over clever hacks aimed at expressing something in the smallest number of lines of code.)
Your x only exists within the scope of the assignment, so it's already gone by the time you get to > 2. What is the point of this anyway? Are you trying to write deliberately unreadable code?
Your best way to get around this is to declare x in a scope that will remain valid throughout the if statement. Seriously though, I fail to understand what you're doing here. Why are you creating a variable that is supposed to disappear again immediately?
if ((int x = 5) > 2) { ... }
Yes this will not compile because you can't declare variables inside the condition section of if clause
The > test will work fine, as long as you declare the int outside of the if condition. Perhaps you are simplifying your condition for the sake of brevity, but there is no reason to put your declaration in the condition.
Can I get around this?
Yes, declare your var outside the condition.
Because you didn't declare the int separately as you did in the == test.
jcomeau#intrepid:/tmp$ cat /tmp/test.java
class test {
public static void main(String[] args) {
int x;
if ((x = 5) > 2) System.out.println("OK");
}
}
In Java, for() allows initialization code, but if() doesn't.
You can't declare the variable in condition section. For example
for(int i = 0; j < 9; i++){...}
is completely valid statement. Notice we declare the variable in for but not in a condition clause, now look at this,
for(int i = 0; (int j = 0)<9; i++){...} // Don't try to make logical sense out of it
not allowed.