Last active
December 21, 2015 18:38
-
-
Save Solonarv/08aa7bd7f69d0e95d15e to your computer and use it in GitHub Desktop.
A linked-list reimplementation in Java 8, with a functional interface.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@FunctionalInterface | |
public interface BinOp<T, U, V> { | |
abstract V op(T x, U y); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@FunctionalInterface | |
public interface Function<T, U> { | |
abstract U run(T x); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* A nice, generic linked list implementation. | |
* | |
* @author Solonarv | |
* | |
* @param <T> | |
* the type of the list's elements. | |
*/ | |
public class LinkedList<T> { | |
protected ConsCell<T> head; | |
// Cached for efficiency | |
protected ConsCell<T> last; | |
protected int length; | |
public LinkedList() { | |
this.head = null; | |
this.last = null; | |
} | |
public void add(T elem) { | |
ConsCell<T> newLast = new ConsCell<>(elem); | |
if (this.last != null) { | |
this.last.cdr = newLast; | |
} | |
this.last = newLast; | |
this.length++; | |
} | |
public void add(T elem, int index) { | |
if (index < 0 || index >= this.length - 1) { | |
this.add(elem); | |
return; | |
} | |
ConsCell<T> prev = null; | |
ConsCell<T> current = this.head; | |
for (int i = 0; i < index; i++) { | |
prev = current; | |
current = current.cdr; | |
} | |
ConsCell<T> newCell = new ConsCell<>(elem, current); | |
prev.cdr = newCell; | |
this.length++; | |
} | |
public boolean remove(int index) { | |
if (index < 0 || index >= this.length) { | |
return false; | |
} | |
ConsCell<T> prev = null; | |
ConsCell<T> current = this.head; | |
for (int i = 0; i < index; i++) { | |
prev = current; | |
current = current.cdr; | |
} | |
prev.cdr = current.cdr; | |
this.length--; | |
return true; | |
} | |
public T getFirst() { | |
if (this.head == null) { | |
return null; | |
} | |
return this.head.car; | |
} | |
public T getLast() { | |
if (this.last == null) { | |
return null; | |
} | |
return this.last.car; | |
} | |
public T get(int index) { | |
if (index < 0 || index >= this.length) { | |
return null; | |
} | |
ConsCell<T> current = this.head; | |
for (int i = 0; i < index; i++) { | |
current = current.cdr; | |
} | |
return current.car; | |
} | |
public boolean remove(T elem) { | |
if (this.head == null) { | |
return false; | |
} | |
ConsCell<T> prev = null; | |
ConsCell<T> current = this.head; | |
boolean found = false; | |
while (current != null) { | |
if (current.car.equals(elem)) { | |
found = true; | |
break; | |
} | |
prev = current; | |
current = current.cdr; | |
} | |
if (found) { | |
prev.cdr = current.cdr; | |
this.length--; | |
return true; | |
} | |
return false; | |
} | |
// Alternate implementation: return this.find(other) != null; | |
// This is probably more efficient though. | |
public boolean contains(T other) { | |
return this.foldr(false, (Boolean acc, T elem) -> { | |
return acc || elem.equals(other); | |
}); | |
} | |
public T find(T other) { | |
return this.foldr(null, (BinOp<T, T, T>) ((T acc, T elem) -> { | |
return (acc != null) ? acc : (elem.equals(other) ? elem : null); | |
})); | |
} | |
protected <R> R foldr(R startingAcc, BinOp<R, T, R> f) { | |
R acc = startingAcc; | |
ConsCell<T> current = this.head; | |
while (current != null) { | |
acc = f.op(acc, current.car); | |
current = current.cdr; | |
} | |
return acc; | |
} | |
public int size() { | |
return this.length; | |
} | |
public <U> LinkedList<U> map(Function<T, U> f) { | |
return this.foldr(new LinkedList<U>(), (BinOp<LinkedList<U>, T, LinkedList<U>>) (LinkedList<U> acc, T elem) -> { | |
return acc.cons(f.run(elem)); | |
}); | |
} | |
public LinkedList<T> cons(T elem) { | |
this.head = new ConsCell<>(elem, this.head); | |
return this; | |
} | |
protected class ConsCell<V> { | |
public V car; | |
public ConsCell<V> cdr; | |
public ConsCell(V car, ConsCell<V> cdr) { | |
this.car = car; | |
this.cdr = cdr; | |
} | |
public ConsCell(V car) { | |
this(car, null); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment