Recursive method for binary tree node couting - java

Ok, so i have to create a recursive method for counting the nodes in a tree, and i did this (variable names are in portuguese, sorry):
public int contaNos(Arvbin r) {
Integer cardinalidade = 0;
contaNosPrivado(r, cardinalidade);
return cardinalidade;
}
private void contaNosPrivado(Arvbin r, Integer cardinalidade) {
if (r==null) {
return;
}
cardinalidade=cardinalidade+1;
contaNosPrivado(r.esq, cardinalidade);
contaNosPrivado(r.dir, cardinalidade);
return;
}
Arvbin is the binary tree, esq and dir are the left and right references to the tree's branches.
I thought this would work, but for some reason when i try to run it, it returns 0. I've usen a little bit of debugging and i think the issue is that when the methods finish and come back to the original non-recursive one, the cardinalidade variable is set to 0. I'm not sure if it's because autoboxing is messing with my Integer and turning it into an int, and then when i call the method it passes a copy of the value instead of the reference to the existing object, and i don't know how to fix it. If anyone could help, i'd greatly appreciate it

The problem is that wrapper classes are immutable in Java. cardinalidade is just a parameter of contaNosPrivado here and, unfortunately, cannot act as an argument like other object type parameters can, i.e. this local reference cannot change inner fields of the object that initial reference refers. Any change to it affects it only the way it affects any primitive local variable.
What exactly happens inside your contaNosPrivado:
On invocation, it is indeed supplied a reference to an Integer object. This reference is assigned to a local variable named
cardinalidade.
In this line:
cardinalidade=cardinalidade+1;
this object is first unboxed to a primitive int variable, this variable is incremented afterwards, and
finally the result is reboxed into a new Integer object which is
then assigned to cardinalidade. There is no way to 'increment'
original object, even if you use the increment operator:
cardinalidade++;
Any further processing applies to the newly created Integer object and doesn't affect the reference passed to contaNosPrivado.
To achieve your goals, use something like this instead:
static int contaNosPrivado(Arvbin r) {
if (r == null)
return 1;
else
return contaNosPrivado(r.esc) + contaNosPrivado(r.dir);
}

As #John McClane has pointed out, you can't pass an Integer argument by reference, only by value.
But there's also no need for a private helper method, you can just simplify it all to a single method:
public int countLeaves( BinaryTreeNode n )
{
return n == null? 0 : ( countLeaves( n.rightLeaf ) + countLeaves( n.leftLeaf ) );
}
Or (excuse my poor Portugese):
public int contaNos( Arvbin r )
{
return r == null? 0 : ( contaNos( r.esq ) + contaNos( r.dir ) );
}

Related

Delete value for previously assigned int field [duplicate]

