/ 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.
Related
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 ) );
}
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.
My god feeling tells me the answer is "Integer and String are immutable", but I want to get confirmation from experts here.
I have a traverse method, which basically will traverse the whole tree starting from the root. Here are two types of usage, first one wont work, always return 0, second one works, the result ArrayList can accumulate in traverse.
Here is the first one:
public int whateverSum(TreeNodeType root, int target) {
int sum = 0;
traverse(root, target, sum);
return sum;
}
Here is the second one:
public List<String> whateverSum(TreeNode root, int target) {
List<String> result = new ArrayList<String>();
traverse(root, target, result);
return result;
}
Please help me the confirm my thought if it is correct.
You got it right. In fact, what happens is that the traverse method passes down the value of an int but not the value of the ArrayList.
Well, what happens is the difference between values and reference. When you are passing down an int to a function, the value is copied. The function accesses the copy of the value. It uses it in whichever way possible, but in the end all of the operations are done to the copy of the value, without the original being modified.
When you are passing an Object to a function, you are passing a reference to it, just like a memory address. It makes sense because when you are passing an ArrayList of millions of items, you would rather not want those millions of items being copied everytime. So, what is being copied is the reference to this Object, which point to the original structure.
That's why, when you pass an int to a function, the original value will never be modified. Whereas when you pass an ArrayList, its content will change.
Now, not all objects behave this way, this is where immutable objects come. You said it String are immutables, which is very handy. So, when you do a modification on a String, it is copied and the original value doesn't change either. Types like Integer or Double are also immutable. It makes lots of sense, because when you're incrementing an integers, you don't want all of the 1 of your program becoming 2's.
Regarding your code, in order to get the first method work, you can do something like:
public int whateverSum(TreeNodeType root, int target) {
int sum = traverse(root, target, 0);
return sum;
}
Where traverse returns the updated sum.
Alright, I'm new to Java, I'm just working through a class, and I've hit a bit of a snag on a program for class. I've managed to work my way through every bit of my final program, except for this last thing.
public static void remove(String studentID)
{
Integer foundLocation = 0;
for (int i = 0; i < studentList.size(); i++)
{
if (studentList.get(i).getStudentID().compareTo(studentID) == 0)
{
//This means we have found our entry and can delete it
foundLocation = i;
}
}
System.out.println(foundLocation);
if (foundLocation != 0)
{
System.out.println(studentList);
studentList.remove(foundLocation);
System.out.println(foundLocation.getClass().getName());
System.out.println("Student ID removed: " + studentID);
System.out.println(studentList);
}
else
{
System.out.println("Sorry, " + studentID + " not found.");
}
The code seems like it should work. But, what I get is that the remove doesn't actually do anything. My extra prints are there to verify. The ArrayList just plain doesn't change.
However, if I just replace:
studentList.remove(foundLocation);
with something like:
studentList.remove(3);
It just removes perfectly.
foundLocation is an Integer.
Can someone explain to me what I've got going on here?
I expect it's blindingly obvious to someone familiar with Java, but I'm missing it.
This is a bit of a nasty overload that snuck into the Collections API design.
There are two remove methods, one that you call with an int, and one that you call with an Object, and they do very different things.
Unfortunately for you Integer is also an Object, even though you want to use it as an int (and do that in a couple of other places, thanks to the magic of autoboxing that unfortunately does not work for remove).
remove(1) will remove by index (the 2nd element).
remove(Integer.valueOf(1)) will remove the object by its value (the first "1" found in the list).
It would have probably been wiser to give these two methods two different names.
In your case, change foundPosition to be an int.
ArrayList have two remove method,one is remove(int index) and the other is remove(Object object),
Your foundLocation type is Integer,when use it it will be a reference,so when you call remove(foundLocation) it will call remove(Object),trying to find a element == foundLocation,it can't find this so remove nothing,once you change the type to int,it will remove element at index foundLocation,refer the method doc.
There are two 'remove' methods in the ArrayList class. One accepts an Object type, the other accepts a int type. By using the Integer object, you are finding an element in the list that is equals to the Integer object. However when you remove by an int type, you are moving by the position of the element in the list.
studentList.remove(foundLocation) will result in the ArrayList checking for a Integer object that is equal to the one that is referenced by foundLocation. This is an object equality check. Two different Integer objects with the same value is deemed as being different even though they have the same numeric value.
studentList.remove(3) will result in the ArrayList to remove the fourth element in the list.
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);
}
}