问题
I am implementing the add(E) method in the cyclic DoublyLinkedList class as well as the Node inner class.
Node should be implemented as a private inner class.
DoublyLinkedList's "first" attribute should point to the first node in the list. Its "size" attribute should store the number of elements in the list.
I am struggling on my add method, because it feels like nothing is wrong and I don't know what else I can add this this code that can fix it.
Therefore a brief introduction on what the add method should do.
The add(E) method should add the value parameter to the end of the list. Be sure to address the case in which the list is empty and/or the added element is the first in the list.
Here's my code:
public class DoublyLinkedList<E>
{
private Node first;
private int size;
@SuppressWarnings("unchecked")
public void add(E value)
{
if(first == null)
{
first = new Node(value, null, null);
first.next = first;
first.prev = first;
}
else
{
first = new Node(value, first.next, first.prev);
first.next = first.prev;
first = first.next;
first.prev = first;
}
size++;
}
private class Node<E>
{
private E data;
private Node next;
private Node prev;
public Node(E data, Node next, Node prev)
{
this.data = data;
this.next = next;
this.prev = prev;
}
}
}
回答1:
Code fixed with minimal change (just the else case in add):
class DoublyLinkedList<E>
{
private Node first;
private int size;
public void add(E value)
{
if(first == null)
{
first = new Node(value, null, null);
first.next = first;
first.prev = first;
}
else
{
first.prev.next = new Node(value, first, first.prev);
first.prev = first.prev.next;
}
size++;
}
private class Node<E>
{
private E data;
private Node next;
private Node prev;
public Node(E data, Node next, Node prev)
{
this.data = data;
this.next = next;
this.prev = prev;
}
}
}
回答2:
EDIT:
One mistake is here: Instead of this line this.next = prev; it should have this.prev = prev;
However, if you fix this line the code will still not work. This is a simplified version of your code that works.
public class DoublyLinkedList<E> {
private static class Node<E> {
private final E data;
private Node<E> next;
private Node<E> prev;
Node(E data) {
this.data = data;
this.next = this;
this.prev = this;
}
Node(E data, Node<E> next) {
this.data = data;
this.next = next;
next.prev = this;
}
}
private Node<E> head;
private Node<E> tail;
private int size;
public void add(E value) {
if (this.head == null) {
this.head = new Node<>(value);
this.tail = head;
} else {
this.head = new Node<>(value, head);
this.head.prev = this.tail;
this.tail.next = head;
}
size++;
}
public void forEach(Consumer<E> consumer) {
Node<E> node = this.head;
if (node != null) {
do {
consumer.accept(node.data);
node = node.next;
} while (node != this.head);
}
}
public static void main(String[] args) {
DoublyLinkedList<Integer> list = new DoublyLinkedList<>();
list.add(1);
list.add(2);
list.add(3);
list.forEach(e -> System.out.print(e + ", "));
}
}
What I've done: in order to create a circular double linked list I keep a reference to the tail.
回答3:
Here is a sample implementation for your case -
import java.util.Iterator;
public class DoublyLinkedList<E> {
// A reference to the root node
private Node<E> root = null;
// attribute for storing the size of the linked list
private int countOfNodes = 0;
// attribute that indicates if the linked list would be iterated in a cycle
private boolean isCircular = false;
/**
* The linked list Node class
*
* @param <E>
*/
@SuppressWarnings("hiding")
class Node<E> {
// attribute for storing the value
private E data;
// attributes for storing the linked list references
private Node<E> previousNode = null;
private Node<E> nextNode = null;
public Node() {
super();
}
public Node(E data) {
super();
this.data = data;
}
public Node<E> getPreviousNode() {
return previousNode;
}
public void setPreviousNode(Node<E> previousNode) {
this.previousNode = previousNode;
}
public Node<E> getNextNode() {
return nextNode;
}
public void setNextNode(Node<E> nextNode) {
this.nextNode = nextNode;
}
public E getData() {
return data;
}
public void setData(E data) {
this.data = data;
}
}
/**
* The iterator implementation
*/
@SuppressWarnings("hiding")
class DoublyLinkedListIterator<E> implements Iterator<E> {
private Node<E> currentNode = null;
public DoublyLinkedListIterator(Node<E> startNode) {
super();
this.currentNode = startNode;
}
@Override
public boolean hasNext() {
return (this.currentNode != null);
}
@SuppressWarnings("unchecked")
@Override
public E next() {
E data = currentNode.getData();
currentNode = currentNode.getNextNode();
if (currentNode == null && DoublyLinkedList.this.isCircular()) {
this.currentNode = (Node<E>) DoublyLinkedList.this.getRoot();
}
return data;
}
}
public DoublyLinkedList() {
super();
}
public boolean isCircular() {
return this.isCircular;
}
public void setCircular(boolean isCircular) {
this.isCircular = isCircular;
}
public Node<E> getRoot() {
return root;
}
public void setRoot(Node<E> root) {
this.root = root;
}
public int size() {
return this.countOfNodes;
}
public Iterator<E> iterator() {
return new DoublyLinkedListIterator<>(this.getRoot());
}
public void add(E value) {
Node<E> node = new Node<E>(value);
addAfter(getLastNode(), node);
this.countOfNodes++;
}
public Node<E> getLastNode() {
Node<E> lastNode = null;
Node<E> node = getRoot();
while (node != null) {
lastNode = node;
node = node.getNextNode();
}
return lastNode;
}
public void addAfter(Node<E> parentNode, E value) {
Node<E> newNode = new Node<E>(value);
addAfter(parentNode, newNode);
}
public void addAfter(Node<E> parentNode, Node<E> newNode) {
if (parentNode == null) {
this.setRoot(newNode);
} else {
parentNode.setNextNode(newNode);
}
}
public void addBefore(Node<E> parentNode, E value) {
Node<E> newNode = new Node<E>(value);
addBefore(parentNode, newNode);
}
public void addBefore(Node<E> parentNode, Node<E> newNode) {
if (parentNode == null) {
this.setRoot(newNode);
} else {
Node<E> prevNode = parentNode.getPreviousNode();
parentNode.setPreviousNode(newNode);
newNode.setNextNode(parentNode);
newNode.setPreviousNode(prevNode);
if (newNode.getPreviousNode() == null) {
this.setRoot(newNode);
}
}
}
}
And, following is a test -
import static org.junit.jupiter.api.Assertions.fail;
import java.util.Iterator;
import org.junit.jupiter.api.Test;
class DoublyLinkedListTest {
private final int initialSize = 4;
private DoublyLinkedList<String> list = new DoublyLinkedList<String>() {{
setCircular(true);
for(int i = 0; i < initialSize; i++) {
add("Data " + (i + 1));
}
}};
public DoublyLinkedListTest() {
super();
}
@Test
void testListSize() {
if (list.size() != initialSize) {
fail(String.format("Expected value for the list's size is %d, whereas obtained value is %d", 4, list.size()));
}
}
@Test
void testLastElement() {
String lastAddedValue = list.getLastNode().getData();
String expectedValue = "Data 4";
if (!expectedValue.equals(lastAddedValue)) {
fail(String.format("Expected value for the last node is %s, whereas obtained value is %s", expectedValue, lastAddedValue));
}
}
@Test
void testAddElementOnTop() {
list.addBefore(list.getRoot(), "Data 5");
String lastAddedValue = list.getRoot().getData();
String expectedValue = "Data 5";
if (!expectedValue.equals(lastAddedValue)) {
fail(String.format("Expected value for the last node is %s, whereas obtained value is %s", expectedValue, lastAddedValue));
}
}
@Test
void testCircularIteration() {
Iterator<String> iterator = list.iterator();
int counter = 0;
final int expectedValue = (initialSize + 1) * 2;
while(iterator.hasNext()) {
counter++;
if (counter == expectedValue) {
break;
}
}
if (counter != expectedValue) {
fail(String.format("Expected value for the iteration count is %d, whereas obtained value is %d", expectedValue, counter));
}
}
}
来源:https://stackoverflow.com/questions/55190980/how-to-do-a-cyclic-doubly-link-list-add-method-in-java