data
field.next
field, which is a reference to the next ListNode.head
field, which points to the first ListNode in the list.head
.tail
pointer for faster access.head
: Points to the first element.tail
: Points to the last element.data
: Holds the data.next
: A reference to the next node (recursion).T
:class List<T> { ListNode<T> head; ListNode<T> tail; ... }
class ListNode<T> { T data; ListNode<T> next; ... }
Adding to the Front:
head
and tail
to it.head
to point to the new element.public void addFront(String data) {
head = new Node(data, head);
if (size == 0)
tail = head;
size++;
}
Note: After the first element is added, the tail
never changes.
Adding to the Back:
public void addBack(String data) {
Node node = new Node(data);
if (size == 0) {
head = node;
} else {
tail.next = node;
}
tail = node;
size++;
}
Note: After the first element is added, the head
never changes.
Traversing a linked list involves visiting each element, useful for printing, searching, and accessing elements by index.
public boolean contains(String data) {
Node current = head;
while (current != null) {
if (current.data.equals(data))
return true;
current = current.next;
}
return false;
}
fun(i, j)
has a time complexity of O(1).mystery(n)
has a time complexity of O(n^2).String Builders are used for efficient string manipulation.
public String toString() {
StringBuilder answer = new StringBuilder();
answer.append("<");
Node<T> current = head;
while (current != null) {
answer.append(current.data);
if (current.next != null)
answer.append(", ");
current = current.next;
}
answer.append(">");
return answer.toString();
}
Without String Builder:
public String toString() {
String answer = “”;
answer = answer + ”<“;
Node<T> current = head;
while (current != null) {
answer = answer + current.data;
if (current.next != null)
answer = answer + ", ";
current = current.next;
}
answer = answer + ">";
return answer;
}
Due to type erasure, generic arrays cannot be created directly.
Instead, an Object array is created, relying on polymorphism and typecasting.
public class DIYArrayList <T extends Comparable<T>> implements DIYList<T> {
private Object[] values;
private int size;
public DIYArrayList() {
values = new Object[INIT_SIZE];
}
}
Growing the array:
private void growArray() {
Object[] oldValues = values;
values = new Object[oldValues.length * 2];
for (int n = 0; n < oldValues.length; n++)
values[n] = oldValues[n];
}
public void add(T data) {
if (size + 1 > values.length) {
growArray();
}
values[size++] = data;
}
public void add(int idx, T data) {
if (size + 1 > values.length)
growArray();
for (int n = size; n > idx; n--)
values[n] = values[n-1];
values[idx] = data;
size++;
}
add(T data)
has a time complexity of O(1).growArray()
has a time complexity of O(n).add(int idx, T data)
has a time complexity of O(n).Operation | ArrayList | LinkedList (no tail ptr) | LinkedList (with tail ptr) |
---|---|---|---|
insertFront | O(N) | O(1) | O(1) |
removeFront | O(N) | O(1) | O(1) |
insertBack | O(1)* | O(N) | O(1) |
removeBack | O(1) | O(N) | O(1) |
getByIndex | O(1) | O(N) | O(N) |
searchByValue | O(\lg N) or O(N) | O(N) | O(N) |
Fast Sort | O(N*\lg(N)) | O(N*\lg(N)) | O(N*\lg(N)) |
Slow Sort | O(N^2) | O(N^2) | O(N^2) |
toString (w/SB) | O(N) | O(N) | O(N) |
toString (no SB) | O(N^2) | O(N^2) | O(N^2) |
Implementation of a binary tree node:
class TreeNode<E> {
TreeNode<E> leftChild;
TreeNode<E> rightChild;
E data;
}
Insert Implementation:
public void insert(E data) {
if (data.compareTo(this.data) < 0) {
if (leftChild == null)
leftChild = new TreeNode<>(data);
else
leftChild.insert(data);
} else {
if (rightChild == null)
rightChild = new TreeNode<>(data);
else
rightChild.insert(data);
}
}
Search Implementation:
public boolean search(E data) {
if (data.compareTo(this.data) < 0) {
if (leftChild == null)
return false;
else
return leftChild.search(data);
} else if (data.compareTo(this.data) > 0) {
if (rightChild == null)
return false;
else
return rightChild.search(data);
} else {
return true;
}
}
Inorder: A B C D E F Z
Preorder: E B A D C F Z
Postorder: A C D B Z F E
public void inOrder() {
if (leftChild != null)
leftChild.inOrder();
System.out.println(data);
if (rightChild != null)
rightChild.inOrder();
}