Singly Linked List
public class SinglyLinkedList<T> implements Iterable<T>{
private ListNode<T> head;
private int size;
public SinglyLinkedList() {
head = null;
size = 0;
}
public void insertAtHead(T value) {
ListNode<T> node = new ListNode<>(value);
node.next = head;
head = node;
size++;
}
public void insertAtEnd(T value) {
ListNode<T> node = new ListNode<>(value);
if (head == null) {
head = node;
} else {
var curr = head;
while (curr.next != null) {
curr = curr.next;
}
curr.next = node;
}
size++;
}
public void insertAfter(T value, T previous) {
if (isEmpty()) {
insertAtEnd(value);
}
ListNode<T> node = new ListNode<>(value);
var curr = head;
while (curr.next != null && curr != previous) {
curr = curr.next;
}
if (curr.next == null) {
curr.next = node;
} else {
var next = curr.next;
curr.next = node;
node.next = next;
}
}
public boolean remove(T value) {
ListNode<T> curr = head, prev = null;
while (curr != null) {
if (curr.value.equals(value)) {
if (prev == null) {
head = curr.next;
} else {
prev.next = curr.next;
}
size--;
return true;
}
prev = curr;
curr = curr.next;
}
return false;
}
public boolean remove(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException(index);
}
int i = 0;
ListNode<T> curr = head, prev = null;
while (curr != null) {
if (i == index) {
if (prev == null) {
head = curr.next;
} else {
prev.next = curr.next;
}
break;
}
i++;
prev = curr;
curr = curr.next;
}
size--;
return true;
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public T get(int index) {
if (index >= size) {
throw new IndexOutOfBoundsException(index);
}
var curr = head;
int i = 0;
while (curr != null) {
if (i == index) {
break;
}
i++;
curr = curr.next;
}
return Objects.requireNonNull(curr).value;
}
@Override
public Iterator<T> iterator() {
return new SinglyListIterator();
}
@Override
public String toString() {
var sb = new StringBuilder();
if (isEmpty()) {
sb.append("List is Empty!");
return sb.toString();
}
ListNode<T> temp = head;
while (temp.next != null) {
sb.append(temp.value.toString())
.append(" -> ");
temp = temp.next;
}
return sb.append(temp.value.toString())
.toString();
}
private class SinglyListIterator implements Iterator<T> {
private ListNode<T> nextNode;
public SinglyListIterator() {
this.nextNode = head;
}
@Override
public boolean hasNext() {
return this.nextNode != null;
}
@Override
public T next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
var item = nextNode.value;
nextNode = nextNode.next;
return item;
}
}
}
Doubly Linked List
public class DoublyLinkedList<E> implements Iterable<E> {
private ListNode<E> head;
private int size;
public boolean isEmpty() {
return head == null;
}
public int size() {
return size;
}
public void addFirst(E item) {
if (isEmpty()) {
head = new ListNode<>(null, item, null);
} else {
var curr = head;
head = new ListNode<>(null, item, curr);
curr.prev = head;
}
size++;
}
public E getFirst() {
if (head == null) throw new NoSuchElementException();
return head.item;
}
public void addLast(E item) {
if (isEmpty()) {
addFirst(item);
} else {
var curr = head;
while (curr.next != null) {
curr = curr.next;
}
curr.next = new ListNode<>(curr, item, null);
size++;
}
}
public E getLast() {
if (isEmpty()) {
throw new NoSuchElementException();
}
var curr = head;
while (curr.next != null) {
curr = curr.next;
}
return curr.item;
}
public E get(final int index) {
checkPositionIndex(index);
if (head == null) throw new IndexOutOfBoundsException();
var curr = head;
for (int i = 0; i < index; i++) {
curr = curr.next;
}
if (curr == null) throw new IndexOutOfBoundsException();
return curr.item;
}
public void add(int index, E item) {
checkPositionIndex(index);
if (index == size) {
addLast(item);
} else {
link(item, node(index));
}
}
public void insertAfter(E item, E newItem) {
if (isEmpty()) {
addFirst(newItem);
return;
}
var curr = head;
while (curr != null && !item.equals(curr.item)) {
curr = curr.next;
}
if (curr != null) {
curr.next = new ListNode<>(curr, newItem, curr.next);
size++;
}
}
public void insertBefore(E item, E newItem) {
if (isEmpty()) {
addFirst(newItem);
return;
}
ListNode<E> prev = null;
var curr = head;
while (curr != null && !item.equals(curr.item)) {
curr = curr.next;
}
if (curr != null) {
var newNode = new ListNode<>(curr.prev, newItem, curr);
curr.prev.next = newNode;
curr.prev = newNode;
size++;
}
}
public void delete(E item) {
if (isEmpty()) {
throw new NoSuchElementException();
}
if (item.equals(head.item)) {
head = head.next;
head.prev = null;
size--;
return;
}
var curr = head;
while (curr != null && !item.equals(curr.item)) {
curr = curr.next;
}
if (curr == null) {
throw new NoSuchElementException("Element " + item.toString() + " not found");
}
if (curr.next != null) {
curr.next.prev = curr.prev;
}
curr.prev.next = curr.next;
size--;
}
private ListNode<E> node(int index) {
var curr = head;
for (int i = 0; i < index; i++) {
curr = curr.next;
}
return curr;
}
private void link(E item, ListNode<E> succ) {
var curr = head;
while (curr.next != null && curr.next != succ) {
curr = curr.next;
}
curr.next = new ListNode<>(curr, item, curr.next);
size++;
}
private void checkPositionIndex(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
@Override
public Iterator<E> iterator() {
return new DoublyListIterator();
}
private static class ListNode<T> {
private T item;
private ListNode<T> next;
private ListNode<T> prev;
public ListNode(ListNode<T> prev, T value, ListNode<T> next) {
this.item = value;
this.next = next;
this.prev = prev;
}
}
private class DoublyListIterator implements Iterator<E> {
private ListNode<E> nextNode;
public DoublyListIterator() {
this.nextNode = head;
}
@Override
public boolean hasNext() {
return this.nextNode != null;
}
@Override
public E next() {
if (!hasNext()) {
throw new NoSuchElementException();
}
var item = nextNode.item;
nextNode = nextNode.next;
return item;
}
}
}