I've written a class which represents a polynom using a linked list (members in that list are objects of another class I made called PolyNodes). In that class I've written this method (this methods is supposed to get a paramater polynom and add it to existing polynom, returning the sum of the two polynoms while not changing the paramater):
public Polynom addPol(Polynom other)
{
if (_head==null) //If the head is null, this polynom is empty and
the other polynom becomes this polynom
{
_head=other._head;
return this;
}
if(other._head==null) //if the polynom to be added is null, the
same polynom is returned
return this;
PolyNode curr=_head, curr2=other._head, prev=null, prev2=null;
while(curr!=null && curr2!=null)
{
if(curr2.getPower()>curr.getPower())
{
System.out.println("1 " + curr2.getCoefficient());
PolyNode copy = new PolyNode(curr2.getPower() ,curr2.getCoefficient() );
System.out.println("2 " + curr2.getCoefficient());
copy.setNext(curr);
if (prev==null)
_head=copy;
else
prev.setNext(copy);
}
else if (curr2.getPower() == curr.getPower()) //If this polynom already
has a term with the same power, curr2's and curr's coefficients are summed up
{
curr.setCoefficient(curr.getCoefficient() + curr2.getCoefficient());
}
//Moving the pointer to the next node in the polynom
if(curr2.getPower()>curr.getPower())
{
prev2=curr2;
curr2=curr2.getNext();
}
else if(curr.getPower()>curr2.getPower())
{
prev=curr;
curr=curr.getNext();
}
else if(curr.getPower()==curr2.getPower())
{
prev2=curr2;
curr2=curr2.getNext();
prev=curr;
curr=curr.getNext();
}
}
if(curr2!=null) //If there are nodes left in other
{
for(;prev!=null;curr2=curr2.getNext()) //add them to this
{
PolyNode copy = new PolyNode(curr2.getPower() ,curr2.getCoefficient() );
prev.setNext(copy);
prev=curr2;
}
}
return this;
}
For some reason (that is beyond me), the paramater polynom is changed as well when I use this method, when I try to keep it unchanged. I have no clue why. can someone please help me? I'm losing hope here.
you have this line:
PolyNode curr=_head, curr2=other._head
what you're doing there is giving a reference to _head and to other._head (the references are to their memory addresses).
so when you change of the objects, all of the objects with the same memory address will be changed as well.
if you want them not to be changed you need to allocate them with a new address in the memory.
you could do that:
PolyNode curr = new PolyNode(_head)
suppose you have a copy constructor.
Related
I'm writing a code to save, delete and load a person's height and weight data. I have created 2 classes:
class Person {
private int height;
private int weight;
public Person(int h, int w) {
height = h;
weight = w;
}
public int getHeight() {
return height;
}
public int getWeight() {
return weight;
}
public String getValues() {
return ("Height "+height+" and weight "+weight);
}
}
class DataModified { //Problem in this class
private LinkedList<Person> lList;
private ListIterator<Person> lIter;
public DataModified() {
lList = new LinkedList<Person>();
lIter = lList.listIterator();
}
public void save(Person p) {
Person p1, p2; //p1: Data needed to be saved
p1 = new Person(p.getHeight(), p.getWeight()); //p2: Data already on the list
boolean alreadyExist = false;
lIter = lList.listIterator();
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p1.getHeight()) && (p2.getWeight() == p1.getWeight())) {
alreadyExist = true;
}
}
if(alreadyExist) {
System.out.println("Person: " + p1.getValues() + " had already been on the list.");
}
else {
lIter.add(p1);
System.out.println("Person: " + p1.getValues() + " is added to the list.");
}
}
public void delete(Person p) {
Person p3, p2; //p3: Data needed to be deleted
p3 = new Person(p.getHeight(), p.getWeight());
boolean alreadyExist = false;
lIter = lList.listIterator();
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p3.getHeight()) && (p2.getWeight() == p3.getWeight())) {
alreadyExist = true;
}
}
if(alreadyExist) {
lIter.remove();
System.out.println("Person: " + p3.getValues() + " is deleted from the list.");
}
else {
System.out.println("Person: " + p3.getValues() + " is not on the list.");
}
}
public void load() { //Problem
lIter = lList.listIterator();
Person p2;
for(int i = 1; lIter.hasNext(); i++){
p2 = lIter.next();
System.out.println("Person "+i+" has "+p2.getValues());
}
}
}
I had tested these 3 methods from class DataModified: I first save data from 3 persons, then delete 1 person and load the rest. However, the last method prints not the 2 persons on the list, but the person I have deleted before.
My question are:
What is wrong with my code? Why did the load() method work like that?
I noticed that after iterating, I can only modified the lIter. So are lList and lIter the same list or 2 separated lists? If they are not the same, how can I give lList the data from lIter?
Is there a way to stop the iteration of a list?
As others are pointing out, you definitely have a bug in your delete method. As written, if the target Person is found in the list, then the last Person in the list will be removed, not the target. You really need to be able to cut out of the while loop when you find the person and remove it immediately instead of continuing the loop.
To answer your questions:
What's wrong? The bug in delete that removes the wrong Person.
Are lList and lIter the same list? Conceptually yes, technically no. lList is the list itself, and lIter is the Iterator acting on that list. It's not a list itself. It's an Iterator. But the data it's working on is definitely the same list.
How to stop iteration? You have a few options. The easiest for how your code is currently written is a break statement. It stops execution of the current loop and resumes executing outside the block. In both your add and delete methods, it would make sense to break right after alreadyExist is set to true. Another option, suggested first by jiveturkey, is to add alreadyExist as a condition to the while loops. Then you'll only continue iterating if both there are more items to iterate over and alreadyExist hasn't yet been set to true. A third option would be to do the real work (i.e delete) as soon as you find the Person and then return from the method entirely.
Beyond that, some unsolicited general advice :)
You're comparing Person objects in multiple methods. Over time, this will get hard to maintain, so it would be better to define the comparison in one place. Java comes with an equals method for this. It's in every Object, but the default implementation won't help you, so you want to override it. In your case, you consider two distinct Person objects to be conceptually equal if their heights and weights are equal. So override the equals() method in Person to return true iff the height and weight are equal. See How to override equals method in java or http://users.csc.calpoly.edu/~gfisher/classes/102/info/howToOverrideEquals.html for some tips. If you override equals, you also need to override hashCode.
You're making copies of the Person parameters. The exact object being passed in is not the actual object being added or deleted from the list; the copy is. You could just use the paremeter. In the best case, you currently have an unnecessary performance hit (creating extra objects). In the worst case you'll hit bugs.
lIter is set both in the constructor and in every method. If you don't need to store its current state across method calls, then it should probably be just a local variable, used for a method and then discarded.
getValues() is currently just being used to make the object human-readable. That's a common problem, and the task given to toString(), also defined in Object and overridable in any class you write. All you'd need to do to take advantage of it is rename getValues to toString. Then you could just use it in a log message directly. Example below.
Here's how I would then rewrite delete, assuming a good equals method in Person, and getValues renamed to toString:
public void delete(Person p) {
boolean alreadyExist = false;
ListIterator definitelyNotLIter = lList.listIterator();
while(definitelyNotLIter.hasNext()) {
Person current = definitelyNotLIter.next();
if (p.equals(current)) {
alreadyExist = true;
definitelyNotLIter.remove();
// Option 1:
break; // next line to execute will be the if(alreadyExist) block
// Option 2:
// put your successful delete logging here
// return;
// and leave the failed delete logging outside the loop
// Option 3:
// Do nothing. The looping will continue, and you'd have a deleteAll method, where multiple items would get deleted if you managed to get duplicates in the list.
// You actually wouldn't need alreadyExist any more.
// I'd go with option 1, myself
}
}
if(alreadyExist) {
System.out.println("Person: " + p + " is deleted from the list."); // p.toString() will get called
}
else {
System.out.println("Person: " + p + " is not on the list."); // p.toString() will get called
}
}
In delete(), once you find your Person you set alreadyExist to true the first time you find someone and keep going. So once it's set, it's set for EVERYONE. If you find your Person in the list in position 1, you'll delete him, but then you'll delete the next person and so on. All of your while loops need to say.
while (!alreadyExists && lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p1.getHeight()) && (p2.getWeight() == p1.getWeight())) {
alreadyExist = true;
lIter.remove();
}
}
// Delete the if/else code
You should probably get rid of the member variable:
private ListIterator<Person> lIter;
From Documentation:
void remove() Removes from the list the LAST element that was returned
by next() or previous()
But when you reach the required Person Object, you continue iteration the next Person Object.
What you need is to break the while loop once it finds the target object.
if ((p2.getHeight()==p3.getHeight())&&(p2.getWeight()==p3.getWeight())){
alreadyExist = true;
break;
}
Now the last element is the required Object, you can now use remove().
if(alreadyExist) {lIter.remove();}
The problem is in your delete method:
You loop through the entire list before removing anything. ListIterator.remove only deletes the last item returned by next(). You need to break when you find the item that already exists:
while(lIter.hasNext()) {
p2 = lIter.next();
if ((p2.getHeight() == p3.getHeight()) && (p2.getWeight() == p3.getWeight())) {
alreadyExist = true;
break;
}
}
Additionally, the way you are comparing Person objects should really be done in a equals() method, as described here.
Finally, your creation/use of an extra Person that is a duplicate of parameter p is entirely unnecessary here. Just use p instead of p1 (in save) and p3 (in delete).
I have a custom linked list with Student object stored as Node object in it. I have a method, public Student worstStudentRec(Node list) which takes the head Node (list) and recursively finds the node containing the Student with the highest GPA. My code below works for this purpose, but I'm confused on whether or not I can change the method code so that it works without declaring variables outside of that class. For example, I declared private Node baseCase to serve as the node containing the Student with the lowest GPA, and worstStudent to serve as my eventual return variable. I'm completely stuck and can't figure out whether this can be done without declaring these variables outside of the method or not.
My code for the method is below. Thanks!
private Node baseCase = new Node (new Student ("", Double.MAX_VALUE, 0));
private Student worstStudent;
public Student worstStudentRec(Node list)
{
if (list == null)
return worstStudent;
else if (list.next == null)
return worstStudent;
else
worstStudent = (baseCase.data.compareTo(list.data) <= 0) ? baseCase.data : list.data;
baseCase = (baseCase.data.compareTo(list.data) <= 0) ? baseCase : list;
return worstStudentRec(list.next);
}
yes you can avoid declaring those outside..
for worst student you can pass another variable worsTudentNode. So in the method check whether the current student is worse than the previous worstStudent. If yes then pass the current student to the next recursion call else use the previous one.
Here is a pseudo code
public Student worstStudentRec(Node list, Node worstStudent)
{
if (list == null || list.next == null)
return worstStudent;
else{
worstStudent = compare with current and add the worse
return worstStudentRec(list.next, worstStudent);
}
}
You can:
public Student worstStudentRec(Node list)
{
if (list == null)
return null; // add null-handling
else if (list.next == null)
return list.data;
Node theWorstFromOthers = worstStudentRec(list.next);
return (list.data.compareTo(theWorstFromOthers.data) <= 0) ? list.data : theWorstFromOthers.data;
}
When you use recursion - keep in mind that you can do not only chain execution but also a computation. In other words - you can(and in many cases) should use result of recursion in your computations.
I'm trying to make a LinkedList containing the "best of" of an offspring in an evolutionary algorithm.
Therefore, I have my own custom add() method:
public boolean add(Virus v) {
if((this.size()< ConfigObject.getInstance().surviverPopulation //if the size of the new population is < surviverPopulation
|| v.getFitness() > this.getLast().getFitness()) //or the fitness is higher than that of the last member
&& v.getFitness() > 0.0 //and the fitness is higher than 0
&& !v.isDead() //and the virus is alive
&& !this.contains((Virus)v)) { //and it is not yet in the list
super.add(v); //add it normally
Collections.sort(this, new Comparator<Virus>() { //sort the list
//define parameter to sort by
#Override
public int compare(Virus virus1, Virus virus2) { //with custom comparator
if(virus1.getFitness() == virus2.getFitness()) {
return 0;
} else if (virus1.getFitness() > virus2.getFitness()) {
return -1;
} else {
return 1;
}
}
});
}
while(this.size() > 300) {
this.removeLast();
}
return true;
}
With this method, I get a LinkedList of limited size which is also sorted and only contains the "best" objects. (The rest of the LinkedList-class is unaltered).
However, when I use this class, something strange happens:
for(Virus parent : this.currentPopulation) { //for every virus in the current population
for(GraphNode child : parent.getChildren()){ //get all the children, and for each child
temp = (Virus) child;
if(!temp.isDead() && !newCurrentPopulation.contains(child)) { //try to add the child if it's not dead
newCurrentPopulation.add((Virus) child); //and not already in the list
} //(list only takes a maximum of <surviverPopulation>
} //and only the strongest ones, see declaration)
newCurrentPopulation.add(parent); //also try to add the parent to the list if
} //still alive
int j = 0;
for(Virus parent : this.currentPopulation) { //for every virus and its children in the current population
for(GraphNode child : parent.getChildren()){ //check if it made it into the new population
if(!newCurrentPopulation.contains((Virus) child)) {
toRemove.add((Virus) child); //if not, memorize to delete it later
}
}
if(!(newCurrentPopulation.contains((Virus) parent))); {
toRemove.add(parent); //do the same for the parent virus
}
}
It works quite fine for the children, but not for the parent. The debugging info shows that even though the parent (identifiable by an id) is in the newCurrentPopulation, it will be included into the toRemove list (where it's also identifiable by the same id).
Also, I did not override the equals-method for the Virus-class or any of its superclasses. I'm probably missing something quite obvious here but I can't see it.
It is something extremely obvious indeed: the last if-statement is followed by a semicolon and not the {}.
The contains method internally calls the equals method of Virus class.
The default equals method provided by the Object class uses == operator, which in your case returns false.
You have to override the equals method in Virus class and compare the objects with id.
Ok so i need to deleted items from a circular list,as part of a bigger program that isnt working, and i cant seem to delete the last node passed in to the delete method, if the index passed in is 1 it will delete the 1st node in list and replace it, but when there is only one node left it has nothing to reference off, been at this hours. i will leave my delete method here
public void delete(int index)
{
if(Node.numOfUsers == 1)
{
first=null;
return;
}
//make curr the same as first node
int i = 1;
curr=first;
//if index passed in is 1, make temporary node same as one after first node
// if(size<1)
// {
// System.out.println("ok so this is where we are at");
// }
if(index==1)
{
temp=first.nextNode;
while(temp.nextNode!=first)
{
temp=temp.nextNode;
}
temp.nextNode=temp.nextNode.nextNode;
first=curr.nextNode;
}
else
{
//as long as i is not equal to node index-1 move current on 1 and increment i by 1
while(i != index-1)
{
curr=curr.nextNode;
i++;
}
//curr.nextNode is pointing to the node index we want and making it equal to one index above it
curr.nextNode=curr.nextNode.nextNode;
}
Node.numOfUsers--;
int size=size();
}
}
Looks like you're keeping track globally of a number of users. If this behaves the way I think it would, you could just have a small check at the beginning of this method so that if it is zero, you don't follow through with any of the logic following it.
if(Node.numOfUsers == 0) return;
This will make it so you don't bother executing any of the other logic.
A slightly better methodology to this problem might be to use the Node you want to delete as a parameter, rather than its index. This way you can avoid having to keep track of indices inside your data structure.
e.g.
public void delete(Node n) {
if(Node.numOfUsers == 0 || n == null) return; // 0 nodes or null parameter.
Node temp = first;
if(temp.next == null) { //only one node
temp = null; //simply delete it
} else {
while(temp.next != n) {
temp = temp.next;
if(temp == first) { //if we circle the entire list and don't find n, it doesn't exist.
return;
}
}
temp.next = n.next; // perform the switch, deleting n
}
}
EDIT: The above code follows the assumption that you'll have references to the node you want to delete. If this is not the case, using indices is just as good. You may also consider comparing values, however this would require you to assume that you have unique values in your nodes (and I don't know what you're restrictions are).
The logic for comparing values would be identical to the above, however instead of comparing if(temp == n) for example, you would compare if(temp.data.equals(n.data)). The use of the .equals() method is specifically for the String type, but you could modify it to work with whatever data type you are expecting, or better yet write a custom .equals method that allows the use of Generics for your abstract data type.
I've written a class which represents a polynom using a linked list (members in that list are objects of another class I made called PolyNodes).
In that class I've written this method:
public Polynom addNode (PolyNode p)
{
if (p==null) //if the polynode to be added is null, the same polynom is returned
return this;
if (_head==null) //If the head is null, the polynom is empty and the polynode becomes the polynom
{
_head=p;
return this;
}
PolyNode curr = _head, prev = null;
while(curr != null) //when curr becomes null that means we reached the end of the polynom hence we reached the end of the loop as well
{
if (p.getPower() > curr.getPower()) //Upon reaching the first term whose power is lower than p's power
{
p.setNext(curr);
if (prev == null) //When curr is the polynom's head
_head = p;
else
prev.setNext(p);
return this;
}
else if (p.getPower() == curr.getPower()) //If the polynom already has a term with the same power, p's and curr's coefficients are summed up
{
curr.setCoefficient(curr.getCoefficient() + p.getCoefficient());
return this;
}
prev = curr;
curr = curr.getNext();
}
//If the method reached outside of the loop then there is no term in the polynom whose power is smaller than p's, and p will become the last term in the polynom
p.setNext(null);
prev.setNext(p);
return this;
}
The problem started when I tried writing an addPol() method.
public Polynom addPol (Polynom other)
{
for (PolyNode temp=other._head ; temp!=null ; temp=temp.getNext())
{
addNode(temp);
}
return this;
}
I can't figure out why, but I'm getting wrong results. I went through the code dozens of times and still couldn't find anything that could cause the problem.
problem goes as follows:
when I print list1 I get:
-5.0x^20+5.0x^17+4.0x^11+6.0x^8-5.0x^7+16.0x+1.0
when I print list2 I get
-3.0x^100+2.0x^17-3.0x^4+4.0x
however, when I print list1.addPol(list2)
-3.0x^100-10.0x^20+10.0x^17+8.0x^11+12.0x^8-10.0x^7+32.0x+2.0
If anyone could please tell me what is causing this I would greatly appriciate it. thanks in advance.
When you add the node to a new list its properties get changed, so then when you move onto next you move to the next in the second list.
You would be better off just using the provided LinkedList class for this rather than trying to re-invent it yourself.
Something like:
PolyNode copy = new PolyNode();
copy.setCoefficienttemp.getCoefficient());
copy.setPower(temp.getPower());
addNode(copy);
As mentioned, otherwise temp.getNext() will be changed in the original list.
It would be more abstract to have a class Term + next == PolyNode without next.