The effect of remove(key) --- removing the (first) item from a linked list that contains a item==key:
|
Note: the technique for step (1) is similar to that in the removeLast() algorithm !!!
|
We stop when current.item is equal to the key:
|
The algorithm is usually written as:
|
|
Let's implement the remove(key) method:
// Delete the node that contains key
public void remove(T key)
{ // General case (take care of edge cases later)
// Find the previous node of the node that contains key
Node<T> current = first;
Node<T> previous = first;
(1) Find the predecesor node of the node containing item==key
while( current!=null && !current.item.equals(key) )
{
previous = current;
current = current.next;
}
if( current == null )
{ // key not found
throw new NoSuchElementException();
}
(2) Unlink the targeted node from its predecesor node
}
|
(1) Find the predecesor node of the node containing item==key:
// Delete the node that contains key
public void remove(T key)
{ // General case (take care of edge cases later)
// Find the previous node of the node that contains key
Node<T> current = first; // Initialize
Node<T> previous = first;
while( current != null && !current.item.equals(key) )
{
previous = current; // Keep track of the previous node
current = current.next; // Moev to next node
}
// previous points to the predecessor node of current
// current points to the node containing the given key
// or current == null: not found
(2) Unlink the targeted node from its predecesor node
}
|
(2a) If key is not found, we report an error (throw an exception):
// Delete the node that contains key
public void remove(T key)
{ // General case (take care of edge cases later)
// Find the previous node of the node that contains key
Node<T> current = first; // Initialize
Node<T> previous = first;
while( current != null && !current.item.equals(key) )
{
previous = current; // Keep track of the previous node
current = current.next; // Moev to next node
}
if( current == null )
{ key not found
throw new NoSuchElementException();
}
(2) Unlink the targeted node from its predecesor node
}
|
(2b) If the key was found in the linked list, we unlink the node from its predecessor node:
// Delete the node that contains key
public void remove(T key)
{ // General case (take care of edge cases later)
// Find the previous node of the node that contains key
Node<T> current = first; // Initialize
Node<T> previous = first;
while( current != null && !current.item.equals(key) )
{
previous = current; // Keep track of the previous node
current = current.next; // Moev to next node
}
if( current == null )
{ key not found
throw new NoSuchElementException();
}
previous.next = current.next; // Unlink the current node from list
}
|
There are 2 edge cases: (1) the empty list and (2) the first node contains the key (updates first)
// Delete the node that contains key
public void remove(T key)
{
if ( edge case 1 )
{
...
}
else if ( edge case 2 )
{
... must update first
}
else
{
// General case updates previous.next
...
Omitted for brevity
previous.next = current.next; // Unlink the current node from list
}
}
|
Detect and handle edge case 1: the empty list
// Delete the node that contains key
public void remove(T key)
{
if ( first == null )
{
throw new NoSuchElementException();
}
else if ( edge case 2 )
{
... must update first
}
else
{
// General case updates previous.next
...
Omitted for brevity
previous.next = current.next; // Unlink the current node from list
}
}
|
Detecting the edge case 2: the first node contains the given key
// Delete the node that contains key
public void remove(T key)
{
if ( first == null )
{
throw new NoSuchElementException();
}
else if ( first.item.equals(key) )
{
... must update first
}
else
{
// General case updates previous.next
...
Omitted for brevity
previous.next = current.next; // Unlink the current node from list
}
}
|
Handling the edge case 2: make the 2nd node into the first node of the list
// Delete the node that contains key
public void remove(T key)
{
if ( first == null )
{
throw new NoSuchElementException();
}
else if ( first.item.equals(key) )
{
first = first.next; // The 2nd node is now the new 1st node
}
else
{
// General case updates previous.next
...
Omitted for brevity
previous.next = current.next; // Unlink the current node from list
}
}
|
public static void main(String[] args)
{
System.out.println("Demo getFirst(), getLast(), get(pos)\n");
GenericLinkedList<Integer> intList = new GenericLinkedList<Integer>();
intList.addFirst(89);
intList.addFirst(78);
intList.addFirst(34);
intList.addFirst(23);
intList.addFirst(12);
System.out.println(intList); // 12 -> 23 -> 34 -> 78 -> 89
intList.remove(34);
System.out.println("After remove(34):");
System.out.println(intList);
intList.remove(89);
System.out.println("After remove(89):");
System.out.println(intList);
intList.remove(12);
System.out.println("After remove(12):");
System.out.println(intList);
System.out.println("remove(99): (not in list)");
intList.remove(12);
}
|
DEMO: demo/11-linked-list/05-remove-item/Demo.java + GenericLinkedList.java