Could someone tell me what's missing in my code. I am trying to remove the first occurrence of a given node value.
It fails very few test cases, but I am not sure what I am missing. Here is my code :
public boolean remove(E obj) {
if (obj == null)
throw new IllegalArgumentException("Violation of precondition : remove(E obj)");
DoubleListNode<E> current = head;
for (int i = 0; i < size; i ++) {
if (current.getData().equals(obj)) {
E result = remove(i);
return true;
}
current = current.getNext();
}
size --;
return false;
}
That recursive call to remove() inside the if block looks wrong.
You are already inside the list, you identified the first matching object. So now your code has to really remove that matching object. Removing would mean to update both links accordingly.
Do these things on paper! Draw a double linked list with nodes and the links between them. Then ask yourself what removing a node that has one or two links coming in (and potentially going out) actually means. You will have to change the links from the previous node and the one following the node that is to removed!
Related
Alright, so cut a long story short, what I'm trying to do here is remove all instances of value e from a doubly linked list. As far as I know, my logic is at least mostly right, but for some off reason it isn't actually removing any of the nodes in my test cases.
public boolean removeAll(int e) {
DIntNode dummy = head,next = null;
if (head == null)
return false;
while (dummy != null) {
if (dummy.getData() == e) {
next = dummy.getNext();
dummy.getNext().setPrev(null);
dummy = next;
return true;
}
else
dummy = dummy.getNext();
}
return false;
}
This is what I currently have for my code of the metho. My logic here was to use a dummy DIntNode that starts at the head and a "next" node to help me shrink the list, so to speak. In other words, if the list was something like "1<-> 1 <-> 2 <-> 3", the function would change it to "2<->3", in theory. The reason this is a boolean function is because I'm required to return true if the given value is removed form the list.
Is there just another step in the logic that I'm missing, or is the methodology itself just unreliable? I'm very unsure at this point, so any and all help would be greatly appreciated.
You set
dummy.getNext().setPrev(null);
But previous node also have reference to next node you try to remove. You should set this reference to next active value.
That because when you want to get all linked list previous value still know about node you remove, because of next node reference
You can try with the following code:
if (dummy.getData() == e) {
DIntNode temp = dummy.getPrevious();
temp.next = dummy.getNext();
temp = dummy.getNext();
temp.previous = dummy.getPrevious();
return true;
}
This used the previous reference. So the previous node will now have reference to the next node of your dummy node (node to be deleted). And similarly, the next node of dummy node will have reference of previous node of your dummy node. So, the dummy node will loose its connection/link from its doubly link list and that's what we want!
Please try.
Two issues with the code:
When relinking a doubly linked list, where removing B from A - B - C, you need to set the next node for A to be C as well as the previous node for C to be A. With trying to keep you method names:
A.setNext(current.getNext());
C.setNext(current.getPrev());
With your code, if you find an occurrence, you return, which means that no other instances will be removed since you jump out of that method. You will probably need a new boolean removed variable, that is set to false, return true changed to removed = true and return false changed to return removed.
The method exits after the first encounter of 'e'.
If you want to remove all instances of 'e', then you should have something like this:
boolean listChanged = false;
while (dummy != null) {
if (dummy.getData() == e) {
// update list
...
listChanged = true;
}
...
}
return listChanged;
Also, you should not write your code like this:
dummy.getNext().setPrev(...); // throws NPE if next is null
I've got an object of type DocObject that contains an arraylist of DocObjects within it called children, each of which may or not contain children themselves. I'm writing a function for this object called replace() that takes a child to be searched for, and if the DocObject contains that child then the child should be replaced with newObj. I have looked around the site and searched google but nothing I've seen is working. The code below shows what I've tried:
public void replace(DocObject oldObj, DocObject newObj) {
for (DocObject child : children ) {
if (child == oldObj) {
child = newObj;
}
}
}
And this (this causes an overflow exception):
public void replace(DocObject oldObj, DocObject newObj) {
if (children.indexOf(oldObj) != -1)
children.set(children.indexOf(oldObj), newObj);
for (DocObject child : children)
child.replace(oldObj, newObj);
}
This isn't replacing the child, however, and I have checked to see that the if statement is working correctly and its condition met. How can I replace oldObj with newObj?
I would not recommend looping using the for (X x: thingWithXs) construct while manipulating the list. I would recommend using indexOf to search for the desired object and if it cannot be found, recursively calling replace on the children of the object you are looking at.
Note that you'll have to modify your replace method to accept the list of objects as an argument:
public boolean replace(List<E> list, E oldE, E newE) {
if (list == null) {
return false;
}
int index = list.indexOf(oldE);
if (index > 0) {
list.set(index, newE);
return true;
}
for (int i = 0, l = list.size(); i < l; i++) {
List<E> children = list.get(i).children;
if (replace(children, oldE, newE)) {
return true;
}
}
return false;
}
Disclaimer: The above code has not been tested. It should give you an idea as to how it can be done. Essentially what it comes down to is checking if the element you are looking for is in the list, and if not, iterating over the list and checking each set of children.
I have an add method for creating a linked list that is unordered and has a trailer node defined by
ListNode<E> front = new ListNode<E>(null,null);
from what I understand I can keep on adding values to the front of the list BUT since this is a Linked List implementation of a Set and I can't have a duplicate values, I need to check the set (each listnode from front to trailer node) to make sure it does not have the new value I'm trying to add into the list. Here is my add method.
public boolean add(E e) {
ListNode<E> newNode = new ListNode<E>(e, null);
//point to trailer
newNode.next = front.next;
//front now points to newNode
front.next = newNode;
//front->newNode->trailer
objectCount++;
return true;
}
Now, to check the that the newNode is not already in the linked list I need to implement a contains method that checks each element in the list and returns true if it is in the linked list. IF it returns true then I don't execute the add method above and if I don't then I successfully add the value. So, I was thinking something along the lines of:
if(this.contains(newNode))
return false;
else {
newNode.next = front.next;
front.next = newNode;
}
But I don't know how to implement my contains method successfully. Heres what I have:
public boolean contains(Object o) {
ListNode<E> o1 = (ListNode<E>) o;
if (o1.value == front.next.value)
return true;
else
return false;
}
I'm not sure how I can make the method contains, check each node for the Object o and return true if it is in the linked list and false otherwise. So, going forward, is my understanding correct on how I should implement this? And how can I fix my contains method?
Every node knows whats before and whats behind it. Thus:
Go over all previous nodes, until there is noone anymore, check them.
Go over all following nodes, until there is noone anymore, check them.
(Because it sounds like an exercise, without code. But you just have to "translate" the written words into code)
--tb
I need to write a method that starts with a single linked list of integers and a special value called the splitting value. The elements of the list are in no particular order. The method divides the nodes into two linked lists: one containing all the nodes that contain an element less than the splitting value and one that contains all the other nodes. If the original linked list had any repeated integers (i.e., any two or more nodes with the same element in them), then the new linked list that has this element should have the same number of nodes that repeat this element. The method returns two head references - one for each of the linked lists that were created.
I have been spent countless hours trying to get this right and think this is the closest but I have an error while compiling that my copyTail* IntNodes may not be initialized. I also may be completely wrong with my code....
Any help pointing in me in the right direction??
public static IntNode[ ] listSplitLessGreater(IntNode source, int splitter)
{
IntNode copyHeadLess;
IntNode copyTailLess;
IntNode copyHeadGreater;
IntNode copyTailGreater;
IntNode[ ] answer = new IntNode[2];
boolean less = true;
boolean greater = true;
// Handle the special case of the empty list.
if (source == null)
return answer; // The answer has two null references .
//Split list into two lists less and greater/equal than splitter.
while (source.link != null)
{
if (splitter < source.data)
{
if (less)
{
copyHeadLess = new IntNode(source.data, null);
copyTailLess = copyHeadLess;
less=false;
}
else
{
source = source.link;
copyTailLess.addNodeAfter(source.data);
copyTailLess = copyTailLess.link;
}
}
else
{
if (greater)
{
copyHeadGreater = new IntNode(source.data, null);
copyTailGreater = copyHeadGreater;
greater=false;
}
else
{
source = source.link;
copyTailGreater.addNodeAfter(source.data);
copyTailGreater = copyTailGreater.link;
}
}
}
//Return Head References
answer[0] = copyHeadLess;
answer[1] = copyHeadGreater;
return answer;
}
I think you're making it more complicated than it needs to be, by modelling a list just with a single class (IntNode). If you model it as "the list" and "a node in the list" then it's easy to have an empty list. You also don't need to keep track of both the head and the tail - the list can do that. At that point, it's very simple:
Create two empty lists, one for "lower" and one for "not lower"
Iterate over the original list:
Work out which list to add the element to
Add the element
Return both lists (e.g. using an array as you have done)
Note that even without that, you can make your code simpler by just using null to mean "I haven't got this list yet". At the moment your code won't compile, as copyHeadLess etc aren't definitely assigned when they're used. You know that you won't try to use them until they've been assigned, but the compiler doesn't. I'd still recommend the remodelling approach though :)
If source isn't null, but source.link is null (list is only composed of one element) then you never assign to your copyHeadLess, etc, variables. Try initializing them to null or whatever the default is:
IntNode copyHeadLess = null;
IntNode copyTailLess = null;
IntNode copyHeadGreater = null;
IntNode copyTailGreater = null;
IntNode[ ] answer = new IntNode[2];
boolean less = true;
boolean greater = true;
// Handle the special case of the empty list.
if (source == null)
return answer; // The answer has two null references .
//Split list into two lists less and greater/equal than splitter.
while (source.link != null)
{
// what about case where source isn't null but source.link is null?
}
//Return Head References
answer[0] = copyHeadLess; // this may have never been assigned in your original code
answer[1] = copyHeadGreater; // this may have never been assigned in your original code
return answer;
}
This is for homework but please know that I have looked online for help (such as http://www.sethi.org/classes/class_stuff/cis435/others/notes-java/data/collections/lists/simple-linked-list.html) and my textbook but I am still having some issues.
Any help would be appreciated...
Right now I'm trying to just insert values in but nothing is working. Whether it's the first item, whether it's being added as the last one, or somewhere in between.
Node header = null; // First element of list.
Node back = null; // Last element of list.
public void insert(int i, double value){ //insert value before i-th element
Node e = new Node();
e.num = value;
Node curr = header;
for(int x=0;x<i;x++) {
if (i == 1) { //we want to insert as first thing
if (size == 0) { //its the FIRST time we add something
header.next = e;
e.next = back;
break;
} else if (size == 1){
e.next = header.next; //i.e. the second thing in the list
header.next = e;
break;
} else {
e.next = header.next.next; //i.e. the second thing in the list
header.next = e;
break;
}
}
else if (x == (i-1)) {
e.next = curr.next;
curr.next = e;
break;
}
curr = curr.next;
}
size = size+1;
}
Not really sure why it isn't working.
Thanks!
For some reason, people who are still learning to program make things far more complicated then they need to be. I did it when I was learning java, I still do it when I am just getting into a new language, and students that I have marked find new and amazing ways to do it. You have more going on in your insert then there needs to be, for example, a method that inserts a value at a specific index should not check if it's the first item to be inserted (not saying it shouldn't check bounds). Here is the pseudo code of what I would do.
insert(index, value)
if index>size
throw null pointer
traverse to index -1 //lets call this nodeI
create newnode and set value
set newnode.next to nodeI.next
set nodeI.next to newnode
increase size.
Couple of handy hints for you, you should have a function to get an element from the link list, something that returns a node? public node elementAt(int index) for example? use that to traverse the linked list. If you want to append to the Linked list, try this
append(value)
insert(size-1,value)
and if you want to insert at the beginning? same idea
insert(value)
insert(0,value)
In the line e.next = header.next.next what would happen if header.next points to a 'null'? Is it possible to get there?
What are the corner cases you have to deal with and have you taken them all into account?
Can you start with the simplest case first, adding either an element to the front or an element to the back? Then use those functions to implement the insert?
A few suggestions:
implement java.util.List
Think about generics
Read this.
Start with "insert at the end" before you think about "insert at i".
I have tried a simple program, which will be useful for you guys, I am also learning Java, please bear with me for any mistakes, but this program works fine.
I am posting a very simple singly linked list program in Java, which I tried out today.
I hope it will help all.
LinkList.java
class LinkList
{
public static void main(String args[])
{
Node node = new Node(1);
node.addAtLast(2);
node.addAtLast(3);
node.addAtLast(4);
node.addAtLast(5);
node.printList();
}
}
Node.java
class Node
{
private int data;
private Node link;
public Node(int mydata)
{
data = mydata;
link = null;
}
public void printList()
{
System.out.print("|"+data+"|"+"->");
if(link != null)
{
//recursive call
link.printList();
}
else
{
//marking end of list as NULL
System.out.print("|NULL|");
}
}
public void addAtLast(int mydata)
{
if(link == null)
{
link = new Node(mydata);
}
else
{
link.addAtLast(mydata);
}
}
}
OUTPUT :
The below is our output
|1|->|2|->|3|->|4|->|5|->|NULL|