A method for removing an element from a linked list has been implemented:
public void remove(T e) {
Node<T> node = first;
Node<T> prevNode = null;
while(node != null){
if(e.equals(node)){
if(prevNode == null) {
first = node.next;
}
else {
prevNode.next = node.next;
}
size--;
}
else {
prevNode = node;
}
node = node.next;
}
}
How to correctly implement deleting an element by index? Using the capabilities of the remove method.
public void removeByIndex(int i) {
remove(i);
}
Something like this should work:
public void remove(int i) {
if (i >= size || i < 0) {
throw new ArrayIndexOutOfBoundsException();
}
Node<T> remove;
if (i == 0) {
remove = first;
first = first.next;
first.prev = null; // <- For double linked list
} else {
Node<T> node = first;
for (int j = 0; j < i - 1; ++j) {
node = node.next;
}
remove = node.next;
if (i == size - 1) {
node.next = null;
} else {
node.next.next.prev = node; // <- For double linked list
node.next = node.next.next;
}
}
// Clear links from removed Node
remove.next = null;
remove.prev = null; // <- For double linked list
size--;
}
Find the node before position i. Point that node to the "over next" node.
Edit
The original code example was a rough sketch at best. Updated with a more complete version.
Edit #2
Slight improvements:
Clears links from the removed node
Also handles double linked lists
remove(get(i));
This is not the most efficient solution, but a simple one which uses the remove(T) method. You call it with get(i) as the object to be removed - which is the element at the specified index.
Note: This solution has some issues if the list has duplicate values, but in that case you shouldn't use the remove(T) method anyway. If you want it to be safe, iterate to the specified index:
Node<T> node = first;
for(int i=0;i<index;i++){
prevNode=node;
node=node.next;
}
and do this:
node.prev.next=node.next;
node.next.prev=node.prev;
size--;
Of course, this is just a rough implementation. To ensure full compability, you should check if the index is valid and use the unlink(Node) method of LinkedList.
The LinkedList also has an implementation for the remove(int) method:
checkElementIndex(index);
return unlink(node(index));
Related
I'm trying to implement a doubly linked list for a class assignment. I am currently stuck on implementing a method to remove a node at a specified index.
public void remove(int index) {
if (index < 0 || index > count-1) {
throw new ListIndexOutOfBoundsException("The index "+index+" is out of bounds.");
}
if (isEmpty()) {
System.out.println("List is empty");
return;
}
MedicationNode curr = head;
int k = 0;
while(k < index) {
curr = curr.next;
k++;
}
if (curr.prev == null) {
curr.next.prev = null;
}else if(curr.next == null) {
curr = curr.prev;
curr.next = null;
}else{
curr.next.prev = curr.prev;
curr.prev.next = curr.next;
}
count--;
}
the method can remove any specified node in a linked list except index 0. I'm thinking the problem may be with my add method but im not really sure.
In your first if condition -
if (curr.prev == null) {
curr.next.prev = null;
//Make your head of the linked list point to this node
head = curr.next;
}
This is because you are removing the head from the list so the head should point to the head's next node.
I have a doubly linked list, and I want to insert an element at the end of the list recursively. I have a method now that does this without recursion, and it works. I just can't seem to understand how to do it with recursion. Inserting at the end of a singly linked list with recursion is quite easy to understand I think, so I hope that someone can explain how to it do it when the list is doubly linked. Here is my normal insertion method that I want to make recursive:
public void insert(T element) {
Node in = new Node(element);
if (in == null) {
first = in;
} else {
Node tmp = first;
while (tmp.next != null) {
tmp = tmp.next;
}
tmp.next = in;
in.prec = tmp;
}
}
The idea is just to re-write the while loop with a function call:
public void insert(T element) {
insert(element, first); // initialization
}
private void insert(T e, Node n) {
if(n == null) { // if the list is empty
first = new Node(e);
} else if(n.next == null) { // same condition as in the while loop
None newNode = new Node(e);
n.next = newNode;
newNode.prec = n;
} else {
insert(e, n.next); // looping
}
}
I've been working on this lab assignment for a few hours and can't understand why this code is not working. The question is to add the method int removeEvery(T item) that removes all occurrences of item and returns the number of removed items to a link list class that implements a link list interface.
This is my code: It removes some occurrences of the item, but not all of them.
public int removeEvery(T item){
int index = 0;
Node currentNode = firstNode;
for(int i = 1; i <= numberOfEntries; i++)
{
System.out.println(currentNode.getData());
if (item.equals(currentNode.getData())){
index++;
remove(i);}
else{
currentNode = currentNode.getNextNode();}
}
if(index != 0)
return index;
return -1;
}
Here is the remove method that was included in the LinkList class:
public T remove(int givenPosition)
{
T result = null; // return value
if ((givenPosition >= 1) && (givenPosition <= numberOfEntries))
{
assert !isEmpty();
if (givenPosition == 1) // case 1: remove first entry
{
result = firstNode.getData(); // save entry to be removed
firstNode = firstNode.getNextNode();
if (numberOfEntries == 1)
lastNode = null; // solitary entry was removed
}
else // case 2: givenPosition > 1
{
Node nodeBefore = getNodeAt(givenPosition - 1);
Node nodeToRemove = nodeBefore.getNextNode();
Node nodeAfter = nodeToRemove.getNextNode();
nodeBefore.setNextNode(nodeAfter); // disconnect the node to be removed
result = nodeToRemove.getData(); // save entry to be removed
if (givenPosition == numberOfEntries)
lastNode = nodeBefore; // last node was removed
} // end if
numberOfEntries--;
} // end if
return result; // return removed entry, or
// null if operation fails
} // end remove
There is something special with your linked list, you can access next element with current.getNextNode but you delete using the element index. You should look in the rest of your implementation how this index is managed. Does the first element have index 0 or 1 (you start your loop with 1). What happens to the indexes of all elements when you remove one. Do the elements know their index ?
You could use something like
int deletedNodes = 0;
int currentIndex = 0; // check if 1 or 0
currentNode = fist;
while(currentNode != null){ // I guess lastNode.getNextNode() is null
if(//should remove){
remove(currentIndex);
deletedNodes++
// probably no need to change the index as all element should have been shifted back one index
} else {
currentIndex++; // index changes only if no node was deleted
}
currentNode = currentNode.getNextNode(); // will work even if it was deleted
}
return deletedNodes;
I think the problem you have comes from remove(i).
When you remove the i-th element, the i+1-th element becomes the i-th and so on: every element is shifted. Therefore if you need to remove 2 elements in your list that are at index j and j+1, removing the j-th element calling remove(j) will shift the j+1-th element at the index j. Hence removing that second element requires calling remove(j) again, and not remove(j+1).
So you need to decrement i after removing.
Since your remove method actually decrements numberOfEntries, the condition on your while loop is properly updated. So all you need to do is replace
if (item.equals(currentNode.getData())) {
index++;
remove(i);
}
else {
currentNode = currentNode.getNextNode();
}
by
if (item.equals(currentNode.getData())) {
index++;
remove(i--);
}
// update the current node, whether removing it or not
currentNode = currentNode.getNextNode();
Iterator.remove()
This problem you are describing shows the usefulness of Iterator.remove() when using data structures from the JDK for going through an iterable collection and removing elements as you go through it.
After removing a node, as #Vakimshaar suggested, you need to decrement the i because the node at this index has been removed and there is a new node at the same index. In addition to that, you also need to update the currentNode reference as it would still be pointing to the node you've just removed, but it should really be pointing to the new node that has moved to this index.
So in the if (item.equals(currentNode.getData())){ block you need to do the following:
Node nextNode = currentNode.getNextNode();
index++;
remove(i--);
currentNode = nextNode;
With this, your code should correctly remove all occurrences.
Here is a Java Code to delete all occurrences of an item from a linked list :
public class LinkedList{
Node head;
class Node{
int data;
Node next;
Node(int d){data =d; next = null;}
}
public void push(int new_data){
Node new_node = new Node(new_data);
new_node.next = head;
head = new_node;
}
public void insertAfter(Node givenNode, int new_data){
if(givenNode == null)
System.out.println("Given node cannot be empty");
Node new_node = new Node(new_data);
new_node.next = givenNode.next;
givenNode.next = new_node;
}
public void append(int new_data){
Node new_node = new Node(new_data);
if(head == null)
head = new_node;
else{
Node last = head;
while(last.next != null)
last = last.next;
last.next = new_node;
}
}
public void printList(){
Node temp = head;
while(temp != null){
System.out.println(temp.data + " ");
temp = temp.next;
}
}
void deleteNode(int key){
// Store head node
Node temp = head, prev=null;
// If head node itself holds the key or multiple occurrences of key
while(temp != null && temp.data == key){
head = temp.next;
temp = head;
}
// Delete occurrences other than head
while(temp != null){
// Search for the key to be deleted, keep track of the
// previous node as we need to change 'prev.next'
while(temp != null && temp.data != key){
prev = temp;
temp = temp.next;
}
// If key was not present in linked list
if(temp == null) return;
// Unlink the node from linked list
prev.next = temp.next;
//Update Temp for next iteration of outer loop
temp = prev.next;
}
}
public static void main(String[] args){
LinkedList llist = new LinkedList();
llist.push(6);
llist.append(7);
llist.append(7);
llist.append(7);
llist.append(9);
llist.push(10);
llist.deleteNode(7);
llist.printList();
}
}
Output :
10
6
9
I am implementing my own linked list in Java. The node class merely has a string field called "name" and a node called "link". Right now I have a test driver class that only inserts several names sequentially. Now, I am trying to write a sorting method to order the nodes alphabetically, but am having a bit of trouble with it. I found this pseudocode of a bubblesort from someone else's post and tried to implement it, but it doesn't fully sort the entries. I'm not really quite sure why. Any suggestions are appreciated!
private void sort()
{
//Enter loop only if there are elements in list
boolean swapped = (head != null);
// Only continue loop if a swap is made
while (swapped)
{
swapped = false;
// Maintain pointers
Node curr = head;
Node next = curr.link;
Node prev = null;
// Cannot swap last element with its next
while (next != null)
{
// swap if items in wrong order
if (curr.name.compareTo(next.name) < 0)
{
// notify loop to do one more pass
swapped = true;
// swap elements (swapping head in special case
if (curr == head)
{
head = next;
Node temp = next.link;
next.link = curr;
curr.link = temp;
curr = head;
}
else
{
prev.link = curr.link;
curr.link = next.link;
next.link = curr;
curr = next;
}
}
// move to next element
prev = curr;
curr = curr.link;
next = curr.link;
}
}
}
I spent some minutes eyeballing your code for errors but found none.
I'd say until someone smarter or more hard working comes along you should try debugging this on your own. If you have an IDE like Eclipse you can single-step through the code while watching the variables' values; if not, you can insert print statements in a few places and hand-check what you see with what you expected.
UPDATE I
I copied your code and tested it. Apart from the fact that it sorts in descending order (which may not be what you intended) it worked perfectly for a sample of 0, 1 and 10 random nodes. So where's the problem?
UPDATE II
Still guessing what could be meant by "it doesn't fully sort the entries." It's possible that you're expecting lexicographic sorting (i.e. 'a' before 'B'), and that's not coming out as planned for words with mixed upper/lower case. The solution in this case is to use the String method compareToIgnoreCase(String str).
This may not be the solution you're looking for, but it's nice and simple. Maybe you're lazy like I am.
Since your nodes contain only a single item of data, you don't really need to re-shuffle your nodes; you could simply exchange the values on the nodes while leaving the list's structure itself undisturbed.
That way, you're free to implement Bubble Sort quite simply.
you should use the sorting procedures supplied by the language.
try this tutorial.
Basically, you need your element class to implement java.lang.Comparable, in which you will just delegate to obj.name.compareTo(other.name)
you can then use Collections.sort(yourCollection)
alternatively you can create a java.util.Comparator that knows how to compare your objects
To obtain good performance you can use Merge Sort.
Its time complexity is O(n*log(n)) and can be implemented without memory overhead for lists.
Bubble sort is not good sorting approach. You can read the What is a bubble sort good for? for details.
This may be a little too late. I would build the list by inserting everything in order to begin with because sorting a linked list is not fun.
I'm positive your teacher or professor doesn't want you using java's native library. However that being said, there is no real fast way to resort this list.
You could read all the nodes in the order that they are in and store them into an array. Sort the array and then relink the nodes back up. I think the Big-Oh complexity of this would be O(n^2) so in reality a bubble sort with a linked list is sufficient
I have done merge sort on the singly linked list and below is the code.
public class SortLinkedList {
public static Node sortLinkedList(Node node) {
if (node == null || node.next == null) {
return node;
}
Node fast = node;
Node mid = node;
Node midPrev = node;
while (fast != null && fast.next != null) {
fast = fast.next.next;
midPrev = mid;
mid = mid.next;
}
midPrev.next = null;
Node node1 = sortLinkedList(node);
Node node2 = sortLinkedList(mid);
Node result = mergeTwoSortedLinkedLists(node1, node2);
return result;
}
public static Node mergeTwoSortedLinkedLists(Node node1, Node node2) {
if (null == node1 && node2 != null) {
return node2;
} else if (null == node2 && node1 != null) {
return node1;
} else if (null == node1 && null == node2) {
return null;
} else {
Node result = node1.data <= node2.data ? node1 : node2;
Node prev1 = null;
while (node1 != null && node2 != null) {
if (node1.data <= node2.data) {
prev1 = node1;
node1 = node1.next;
} else {
Node next2 = node2.next;
node2.next = node1;
if (prev1 != null) {
prev1.next = node2;
}
node1 = node2;
node2 = next2;
}
}
if (node1 == null && node2 != null) {
prev1.next = node2;
}
return result;
}
}
public static void traverseNode(Node node) {
while (node != null) {
System.out.print(node + " ");
node = node.next;
}
System.out.println();
}
public static void main(String[] args) {
MyLinkedList ll1 = new MyLinkedList();
ll1.insertAtEnd(10);
ll1.insertAtEnd(2);
ll1.insertAtEnd(20);
ll1.insertAtEnd(4);
ll1.insertAtEnd(9);
ll1.insertAtEnd(7);
ll1.insertAtEnd(15);
ll1.insertAtEnd(-3);
System.out.print("list: ");
ll1.traverse();
System.out.println();
traverseNode(sortLinkedList(ll1.start));
}
}
The Node class:
public class Node {
int data;
Node next;
public Node() {
data = 0;
next = null;
}
public Node(int data) {
this.data = data;
}
public int getData() {
return this.data;
}
public Node getNext() {
return this.next;
}
public void setData(int data) {
this.data = data;
}
public void setNext(Node next) {
this.next = next;
}
#Override
public String toString() {
return "[ " + data + " ]";
}
}
The MyLinkedList class:
public class MyLinkedList {
Node start;
public void insertAtEnd(int data) {
Node newNode = new Node(data);
if (start == null) {
start = newNode;
return;
}
Node traverse = start;
while (traverse.getNext() != null) {
traverse = traverse.getNext();
}
traverse.setNext(newNode);
}
public void traverse() {
if (start == null)
System.out.println("List is empty");
else {
Node tempNode = start;
do {
System.out.print(tempNode.getData() + " ");
tempNode = tempNode.getNext();
} while (tempNode != null);
System.out.println();
}
}
}
I am trying to run a test for a getPrevious() method in JUnit.
public void getPrev(){
for (int i = 0; i < 1000; i++) {
list.add(i);
}
list.reset();
for (int i = 999; i >= 0; i--) {
int info = list.getPrevious();
assertEquals(i, info);
}
}
Every other method seem to work, except for this one. After running some printing tests, I realized that the reset method
...reset(){
if (list != null)
location = list.getPrev();//returns the last node's previous node -- head node.
}
(which should make the location node the head node) was not returning the correct information. It returned null instead of the head node.
Thus, my logic led me to believe that the add method was not working as it should be. And this is also my question. I have been trying multiple things to see where the error is but nothing seem to work. I am looking to see if anyone can help spot the logic error in this code.
public void add(Object elem) {
LLNode<T> newNode = new LLNode(elem);
if(list == null){
tail = list = newNode;
}
list.setPrev(newNode);
newNode.setNext(list);
newNode.setPrev(tail);
tail.setNext(newNode);
list = newNode;
size++;
}
Try This
public int add(Object elem) {
Node node = new Node(elem);
if (head == null) {
head = node;
} else {
tail.setNext(node);
node.setPrevious(tail);
}
tail = node;
return value;
}