Here is a naive version of a singly linked list in Java. It implements only Collection
and Iterable
interfaces. Any comments and suggestions are welcome.
SinglyLinkedList.java:
package com.ciaoshen.thinkinjava.newchapter17;
import java.util.*;
public class SinglyLinkedList<E> implements Collection<E>, Iterable<E> {
private int size = 0;
private Node<E> head = new Node<E>();
// constructor
public SinglyLinkedList() {
head.setNext(head);
}
public SinglyLinkedList(Collection<E> c) {
this();
addAll(c);
}
// unmodifiable collection (except remove() method)
public Iterator<E> iterator() {
return new Iterator<E>() {
Node<E> cursor = head;
Node<E> previous = head;
public boolean hasNext() {
return cursor.getNext() != head;
}
public E next() {
if (! hasNext()) {
throw new IndexOutOfBoundsException("Iterator has reached the end of the list!");
}
Node<E> toReturn = cursor.getNext();
previous = cursor;
cursor = toReturn;
return toReturn.getInfo();
}
public void remove() { // only remove once the last node return by next() method.
if (cursor == previous) {
throw new IndexOutOfBoundsException("Cannot remove current node. Last node returned by next() already removed, or reach the head of the list!");
}
previous.setNext(cursor.getNext());
cursor.setNext(null);
cursor = previous;
size--;
}
};
}
public int size() {
return size;
}
public String toString() {
if (isEmpty()) {
return "[]";
}
StringBuilder sb = new StringBuilder();
Iterator<E> ite = iterator();
sb.append("[");
while (ite.hasNext()) {
sb.append(ite.next());
if (ite.hasNext()) {
sb.append(", ");
}
}
sb.append("]");
return sb.toString();
}
@SuppressWarnings("unchecked")
public boolean contains(Object o) {
if (o == null) {
throw new NullPointerException("Object for contains() method is null!");
}
E ele = (E)o; // throw ClassCastException
Iterator<E> ite = iterator();
while (ite.hasNext()) {
if (ite.next().equals(ele)) {
return true;
}
}
return false;
}
public boolean containsAll(Collection<?> c) {
if (c == null) {
throw new NullPointerException("Collection arg is null in conainsAll() method!");
}
for (Object o : c) {
if (!contains(o)) {
return false;
}
}
return true;
}
@SuppressWarnings("rawtypes")
public boolean equals(Object o) {
if (o == null || !(o instanceof SinglyLinkedList)) {
return false;
}
SinglyLinkedList target = (SinglyLinkedList)o;
if (size() != target.size()) {
return false;
}
return hashCode() == target.hashCode();
}
public int hashCode() {
int init = 31;
for (E ele : this) {
init = (init + ele.hashCode()) * 31;
}
return init;
}
public boolean isEmpty() {
return head.getNext() == head;
}
public Object[] toArray() { // keep silence even if list is changed during the copy (naive way)
Object[] array = new Object[size()];
Iterator<E> ite = iterator();
for (int i = 0; i <array.length; i++) {
if (ite.hasNext()) {
array[i] = ite.next();
}
}
return Arrays.copyOf(array,array.length); // deep copy, not shallow copy
}
public <T> T[] toArray(T[] a) {
throw new UnsupportedOperationException("Not Yet!");
}
// modifible optional operations
public boolean add(E e) { // add after head
if (e == null) {
return false;
}
Node<E> newNode = new Node<E>(e);
newNode.setNext(head.getNext());
head.setNext(newNode);
size ++;
return true;
}
public boolean addAll(Collection<? extends E> c) {
boolean result = false;
if (c == null || c.isEmpty()) {
return result;
}
for (E ele : c) {
if (add(ele)) {
result = true;
}
}
return result;
}
public void clear() {
head.setNext(head);
size = 0;
}
@SuppressWarnings("unchecked")
public boolean remove(Object o) {
boolean result = false;
if (o == null) {
Iterator<E> ite = iterator();
while (ite.hasNext()) {
if (ite.next() == null) {
ite.remove();
result = true;
}
}
} else {
E ele = (E)o;
Iterator<E> ite = iterator();
while (ite.hasNext()) {
if (ite.next().equals(ele)) {
ite.remove();
result = true;
}
}
}
return result;
}
public boolean removeAll(Collection<?> c) {
boolean result = false;
if (c == null || c.isEmpty()) {
return result;
}
if (!(c instanceof Collection)) {
throw new ClassCastException("Argument for removeAll() method should be a Collection!");
}
for (Object o : c) {
if (remove(o)) {
result = true;
}
}
return result;
}
public boolean retainAll(Collection<?> c) {
boolean result = false;
if (c == null || c.isEmpty()) {
return result;
}
if (!(c instanceof Collection)) {
throw new ClassCastException("Argument for retainAll() method should be a Collection!");
}
Iterator<E> ite = iterator();
while (ite.hasNext()) {
if (!c.contains(ite.next())) {
ite.remove();
result = true;
}
}
return result;
}
}
Node.java:
package com.ciaoshen.thinkinjava.newchapter17;
import java.util.*;
public class Node<T> {
private T info = null;
private Node<T> next = null;
public Node() {}
public Node(T t) {
info = t;
}
@SuppressWarnings("rawtypes")
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o == null || !(o instanceof Node)) {
return false;
}
Node node = (Node)o;
return info.equals(node.info);
}
public int hashCode() {
if (info == null) {
return 0;
}
return info.hashCode();
}
public T getInfo() {
return info;
}
public T setInfo(T t) { // return old value
T old = getInfo();
info = t;
return old;
}
public Node<T> getNext() {
return next;
}
public Node<T> setNext(Node<T> n) {
Node<T> old = next;
next = n;
return old;
}
public String toString() {
return "[" + info + "]";
}
}
AbstractList
which implements some methods based on other abstract methods so you don't have to. Also,Collection<E>
already extendsIterable<E>
. There's no need for an explicitimplements
of the latter. \$\endgroup\$ – David Foerster Jan 20 '17 at 13:33