Can an int be null in Java?
For example:
int data = check(Node root);
if ( data == null ) {
// do something
} else {
// do something
}
My goal is to write a function which returns an int. Said int is stored in the height of a node, and if the node is not present, it will be null, and I'll need to check that.
I am doing this for homework but this specific part is not part of the homework, it just helps me get through what I am doing.
Thanks for the comments, but it seems very few people have actually read what's under the code, I was asking how else I can accomplish this goal; it was easy to figure out that it doesn't work.
int can't be null, but Integer can. You need to be careful when unboxing null Integers since this can cause a lot of confusion and head scratching!
e.g. this:
int a = object.getA(); // getA returns a null Integer
will give you a NullPointerException, despite object not being null!
To follow up on your question, if you want to indicate the absence of a value, I would investigate java.util.Optional<Integer>
No. Only object references can be null, not primitives.
A great way to find out:
public static void main(String args[]) {
int i = null;
}
Try to compile.
In Java, int is a primitive type and it is not considered an object. Only objects can have a null value. So the answer to your question is no, it can't be null. But it's not that simple, because there are objects that represent most primitive types.
The class Integer represents an int value, but it can hold a null value. Depending on your check method, you could be returning an int or an Integer.
This behavior is different from some more purely object oriented languages like Ruby, where even "primitive" things like ints are considered objects.
Along with all above answer i would like to add this point too.
For primitive types,we have fixed memory size i.e for int we have 4 bytes and char we have 2 bytes. And null is used only for objects because there memory size is not fixed.
So by default we have,
int a=0;
and not
int a=null;
Same with other primitive types and hence null is only used for objects and not for primitive types.
The code won't even compile. Only an fullworthy Object can be null, like Integer. Here's a basic example to show when you can test for null:
Integer data = check(Node root);
if ( data == null ) {
// do something
} else {
// do something
}
On the other hand, if check() is declared to return int, it can never be null and the whole if-else block is then superfluous.
int data = check(Node root);
// do something
Autoboxing problems doesn't apply here as well when check() is declared to return int. If it had returned Integer, then you may risk NullPointerException when assigning it to an int instead of Integer. Assigning it as an Integer and using the if-else block would then indeed have been mandatory.
To learn more about autoboxing, check this Sun guide.
instead of declaring as int i declare it as Integer i then we can do i=null;
Integer i;
i=null;
Integer object would be best. If you must use primitives you can use a value that does not exist in your use case. Negative height does not exist for people, so
public int getHeight(String name){
if(map.containsKey(name)){
return map.get(name);
}else{
return -1;
}
}
No, but int[] can be.
int[] hayhay = null; //: allowed (int[] is reference type)
int hayno = null; //: error (int is primitive type)
//: Message: incompatible types:
//: <null> cannot be converted to int
As #Glen mentioned in a comment, you basically have two ways around this:
use an "out of bound" value. For instance, if "data" can never be negative in normal use, return a negative value to indicate it's invalid.
Use an Integer. Just make sure the "check" method returns an Integer, and you assign it to an Integer not an int. Because if an "int" gets involved along the way, the automatic boxing and unboxing can cause problems.
Check for null in your check() method and return an invalid value such as -1 or zero if null. Then the check would be for that value rather than passing the null along. This would be a normal thing to do in old time 'C'.
Any Primitive data type like int,boolean, or float etc can't store the null(lateral),since java has provided Wrapper class for storing the same like int to Integer,boolean to Boolean.
Eg: Integer i=null;
An int is not null, it may be 0 if not initialized. If you want an integer to be able to be null, you need to use Integer instead of int . primitives don't have null value. default have for an int is 0.
Data Type / Default Value (for fields)
int ------------------ 0
long ---------------- 0L
float ---------------- 0.0f
double ------------- 0.0d
char --------------- '\u0000'
String --------------- null
boolean ------------ false
Since you ask for another way to accomplish your goal, I suggest you use a wrapper class:
new Integer(null);
I'm no expert, but I do believe that the null equivalent for an int is 0.
For example, if you make an int[], each slot contains 0 as opposed to null, unless you set it to something else.
In some situations, this may be of use.

Return statement in Helper Method(Java)

I am practicing simple coding problems from codingbat. One of the problems are asking me to use helper method to prevent redundant codes. However, I am very lost because I do not know why I should use public and int as return type for this problem.(because the question asks me to use header below)
public int fixTeen(int n)
What does the return from the helper method doing? Also, how do I know if I should use private or public for my helper method?
Please take a look at my code.
// Given 3 int values, a b c, return their sum. However, if any of the values
// is a teen -- in the range 13..19 inclusive -- then that value counts as 0,
// except 15 and 16 do not count as a teens. Write a separate helper
// "public int fixTeen(int n) {"that takes in an int value and returns that value
// fixed for the teen rule. In this way, you avoid repeating the teen code 3
// times (i.e. "decomposition"). Define the helper below and at the same
// indent level as the main noTeenSum().
public int noTeenSum(int a, int b, int c) {
return fixTeen(a) + fixTeen(b) + fixTeen(c);
}
public int fixTeen(int n) {
if (n >= 13 && n <= 19 && n != 15 && n != 16)
n = 0;
return n;
}
Edit:
What is the difference between setting return type void and int for the helper method? At first, I thought return int is unnecessary and tried to set the return type as void but it gave me an error.
In general, at least for the beginnings of java, methods should be named public. Later on, when you get to object oriented programming, the area it's in (public or private) matters more. For example, adding the keyword "public" means that that value can be accessed outside of the class, while "private" means it cannot. This is important for when you don't want the end user to be able to access your private data.
Point is, when you make a method, for now have them set to public.
Next up is the helper method. After the "public" or "private", you have the return type. You have it set to "int". Therefore, the return type must be an integer. It can't be a string, or a double - it must be an integer. If you set the return value to "void", then there would be no return value, and if you tried to write "return(n);", it would give you an error.
So TLDR: It's named "public" because you want to be able to access this method outside of the class, and it says "int", because you need to return an integer type. Then, when you return(n), it'll give the value, say, a == 7, and if b == 18, it'll set b == 0. After that, it adds the numbers together, and you have your answer!

