How do you implement a class SequenceDLList that defines a Sequence ADT as a double linked list?
I've been trying to modify the below code with single linked list....but not getting there.
This is supposed to work..
class SequenceListException extends Exception {
SequenceListException() {
super();
}
SequenceListException(String s) {
super(s);
}
}
*/
public class SequenceList
{
/**
* Member class Node encapsulates the nodes of the linked list in
* which the stack is stored. Each node contains a data item and a
* reference to another node - the next in the linked list.
*/
protected class Node
{
public Node(Object o)
{
this(o, null);
}
public Node(Object o, Node n)
{
datum = o;
next = n;
}
//The Node data structure consists of two object references.
//One for the datum contained in the node and the other for
//the next node in the list.
protected Object datum;
protected Node next;
}
//We use object references to the head and tail of the list (the head
//and tail of the sequence, respectively).
private Node listHead;
private Node listTail;
//Only require a single constructor, which sets both object
//references to null.
/**
* Constructs an empty sequence object.
*/
public SequenceList()
{
listHead = null;
listTail = null;
}
/**
* Adds a new item at the start of the sequence.
*/
public void insertFirst(Object o)
{
//There is a special case when the sequence is empty.
//Then the both the head and tail pointers needs to be
//initialised to reference the new node.
if(listHead == null) {
listHead = new Node(o, listHead);
listTail = listHead;
}
//In the general case, we simply add a new node at the start
//of the list via the head pointer.
else {
listHead = new Node(o, listHead);
}
}
/**
* Adds a new item at the end of the sequence.
*/
public void insertLast(Object o)
{
//There is a special case when the sequence is empty.
//Then the both the head and tail pointers needs to be
//initialised to reference the new node.
if(listHead == null) {
listHead = new Node(o, listHead);
listTail = listHead;
}
//In the general case, we simply add a new node to the end
//of the list via the tail pointer.
else {
listTail.next = new Node(o, listTail.next);
listTail = listTail.next;
}
}
/**
* Adds a new item at a specified position in the sequence.
*/
public void insert(Object o, int index) throws SequenceListException
{
//Check the index is positive.
if(index < 0) {
throw new SequenceListException("Indexed Element out of Range");
}
//There is a special case when the sequence is empty.
//Then the both the head and tail pointers needs to be
//initialised to reference the new node.
if(listHead == null) {
if(index == 0) {
listHead = new Node(o, listHead);
listTail = listHead;
}
else throw new SequenceListException("Indexed element is out of range");
}
//There is another special case for insertion at the head of
//the sequence.
else if(index == 0) {
listHead = new Node(o, listHead);
}
//In the general case, we need to chain down the linked list
//from the head until we find the location for the new
//list node. If we reach the end of the list before finding
//the specified location, we know that the given index was out
//of range and throw an exception.
else {
Node nodePointer = listHead;
int i = 1;
while(i < index) {
nodePointer = nodePointer.next;
i += 1;
if(nodePointer == null) {
throw new SequenceListException("Indexed Element out of Range");
}
}
//Now we've found the node before the position of the
//new one, so we 'hook in' the new Node.
nodePointer.next = new Node(o, nodePointer.next);
//Finally we need to check that the tail pointer is
//correct. Another special case occurs if the new
//node was inserted at the end, in which case, we need
//to update the tail pointer.
if(nodePointer == listTail) {
listTail = listTail.next;
}
}
}
/**
* Removes the item at the start of the sequence.
*/
public void deleteFirst() throws SequenceListException
{
//Check there is something in the sequence to delete.
if(listHead == null) {
throw new SequenceListException("Sequence Underflow");
}
//There is a special case when there is just one item in the
//sequence. Both pointers then need to be reset to null.
if(listHead.next == null) {
listHead = null;
listTail = null;
}
//In the general case, we just unlink the first node of the
//list.
else {
listHead = listHead.next;
}
}
/**
* Removes the item at the end of the sequence.
*/
public void deleteLast() throws SequenceListException
{
//Check there is something in the sequence to delete.
if(listHead == null) {
throw new SequenceListException("Sequence Underflow");
}
//There is a special case when there is just one item in the
//sequence. Both pointers then need to be reset to null.
if(listHead.next == null) {
listHead = null;
listTail = null;
}
//In the general case, we need to chain all the way down the
//list in order to reset the link of the second to last
//element to null.
else {
Node nodePointer = listHead;
while(nodePointer.next != listTail) {
nodePointer = nodePointer.next;
}
//Unlink the last node and reset the tail pointer.
nodePointer.next = null;
listTail = nodePointer;
}
}
/**
* Removes the item at the specified position in the sequence.
*/
public void delete(int index) throws SequenceListException
{
//Check there is something in the sequence to delete.
if(listHead == null) {
throw new SequenceListException("Sequence Underflow");
}
//Check the index is positive.
if(index < 0) {
throw new SequenceListException("Indexed Element out of Range");
}
//There is a special case when there is just one item in the
//sequence. Both pointers then need to be reset to null.
if(listHead.next == null) {
if(index == 0) {
listHead = null;
listTail = null;
} else throw new SequenceListException("Indexed element is out of range.");
}
//There is also a special case when the first element has to
//be removed.
else if(index == 0) {
deleteFirst();
}
//In the general case, we need to chain down the list to find
//the node in the indexed position.
else {
Node nodePointer = listHead;
int i = 1;
while(i < index) {
nodePointer = nodePointer.next;
i += 1;
if (nodePointer.next == null) {
throw new SequenceListException("Indexed Element out of Range");
}
}
//Unlink the node and reset the tail pointer if that
//node was the last one.
if(nodePointer.next == listTail) {
listTail = nodePointer;
}
nodePointer.next = nodePointer.next.next;
}
}
/**
* Returns the item at the start of the sequence.
*/
public Object first() throws SequenceListException
{
if(listHead != null) {
return listHead.datum;
}
else {
throw new SequenceListException("Indexed Element out of Range");
}
}
/**
* Returns the item at the end of the sequence.
*/
public Object last() throws SequenceListException
{
if(listTail != null) {
return listTail.datum;
}
else {
throw new SequenceListException("Indexed Element out of Range");
}
}
/**
* Returns the item at the specified position in the sequence.
*/
public Object element(int index) throws SequenceListException
{
//Check the index is positive.
if(index < 0) {
throw new SequenceListException("Indexed Element out of Range");
}
//We need to chain down the list until we reach the indexed
//position
Node nodePointer = listHead;
int i = 0;
while (i < index) {
if(nodePointer.next == null) {
throw new SequenceListException("Indexed Element out of Range");
}
else {
nodePointer = nodePointer.next;
i += 1;
}
}
return nodePointer.datum;
}
/**
* Tests whether there are any items in the sequence.
*/
public boolean empty()
{
return (listHead == null);
}
/**
* Returns the number of items in the sequence.
*/
public int size()
{
//Chain down the list counting the elements
Node nodePointer = listHead;
int size = 0;
while(nodePointer != null) {
size += 1;
nodePointer = nodePointer.next;
}
return size;
}
/**
* Empties the sequence.
*/
public void clear()
{
listHead = null;
listTail = null;
}
}
As others mentioned already, each node has to have a reference to it's next and previous neighbor in the list.
Basically, the whole solution does not look that different from your example. You have to take care, that wherever you add or remove a node, you need to adjust the adjacent nodes' references accordingly.
The only method which is a lot different is deleteLast. Here you don't need to traverse through the whole list to find the penultimate node. You can just use the 'prev'-reference of the last node instead.
I fear that I just did your homework, but here is the complete example anyway. Please be advised that I didn't really test that code much at all:
class SequenceListException extends Exception {
SequenceListException() {
super();
}
SequenceListException(String s) {
super(s);
}
}
public class SequenceList {
/**
* Member class Node encapsulates the nodes of the linked list in which the
* stack is stored. Each node contains a data item and a reference to
* another node - the next in the linked list.
*/
protected class Node {
public Node(Object o) {
this(o, null, null);
}
public Node(Object o, Node p, Node n) {
datum = o;
prev = p;
next = n;
}
// The Node data structure consists of three object references.
// One for the datum contained in the node and two for
// the next and previous node in the list.
protected Object datum;
protected Node next;
protected Node prev;
}
// We use object references to the head and tail of the list (the head
// and tail of the sequence, respectively).
private Node listHead;
private Node listTail;
// Only require a single constructor, which sets both object
// references to null.
/**
* Constructs an empty sequence object.
*/
public SequenceList() {
listHead = null;
listTail = null;
}
/**
* Adds a new item at the start of the sequence.
*/
public void insertFirst(Object o) {
// There is a special case when the sequence is empty.
// Then the both the head and tail pointers needs to be
// initialised to reference the new node.
if (listHead == null) {
listHead = new Node(o);
listTail = listHead;
}
// In the general case, we simply add a new node at the start
// of the list via the head pointer.
else {
listHead.prev = new Node(o, null, listHead);
listHead = listHead.prev;
}
}
/**
* Adds a new item at the end of the sequence.
*/
public void insertLast(Object o) {
// There is a special case when the sequence is empty.
// Then the both the head and tail pointers needs to be
// initialised to reference the new node.
if (listHead == null) {
listHead = new Node(o);
listTail = listHead;
}
// In the general case, we simply add a new node to the end
// of the list via the tail pointer.
else {
listTail.next = new Node(o, listTail, null);
listTail = listTail.next;
}
}
/**
* Adds a new item at a specified position in the sequence.
*/
public void insert(Object o, int index) throws SequenceListException {
// Check the index is positive.
if (index < 0) {
throw new SequenceListException("Indexed Element out of Range");
}
// There is a special case when the sequence is empty.
// Then the both the head and tail pointers needs to be
// initialised to reference the new node.
if (listHead == null) {
if (index == 0) {
listHead = new Node(o);
listTail = listHead;
} else {
throw new SequenceListException("Indexed element is out of range");
}
return;
}
// There is another special case for insertion at the head of
// the sequence.
if (index == 0) {
insertFirst(o);
return;
}
// In the general case, we need to chain down the linked list
// from the head until we find the location for the new
// list node. If we reach the end of the list before finding
// the specified location, we know that the given index was out
// of range and throw an exception.
Node nodePointer = listHead;
int i = 1;
while (i < index) {
nodePointer = nodePointer.next;
i += 1;
if (nodePointer == null) {
throw new SequenceListException("Indexed Element out of Range");
}
}
// Now we've found the node before the position of the
// new one, so we 'hook in' the new Node.
Node newNode = new Node(o, nodePointer, nodePointer.next);
if (nodePointer.next != null) {
nodePointer.next.prev = newNode;
}
nodePointer.next = newNode;
// Finally we need to check that the tail pointer is
// correct. Another special case occurs if the new
// node was inserted at the end, in which case, we need
// to update the tail pointer.
if (nodePointer == listTail) {
listTail = newNode;
}
}
/**
* Removes the item at the start of the sequence.
*/
public void deleteFirst() throws SequenceListException {
// Check there is something in the sequence to delete.
if (listHead == null) {
throw new SequenceListException("Sequence Underflow");
}
// There is a special case when there is just one item in the
// sequence. Both pointers then need to be reset to null.
if (listHead.next == null) {
listHead = null;
listTail = null;
return;
}
// In the general case, we just unlink the first node of the
// list.
listHead = listHead.next;
listHead.prev = null;
}
/**
* Removes the item at the end of the sequence.
*/
public void deleteLast() throws SequenceListException {
// Check there is something in the sequence to delete.
if (listHead == null) {
throw new SequenceListException("Sequence Underflow");
}
// There is a special case when there is just one item in the
// sequence. Both pointers then need to be reset to null.
if (listHead.next == null) {
listHead = null;
listTail = null;
return;
}
// In the general case, we just unlink the last node of the
// list.
listTail = listTail.prev;
listTail.next = null;
}
/**
* Removes the item at the specified position in the sequence.
*/
public void delete(int index) throws SequenceListException {
// Check there is something in the sequence to delete.
if (listHead == null) {
throw new SequenceListException("Sequence Underflow");
}
// Check the index is positive.
if (index < 0) {
throw new SequenceListException("Indexed Element out of Range");
}
// There is a special case when there is just one item in the
// sequence. Both pointers then need to be reset to null.
if (listHead.next == null) {
if (index == 0) {
listHead = null;
listTail = null;
} else {
throw new SequenceListException("Indexed element is out of range.");
}
return;
}
// There is also a special case when the first element has to
// be removed.
if (index == 0) {
deleteFirst();
return;
}
// In the general case, we need to chain down the list to find
// the node in the indexed position.
Node nodePointer = listHead;
int i = 1;
while (i < index) {
nodePointer = nodePointer.next;
i += 1;
if (nodePointer.next == null) {
throw new SequenceListException("Indexed Element out of Range");
}
}
// Unlink the node and reset the tail pointer if that
// node was the last one.
if (nodePointer.next == listTail) {
listTail = nodePointer;
}
// Change reference of node after the node which is removed.
if (nodePointer.next.next != null) {
nodePointer.next.next.prev = nodePointer;
}
// Change reference of node before the node which is removed.
nodePointer.next = nodePointer.next.next;
}
/**
* Returns the item at the start of the sequence.
*/
public Object first() throws SequenceListException {
if (listHead != null) {
return listHead.datum;
} else {
throw new SequenceListException("Indexed Element out of Range");
}
}
/**
* Returns the item at the end of the sequence.
*/
public Object last() throws SequenceListException {
if (listTail != null) {
return listTail.datum;
} else {
throw new SequenceListException("Indexed Element out of Range");
}
}
/**
* Returns the item at the specified position in the sequence.
*/
public Object element(int index) throws SequenceListException {
// Check the index is positive.
if (index < 0) {
throw new SequenceListException("Indexed Element out of Range");
}
// We need to chain down the list until we reach the indexed
// position
Node nodePointer = listHead;
int i = 0;
while (i < index) {
if (nodePointer.next == null) {
throw new SequenceListException("Indexed Element out of Range");
} else {
nodePointer = nodePointer.next;
i += 1;
}
}
return nodePointer.datum;
}
/**
* Tests whether there are any items in the sequence.
*/
public boolean empty() {
return (listHead == null);
}
/**
* Returns the number of items in the sequence.
*/
public int size() {
//Chain down the list counting the elements
Node nodePointer = listHead;
int size = 0;
while (nodePointer != null) {
size += 1;
nodePointer = nodePointer.next;
}
return size;
}
/**
* Empties the sequence.
*/
public void clear() {
listHead = null;
listTail = null;
}
public Node lastNode() {
return listTail;
}
public Node firstNode() {
return listHead;
}
}
In a doubly linked list each Node points to the next Node and to the previous one.
so it would be something like this. So i will give you a hint. Your node should have a Node next and Node previous
________ _______
| | | |
| |------>| |
| |<------| |
| | | |
|_______| |______|
You construct Nodes with an object and the next Node. To make this a doubly-linked list, you need to store a previous Node too:
private class DLNode<T> {
private final T datum;
private DLNode<T> next;
private DLNode<T> previous;
private DLNode(final T datum) { this.datum = datum; }
// Manipulate next and previous directly instead of setting them in constructors.
}
public DLNode<T> insertAfter(DLNode<T> node, T datum) {
final DLNode<T> inserted = new DLNode<T>(datum);
final DLNode<T> currentNext = node.next;
inserted.next = currentNext;
inserted.previous = node;
currentNext.previous = inserted;
node.next = inserted;
return inserted;
Related
package linkedlists;
public class SinglyLinkedList<E> implements Cloneable {
//---------------- nested Node class ----------------
/**
* Node of a singly linked list, which stores a reference to its
* element and to the subsequent node in the list (or null if this
* is the last node).
*/
private static class Node<E> {
/** The element stored at this node */
private E element; // reference to the element stored at this node
/** A reference to the subsequent node in the list */
private Node<E> next; // reference to the subsequent node in the list
/**
* Creates a node with the given element and next node.
*
* #param e the element to be stored
* #param n reference to a node that should follow the new node
*/
public Node(E e, Node<E> n) {
element = e;
next = n;
}
// Accessor methods
/**
* Returns the element stored at the node.
* #return the element stored at the node
*/
public E getElement() { return element; }
/**
* Returns the node that follows this one (or null if no such node).
* #return the following node
*/
public Node<E> getNext() { return next; }
// Modifier methods
/**
* Sets the node's next reference to point to Node n.
* #param n the node that should follow this one
*/
public void setNext(Node<E> n) { next = n; }
} //----------- end of nested Node class -----------
// instance variables of the SinglyLinkedList
/** The head node of the list */
private Node<E> head = null; // head node of the list (or null if empty)
/** The last node of the list */
private Node<E> tail = null; // last node of the list (or null if empty)
/** Number of nodes in the list */
private int size = 0; // number of nodes in the list
/** Constructs an initially empty list. */
public SinglyLinkedList() { } // constructs an initially empty list
// access methods
/**
* Returns the number of elements in the linked list.
* #return number of elements in the linked list
*/
public int size() { return size; }
/**
* Tests whether the linked list is empty.
* #return true if the linked list is empty, false otherwise
*/
public boolean isEmpty() { return size == 0; }
/**
* Returns (but does not remove) the first element of the list
* #return element at the front of the list (or null if empty)
*/
public E first() { // returns (but does not remove) the first element
if (isEmpty()) return null;
return head.getElement();
}
/**
* Returns (but does not remove) the last element of the list.
* #return element at the end of the list (or null if empty)
*/
public E last() { // returns (but does not remove) the last element
if (isEmpty()) return null;
return tail.getElement();
}
// update methods
/**
* Adds an element to the front of the list.
* #param e the new element to add
*/
public void addFirst(E e) { // adds element e to the front of the list
head = new Node<>(e, head); // create and link a new node
if (size == 0)
tail = head; // special case: new node becomes tail also
size++;
}
/**
* Adds an element to the end of the list.
* #param e the new element to add
*/
public void addLast(E e) { // adds element e to the end of the list
Node<E> newest = new Node<>(e, null); // node will eventually be the tail
if (isEmpty())
head = newest; // special case: previously empty list
else
tail.setNext(newest); // new node after existing tail
tail = newest; // new node becomes the tail
size++;
}
/**
* Removes and returns the first element of the list.
* #return the removed element (or null if empty)
*/
public E removeFirst() { // removes and returns the first element
if (isEmpty()) return null; // nothing to remove
E answer = head.getElement();
head = head.getNext(); // will become null if list had only one node
size--;
if (size == 0)
tail = null; // special case as list is now empty
return answer;
}
#SuppressWarnings({"unchecked"})
public boolean equals(Object o) {
if (o == null) return false;
if (getClass() != o.getClass()) return false;
SinglyLinkedList other = (SinglyLinkedList) o; // use nonparameterized type
if (size != other.size) return false;
Node walkA = head; // traverse the primary list
Node walkB = other.head; // traverse the secondary list
while (walkA != null) {
if (!walkA.getElement().equals(walkB.getElement())) return false; //mismatch
walkA = walkA.getNext();
walkB = walkB.getNext();
}
return true; // if we reach this, everything matched successfully
}
#SuppressWarnings({"unchecked"})
public SinglyLinkedList<E> clone() throws CloneNotSupportedException {
// always use inherited Object.clone() to create the initial copy
SinglyLinkedList<E> other = (SinglyLinkedList<E>) super.clone(); // safe cast
if (size > 0) { // we need independent chain of nodes
other.head = new Node<>(head.getElement(), null);
Node<E> walk = head.getNext(); // walk through remainder of original list
Node<E> otherTail = other.head; // remember most recently created node
while (walk != null) { // make a new node storing same element
Node<E> newest = new Node<>(walk.getElement(), null);
otherTail.setNext(newest); // link previous node to this one
otherTail = newest;
walk = walk.getNext();
}
}
return other;
}
public int hashCode() {
int h = 0;
for (Node walk=head; walk != null; walk = walk.getNext()) {
h ^= walk.getElement().hashCode(); // bitwise exclusive-or with element's code
h = (h << 5) | (h >>> 27); // 5-bit cyclic shift of composite code
}
return h;
}
/**
* Produces a string representation of the contents of the list.
* This exists for debugging purposes only.
*/
public String toString() {
StringBuilder sb = new StringBuilder("(");
Node<E> walk = head;
while (walk != null) {
sb.append(walk.getElement());
if (walk != tail)
sb.append(", ");
walk = walk.getNext();
}
sb.append(")");
return sb.toString();
}
public void swapNodes(Node<E> num1, Node<E> num2) {
Node<E> num1Prev = this.head;
Node<E> num2Prev = this.head;
if (num1 == num2 )
return ;
while((num1Prev != null)&&(num1Prev.getNext() != num1)){
num1Prev = num1Prev.getNext();
}
while((num2Prev != null)&&(num2Prev.getNext() != num2)){
num2Prev = num2Prev.getNext();
}
if(num2Prev == num1) {
num1.setNext(num2.getNext());
num2.setNext(num1);
num1Prev.setNext(num2);
}
else if(num1Prev == num2) {
num2.setNext(num1.getNext());
num1.setNext(num2);
num2Prev.setNext(num1);
}
else {
Node<E> tmp = num1.getNext();
num1.setNext(num2.getNext());
num2.setNext(tmp);
num1Prev.setNext(num2);
num2Prev.setNext(num1);
}
}
//main method
public static void main(String[] args)
{
SinglyLinkedList<String> list = new SinglyLinkedList<String>();
list.addFirst("MSP");
list.addLast("ATL");
list.addLast("BOS");
//
list.addFirst("LAX");
System.out.println(list);
//
SinglyLinkedList<String> swap = new SinglyLinkedList<String>();
swap.addFirst("1");
swap.addLast("2");
swap.addLast("3");
swap.addLast("4");
swap.addLast("5");
System.out.println("Original list: " + swap);
swap.swapNodes("2","5");
System.out.println("After Swapping list: " + swap);
}
}
Task: In this exercise, you will add a method swapNodes to SinglyLinkedList class from week 2 lecture examples. This method should swap two nodes node1 and node2 (and not just their contents) given references only to node1 and node2. The new method should check if node1 and node2 are the same nodes, etc. Write the main method to test the swapNodes method. Hint: You may need to traverse the list.
I made this method
public void swapNodes(Node<E> num1, Node<E> num2) {
Node<E> num1Prev = this.head;
Node<E> num2Prev = this.head;
if (num1 == num2 )
return ;
while((num1Prev != null)&&(num1Prev.getNext() != num1)){
num1Prev = num1Prev.getNext();
}
while((num2Prev != null)&&(num2Prev.getNext() != num2)){
num2Prev = num2Prev.getNext();
}
if(num2Prev == num1) {
num1.setNext(num2.getNext());
num2.setNext(num1);
num1Prev.setNext(num2);
}
else if(num1Prev == num2) {
num2.setNext(num1.getNext());
num1.setNext(num2);
num2Prev.setNext(num1);
}
else {
Node<E> tmp = num1.getNext();
num1.setNext(num2.getNext());
num2.setNext(tmp);
num1Prev.setNext(num2);
num2Prev.setNext(num1);
}
}
And then, created an instance to check if it's work, but it is showing me an error on here swap.swapNodes("2", "5");
Does anyone know what is the problem? Thank you
It's throwing error, because in your swapNodes function, you expect two parameters of type Node<E> passed, but you are passing E (String). So you have to change signature of the function or pass Node<E> that you added to your List.
Here's how you could do your swapNodes function with parameters of type E:
public void swapNodes(E element1, E element2) {
if (element1 == element2 || element1 == null || element2 == null || isEmpty()) return;
Node<E> num1 = findNode(element1);
Node<E> num2 = findNode(element2);
if (num1 == null || num2 == null) return;
Node<E> num1Prev = this.head;
Node<E> num2Prev = this.head;
while(num1Prev != null && num1Prev.getNext() != num1){
num1Prev = num1Prev.getNext();
}
while(num2Prev != null && num2Prev.getNext() != num2){
num2Prev = num2Prev.getNext();
}
if (num1Prev.getNext() == null || num2Prev.getNext() == null) return;
if (num2Prev.equals(num1)) {
num1.setNext(num2.getNext());
num2.setNext(num1);
num1Prev.setNext(num2;
} else if (num1Prev.equals(num2)) {
num2.setNext(num1.getNext());
num1.setNext(num2);
num2Prev.setNext(num1);
} else {
Node<E> tmp = num1.getNext();
num1.setNext(num2.getNext());
num2.setNext(tmp);
num1Prev.setNext(num2);
num2Prev.setNext(num1);
}
}
The findNode function could look like this:
public Node<E> findNode(E element) {
if (isEmpty()) return null;
Node<E> node = this.head;
while(node != null) {
if (node.getElement() == element) return node;
}
return null;
}
Got an assignment to create a class that links elements together.
Methods get(), add() and remove() were predefined by the assignment.
I actually managed to write code that creates such linked list,
but with the exception that the instance with value "Yo!" gets overwritten, when
adding new elements to the list and also I can't get the remove method working.
I really can't wrap my head around referencing object this way.
Could you help me correct my code ?
/**
*
* Represents a linked list of elements.
*
* #param <T>
*/
class LinkedElement<T> {
/**
* Adds a new linked element holding the given value at the end of the linked
* elements.
*
* #param newVal the new value.
*/
public void add(T newVal) {
if (head == null) {
head = new Element(newVal);
}
Element next = new Element(newVal);
Element current = head;
if (current != null) {
while (current.getNext() != null) {
current = current.getNext();
}
current.setNext(next);
}
increaseListSize();
}
/**
* Removes the i-th element from the linked elements. If {#code i == 0}, this
* will effectively remove the head element. Thus, this method returns the
* linked element that is the new head element.
*
* #param i index of the element to remove.
* #return the new head element.
*/
public LinkedElement<T> remove(int i) {
if (i < 1 || i > getListSize())
return null;
Element current = head;
if (head != null) {
for (int e = 0; e < i; i++) {
if (current.getNext() == null)
return null;
current = current.getNext();
}
current.setNext(current.getNext().getNext());
decreaseListSize();
}
return null;
}
Your get method is slightly wrong, you need to start current with head and not head.next()
public T get(int i) {
if (i < 0)
return null;
Element current = head;
if (current != null) {
for (int e = 0; e < i; e++) {
if (current.getNext() == null)
return null;
current = current.getNext();
}
return current.getValue();
}
return null;
}
You have a mistake in your get method: Element current = head; is correct.
There are several things that doesn't work in your remove method. This one should be working:
public void remove(int i) {
if (i==0) {
head = head.getNext();
decreaseListSize();
return;
}
if (i < 1 || i > getListSize()) {
return;
}
Element current = head;
if (head != null) {
for (int e = 1; e < i; e++) {
if (current.getNext() == null)
return ;
current = current.getNext();
}
current.setNext(current.getNext().getNext());
decreaseListSize();
}
}
Note that I changed return type to void since your method returned null in any case and return of head is no neccessary. If you want to return the head element you can easily adapt it and return head instead of nothing.
Furthermore, a note that the count - as so often in computer science - starts at 0. To remove the first element you have to write headElement.remove(0);.
I created a list that goes {50, 10, 60, 30, 40} and want to return the index when I reach 30 in my Linked List, however my program always returns -1 (basically it is unable to increment and return my index). I am not sure about how to go about getting back the index in a different manor unless I am able to cast the anEntry object into an integer and equal it my index.
class MyLinkedList {
private Node firstNode; // index = 0
private int length;
public MyLinkedList() {
firstNode = null;
length = 0;
} // end default constructor
/** Task: Adds a new entry to the end of the list.
* #param newEntry the object to be added as a new entry
* #return true if the addition is successful, or false if not */
public boolean add(Object newEntry) {
Node newNode = new Node(newEntry);
if (isEmpty())
firstNode = newNode;
else {
Node lastNode = getNode(length-1);
lastNode.next = newNode;
}
length++;
return true;
} // end add
/** Task: Adds a new entry at a specified index
* #param newEntry the object to be added at the specified index
* #return true if successful, or false if not */
public boolean add(int index, Object newEntry) {
boolean isSuccessful = true;
if ((index >= 0) && (index <= length)) {
Node newNode = new Node(newEntry);
if (isEmpty() || (index == 0)) {
newNode.next = firstNode;
firstNode = newNode;
}
else {
Node nodeBefore = getNode(index - 1);
Node nodeAfter = nodeBefore.next;
newNode.next = nodeAfter;
nodeBefore.next = newNode;
}
length++;
}
else
isSuccessful = false;
return isSuccessful;
} // end add
/** Task: Determines whether the list contains a given entry.
* #param anEntry the object that is the desired entry
* #return true if the list contains anEntry, or false if not */
public boolean contains(Object anEntry) {
boolean found = false;
Node currentNode = firstNode;
while (!found && (currentNode != null)) {
if (anEntry.equals(currentNode.data))
found = true;
else
currentNode = currentNode.next;
} // end while
return found;
} // end contains
/** Task: Gets an entry in the list.
* #param the desired index
* #return the desired entry, or
* null if either the list is empty or index is invalid */
public Object getEntry(int index) {
Object result = null; // result to return
if (!isEmpty() && (index >= 0) && (index < length))
result = getNode(index).data;
return result;
} // end getEntry
/** Task: Gets index of an entry in the list.
* #param the desired entry
* #return index of the first occurrence of the specified entry
* in this list, or -1 if this list does not contain the entry */
public int getIndex(Object anEntry) {
Node currentNode = firstNode;
int index = 0; // result to return
while (anEntry != currentNode.data) {
currentNode = currentNode.next;
index++;
if (anEntry.equals(currentNode.data)){
break;
}
else {
return -1;
}
}
return index;
} // end getIndex
private Node getNode(int index) {
Node currentNode = firstNode;
// traverse the list to locate the desired node
for (int counter = 0; counter < index; counter++)
currentNode = currentNode.next;
return currentNode;
} // end getNode
private Node getNode(int index) {
Node currentNode = firstNode;
// traverse the list to locate the desired node
for (int counter = 0; counter < index; counter++)
currentNode = currentNode.next;
return currentNode;
} // end getNode
private class Node {
private Object data; // data portion
private Node next; // link to next node
private Node(Object dataPortion) {
data = dataPortion;
next = null;
} // end constructor
private Node(Object dataPortion, Node nextNode) {
data = dataPortion;
next = nextNode;
} // end constructor
private void setData(Object dataPortion) {
data = dataPortion;
} // end setData
private Object getData() {
return data;
} // end getData
private void setNextNode(Node nextNode) {
next = nextNode;
} // end setNextNode
private Node getNextNode() {
return next;
} // end getNextNode
} // end Node
} // end MyLinkedList
The problem is that your while loop never does more than one iteration.
if (anEntry.equals(currentNode.data)){
break;
}
else {
return -1;
}
If the current element matches, then I have found the item so we can stop. If it doesn't, then the list does not contain this item. It should be relatively clear that this logic is wrong. Just because the current element doesn't match does not mean that subsequent elements might not match.
You can demonstrate this further by observing that getIndex(50) actually does return the correct index: zero. Your statement "my program always returns -1" is actually incorrect.
We need to swap this logic around - only return -1 after we have already tried all the elements.
while (anEntry != currentNode.data) {
currentNode = currentNode.next;
index++;
if (anEntry.equals(currentNode.data)){
return index;
}
}
return -1;
You will still have a problem where your code will throw an exception if the element is not in the list. This can be trivially solved with a minor change to the above code, but I'll leave that up to you to figure out!
Hi I'm trying to make remove method. But I don't know How to make this right. Here is my code.
This is LinkedList.java from Algorithm fourth edition.
/**
* <i>Algorithms, 4th Edition</i> by Robert Sedgewick and Kevin
* Wayne.
* #author Robert Sedgewick
* #author Kevin Wayne
*/
public class LinkedQueue<Item> implements Iterable<Item> {
private int N; // number of elements on queue
private Node first; // beginning of queue
private Node last; // end of queue
// helper linked list class
private class Node {
private Item item;
private Node next;
}
/**
* Initializes an empty queue.
*/
public LinkedQueue() {
first = null;
last = null;
N = 0;
assert check();
}
/**
* Is this queue empty?
* #return true if this queue is empty; false otherwise
*/
public boolean isEmpty() {
return first == null;
}
/**
* Returns the number of items in this queue.
* #return the number of items in this queue
*/
public int size() {
return N;
}
/**
* Returns the item least recently added to this queue.
* #return the item least recently added to this queue
* #throws java.util.NoSuchElementException if this queue is empty
*/
public Item peek() {
if (isEmpty()) throw new NoSuchElementException("Queue underflow");
return first.item;
}
/**
* Adds the item to this queue.
* #param item the item to add
*/
public void enqueue(Item item) {
Node oldlast = last;
last = new Node();
last.item = item;
last.next = null;
if (isEmpty()) first = last;
else oldlast.next = last;
N++;
assert check();
}
/**
* Removes and returns the item on this queue that was least recently added.
* #return the item on this queue that was least recently added
* #throws java.util.NoSuchElementException if this queue is empty
*/
public Item dequeue() {
if (isEmpty()) throw new NoSuchElementException("Queue underflow");
Item item = first.item;
first = first.next;
N--;
if (isEmpty()) last = null; // to avoid loitering
assert check();
return item;
}
/**
* Returns a string representation of this queue.
* #return the sequence of items in FIFO order, separated by spaces
*/
public String toString() {
StringBuilder s = new StringBuilder();
for (Item item : this)
s.append(item + " ");
return s.toString();
}
// check internal invariants
private boolean check() {
if (N == 0) {
if (first != null) return false;
if (last != null) return false;
}
else if (N == 1) {
if (first == null || last == null) return false;
if (first != last) return false;
if (first.next != null) return false;
}
else {
if (first == last) return false;
if (first.next == null) return false;
if (last.next != null) return false;
// check internal consistency of instance variable N
int numberOfNodes = 0;
for (Node x = first; x != null; x = x.next) {
numberOfNodes++;
}
if (numberOfNodes != N) return false;
// check internal consistency of instance variable last
Node lastNode = first;
while (lastNode.next != null) {
lastNode = lastNode.next;
}
if (last != lastNode) return false;
}
return true;
}
//working properly
void reverseBystack(){
Stack<Item> s = new Stack<>();
Item item;
while (isEmpty() != true){
item = dequeue();
s.push(item);
}
while(s.isEmpty() != true){
item = s.pop();
enqueue(item);
}
}
//working properly.
void reverseBylink() {
Node prev = null;
Node current = this.first;
Node next = null;
Node temp = null;
while (current != null) {
next = current.next;
current.next = prev;
prev = current;
current = next;
}
temp =first;
first = last;
last = temp;
}
//How to do this...;<..
int remove(Item item) {
Node cur = this.first;
while (cur !=null) {
if (cur.item.equals(item)) {
item = dequeue();
}
cur = cur.next;
N++;
}
return 0;
}
/**
* Returns an iterator that iterates over the items in this queue in FIFO order.
* #return an iterator that iterates over the items in this queue in FIFO order
*/
public Iterator<Item> iterator() {
return new ListIterator();
}
// an iterator, doesn't implement remove() since it's optional
private class ListIterator implements Iterator<Item> {
private Node current = first;
public boolean hasNext() { return current != null; }
public void remove() { throw new UnsupportedOperationException(); }
public Item next() {
if (!hasNext()) throw new NoSuchElementException();
Item item = current.item;
current = current.next;
return item;
}
}
Unit tests
/**
* Unit tests the <tt>LinkedQueue</tt> data type.
*/
public static void main(String[] args) {
LinkedQueue<String> q = new LinkedQueue<String>();
/* Working properly for reverseByStack.
q.enqueue("a");
q.enqueue("b");
q.enqueue("c");
q.enqueue("a");
q.enqueue("b");
q.enqueue("d");
q.enqueue("b");
q.enqueue("abba");
q.enqueue("a");
q.enqueue("z");
q.enqueue("a");
q.reverseBystack();
System.out.println(q);
StdOut.println("(" + q.size() + " left on queue)");
*/
/*Move on to next, working properly
q.enqueue("a");
q.enqueue("b");
q.enqueue("c");
q.enqueue("a");
q.enqueue("b");
q.enqueue("d");
q.enqueue("b");
q.enqueue("abba");
q.enqueue("a");
q.enqueue("z");
q.enqueue("a");
q.reverseBylink();
System.out.println(q);
StdOut.println("(" + q.size() + "left on queue)");*/
q.enqueue("a");
q.enqueue("b");
q.enqueue("c");
q.enqueue("a");
q.enqueue("b");
q.enqueue("d");
q.enqueue("b");
q.enqueue("abba");
q.enqueue("a");
q.enqueue("z");
q.enqueue("a");
System.out.println(q);
System.out.println("Remove some of elements. and use reverseByLink");
q.remove("a");
q.remove("f");
q.remove("c");
System.out.println(q);
}
Output.
a b c a b d b abba a z a
Remove some of elements. and use reverseByLink
a b d b abba a z a
I don't know why String a is not removed and after abba.
int remove(Item item) {
if(this.first == null)
return 0;
if(this.first == item) {
// remove root item
Node node = this.first.next;
this.first.next = null;
this.first = node;
return 1;
}
Node prv = this.first;
while (prv.next != item)
prv = prv.next;
// item was not found
if(prv == null)
return 0;
Node node = prv.next.next;
prv.next.next = null;
prv.next = node;
return 1;
}
I'm fairly sure this method is wrong:
int remove(Item item) {
Node cur = this.first;
while (cur !=null) {
if (cur.item.equals(item)) {
item = dequeue();
}
cur = cur.next;
N++;
}
return 0;
}
Your dequeue method pops the front of the list. But the item you're removing might not be the front of the list.
I didn't look for more problems.
This is standard linked list stuff. Some of your textbooks should have algorithms for this. But basically, you need to keep track of the last pointer you used. Let's say you have lastPtr and currentPtr, and you determine that currentPtr needs to go.
Then lastPtr.next = currentPtr.next
It's more interesting if you're at the head. You need to recognize that and instead do first.next = currentPtr.next.
dequeue() methods is popping out items from the front , but to remove all the occurrences of any string , you need to modify your remove() method to -
void remove(Item item) {
Node cur = this.first;
Node prev = null;
if(this.first.item.equals(item)){
item = dequeue();
cur = this.first;
}
while (cur != null) {
/* if (cur.item.equals(item)) {
item = dequeue();
}*/
while(cur != null && !cur.item.equals(item)) {
prev = cur;
cur = cur.next;
}
if(cur == null)
return;
prev.next = cur.next;
cur = prev.next;
}
return ;
}
I would like to use a linked list in order to perform extractions and insertions of elements, trying out all combinations for a heuristic. Linked lists are more efficient for this type of operations.
Since I would want to try all possible pairs of extractions/inserts, I used two different iterators over the list. This raises a "ConcurrentModificationException". How could I perform this operation efficiently, without re-traversing the list every time, as this would defeat the whole purpose of using a list in the first place?
Here is the relevant part of the code:
ListIterator<Integer> it1 = data.listIterator();
ListIterator<Integer> it2;
while(it1.hasNext()) {
int i = it1.next();
it2 = data.listIterator();
while(it2.hasNext()) {
if (i == it2.next()) continue; // continue right away when the indexes are equal
it1.remove();
it2.add(i);
if (length() < best)
return true;
}
// when the swap is not better/consistent
it2.remove();
it1.add(i);
}
return false;
Thanks
You can't use multiple iterators simultaneously on a LinkedList, however you can with a CopyOnWriteArrayList
Try this:
List<Integer> safeData = new CopyOnWriteArrayList(date);
// your code, but working with safeData rather than data
If I get you right, you look for a data structure that offers several iterators for manipulating the list. This is technically difficult for the original java.util.LinkedList because it does housekeeping for the current index and this is only possible in an efficient way if there are no parallel changes at unknown positions in the list by other iterators. But, you can easily implement a simple LinkedList that does not do this housekeeping and supports adding/removing through several iterators. Then, an iterator does not know its position in the list, but I bet you do not care. Just use something like this:
public class MyList<T> {
private MyNode<T> first = null, last = null;
public MyNode<T> getFirst() {
return first;
}
public MyNode<T> getLast() {
return last;
}
public boolean contains(MyNode<T> n) {
return n.list == this;
}
/**
* If beforeMe is null, toInsert is inserted at the end of the list.
* #return inserted node
*/
public void insertBefore(MyNode<T> beforeMe, MyNode<T> newNode) {
if (newNode == null) {
throw new IllegalArgumentException("toInsert must not be null!");
}
if (newNode.list != null) {
throw new IllegalArgumentException("This node is already in the list " + newNode.list);
}
if (beforeMe == null) {
if (last == null) {
newNode.prev = newNode.next = null;
first = last = newNode;
} else {
last.next = newNode;
newNode.prev = last;
newNode.next = null;
last = newNode;
}
} else {
newNode.prev = beforeMe.prev;
newNode.next = beforeMe;
if (beforeMe.prev != null) {
beforeMe.prev.next = newNode;
} else {
first = newNode;
}
beforeMe.prev = newNode;
}
newNode.list = this;
}
/**
* If beforeMe is null, t is inserted at the end of the list.
* #return inserted node
*/
public MyNode<T> insertBefore(MyNode<T> beforeMe, T t) {
MyNode<T> newNode = new MyNode<T>(t);
insertBefore(beforeMe, newNode);
return newNode;
}
public void remove(MyNode<T> n) {
if (n == null || n.list != this) {
throw new IllegalArgumentException("Node is not in the list!");
}
if (n.prev != null) {
n.prev.next = n.next;
} else {
first = n.next;
}
if (n.next != null) {
n.next.prev = n.prev;
} else {
last = n.prev;
}
n.prev = n.next = null;
n.list = null;
}}
public class MyNode<T> {
private T t;
/**
* written only by MyList
*/
MyNode<T> prev = null;
/**
* written only by MyList
*/
MyNode<T> next = null;
/**
* written only by MyList
*/
MyList<T> list = null;
public T get() {
return t;
}
public void set(T t) {
this.t = t;
}
public MyNode<T> previous() {
return prev;
}
public MyNode<T> next() {
return next;
}
public MyList<T> list() {
return list;
}
/**
* called only by MyList.
* #param t
*/
MyNode(T t) {
this.t = t;
}}
You can use ANY number of iterators on a LIST when you are doing only a read operation. Since you are doing a remove / add here, you can't use the same list with two different iterators as it will cause the ConcurrentModificationException as you are experiencing now.
What you like to achieve? May be, people can help you with different options.