How can I get my binary tree insert function to work?

/ Solved /
I actually passed null. Since it doesn't contain any information, adding values to it won't affect my tree, thanks for the answer!
We have got a task in Java to create a binary tree which can hold integer. We have to write an insert function which inserts an integer to a tree by coincidence. I have now written the function but somehow it doesn't add the values I put in.
My class consists of an integer "value" and two references for the left and right branch, "left" and "right".
Also, I have to write this function in this way, so they have to return void, I am aware that there are easier ways.
So, for now, I already know that I get to the leaf. Then it's t == null. When I try, then to put "t = new CONSTRUCTOR(value, ...)"
it doesn't change anything.
public void insert_in_tree(int i) {
/*Creating random number*/
Random rand = new Random();
int rand_num = rand.nextInt(2);
if(rand_num == 0) {
setLeft(this.left, i);
} else {
setRight(this.right, i);
}
}
... here is the code for the "setLeft" (The "setRight" function is the same, I just pass the right subtree when I am calling it) function:
void setLeft(IntBinTree t, int value) {
if(t == null) {
t = new IntBinTree(value, null, null);
return;
}
int i = 0;
/*Random number*/
Random rand = new Random();
int rand_num = rand.nextInt(2);
/*Calling either left or right*/
if(rand_num == 0) setLeft(t.left, value);
setRight(t.right, value);
}
I suppose, the error is calling the function and changing then the local variable "t" instead of using "this". However, since I am passing a reference of "this", there shouldn't be any problem in doing this, can anyone spot the error?
You are passing a null to a function. NOT an object.
If you passed an object (e.g. "this"), it would pass the reference to that object (in reality, Java is "Pass by value", but what you pass by value is the reference, NOT the object itself) and any changes to it would reflect outside the function.
Passing a null would NOT do that since there is no object reference and you are just passing a value of "null" which has NOTHING to do with your original object, so any changes to "t" made inside the second function are lost.
What you should do is one of 2 things:
Pass "this" and a left/right flag.
Create left/right sub-tree (if empty) in the caller, pass the newly created and assigned subtree.
By the way, you have nearly identical code for left/right in the top level method and in set method - it would be easier to keep it entirely in the set method.

Java Tree Recursion parameter issues

I am attempting to give a void function to a Tree. It calculates some parameters and uses Ids to reference some coordinates and the distance between them. The problem I have is that every recursion call returns me 0 on both parameters I use, I thought in Java every variable was a reference so this would work, but I seem to be missing something. Here is the code:
public void volumeandcost(Integer volume,Float cost){
if(children().equals(0)){//children() returns the number of children our tree has
volume=volume+getCapacidad(this.root);//root is the Id
}
else{//recursive call
ArrayList<Integer> myvol= new ArrayList();
ArrayList<Float> mycost=new ArrayList();
for(int i=0;i<this.children();i++){
myvol.add(new Integer(0));
mycost.add(new Float(0.0));
children.get(i).volumeandcost(myvol.get(i), mycost.get(i));
cost=cost+mycost.get(i)+myvol.get(i)*
square(ProbIA5Board.m_dist.get(this.root).get(this.children.get(i).getId()));
}
//this calculates our volume in case we have children
volume=min(getCapacidad(root)*3,mysum(myvol)+getCapacidad(root));
}
}
I call this function with both parameters initially set at 0, and they come back in the same way after the call to volumeandcost.
After following some advice I implemented a new class Pair like this:
public class Pair {
Integer vol;Float cost;
public Pair (){this.vol=new Integer(0);this.cost=new Float(0);}
Integer getVol(){ return this.vol;}
Float getCost(){ return this.cost;}
void setVol(Integer x){this.vol=x ;}
void setCost(Float x){this.cost=x ;}
void addVol(Integer x){this.vol=this.vol+x;}
void addCost(Float x){this.cost=this.cost+x;}
}
and modified the function so that it's like this:
public void volumeandcostp(Pair p){
if(children().equals(0)){
p.setVol(p.getVol() + getCapacidad(this.root));//tenemos el volumen
}
else{//recursion
ArrayList<Pair> myvol= new ArrayList();
for(int i=0;i<this.children();i++){
myvol.add(new Pair());
children.get(i).volumeandcostp(myvol.get(i));
myvol.get(i).getCost());
p.addCost(myvol.get(i).getCost()+ myvol.get(i).getVol()* square(ProbIA5Board.m_dist.get(this.root).get(this.children.get(i).getId())));
} p.setVol(min(getCapacidad(root)*3,mysump(myvol)+getCapacidad(root)));
}
}
But all the getters from Pair keep giving me 0 as answer.
I thought in Java every variable was a reference.
First of all that statement is wrong: you have primitive types like int, float, char. Those are not references to begin with. But indeed variables with types other than those eight are references.
But when you call a function, Java does a call-by-value. That means the references are copied. When you call: volumeandcost(a,b). Java will make a copy of the reference. So volume and cost work independently. Setting them (i.e. assigning a new value to them) in your method has no effect.
You can alter the state of the objects you are given: since you copy the reference a refers to the same object as volume (in the example above), you can call methods on the objects the references refer to and alter the state, but you cannot change the reference itself.
As provided in other answers, you can only alter the state of the objects when you pass them to a method- Java is call by value.
Consider this instead of Integers :
List<Integer> list = new ArrayList<Integer>();
System.out.println( "Before adding size is " + list.size() );
modifyList(list);
System.out.println( "After adding size is " + list.size() );
public void modifyList( List<Integer> list )
{
list.add( 5 );
}
Why do you see the list.size() modified ? Because list's state is modified not the original reference to list itself, the copied reference that passed to method played with a method called add and modified the state of object it refers to. So when you call size() using original reference , you will get the updated state of the object.
Now, to tackle your problem, you could do it with devising your own class, some thing like :
class Metrics
{
Integer volume;
Float cost;
}
Pass Metrics to your new method and update the fields volume, cost inside your method.

java method to change the value of an array to null

public void setData(double[] d) {
if (d == null) {
data = new double[0];
} else {
data = new double[d.length];
for (int i = 0; i < d.length; i++)
data[i] = d[i];
}
}
this method in my code is used to set the data of an array. I am also required to write a method called reset() that changes a given array to have a null value. Also, we are practicing overloading in this lab. There are four versions of setData() (double, int, float, long). Since a double array is used internally by the Stat class to store the values, do I only have to make one reset() method of type double?(I think I only need one...) Finally, please give me some hints as to going about this reset business because everything I have tried has failed miserably and usually consists of statements such as
"setData(double[] null)" which return errors.
Everything in java is pass by value; even references are passed by value. So by passing an array through a method, you can change the contents of the array, but you cannot change what the array points to. Now, if you are inside a class and happen to pass an instance member that you already have access to by virtue of being in the class, you will be able to set the array to null.
If you always want to be able to change what an array points to, then simply have a function which returns an array (instead of being void), and assign that returned value to the array of interest.
Because java is pass by value, you can't reassign a variable passed as a parameter to a method, and expect to see that change reflected outside.
What you can do, is put the array in some sort of wrapper class like this:
class ArrayReference<T> {
T[] array; // T would be either Double, or Long, or Integer, or whatever
}
and then:
void setData(ArrayReference<Double> myReference) {
myReference.array = null;
}
I'm not sure if I understood your question, but is it that what you want?
public class Stat {
private double[] data;
public void reset() {
data = null;
}
public void setData(double[] d) {
data = (d == null) ? new double[0] : Arrays.copyOf(d, d.length);
}
}

Categories