动态数组的缺点
- 可能会造成内存空间的大量浪费。
单向链表
- 链表是一种
链式存储的线性表,所有元素的内存地址不一定是连续的。
链表的设计
- 首先包含一个
size:记录元素的个数
- 其次拥有一个
Node对象,包含element、next的引用
- 链表类应该 有一个
first(head)的引用。
链表的接口设计
链表的 clear()操作
- 只需要将 first 引用设置为
null
- 当 first 元素被 释放后,其
next的引用无效,接着其他元素相继释放。
添加元素
- 需要将新元素的next的指针指向 prev.next元素,然后将prev.next指向新元素
- 注意判断是否为第一个节点
- 我们可以添加一个虚拟头节点,统一所有的操作。
删除元素
- prev.next 直接指向要删除元素的next元素
public class LinkedList<E> extends AbstractList<E> {
private Node<E> first;
@Override
public int indexOf(E element) {
if (element == null) {
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (node.element == null) {
return i;
}
node = node.next;
}
} else {
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (element.equals(node.element)) {
return i;
}
node = node.next;
}
}
return -1;
}
@Override
public boolean contains(E element) {
return false;
}
@Override
public E get(int index) {
return node(index).element;
}
public E set(int index, E element) {
Node<E> node = node(index);
E oldValue = node.element;
node.element = element;
return oldValue;
}
@Override
public void add(E element) {
add(size, element);
}
@Override
public void add(int index, E element) {
rangeCheckForAdd(index);
if (index == 0) {
first = new Node<>(element, first);
} else {
Node<E> prev = node(index - 1);
prev.next = new Node<>(element, prev.next);
}
size++;
}
@Override
public E remove(int index) {
rangeCheck(index);
Node<E> delNode = first;
if (index == 0) {
first = first.next;
} else {
Node<E> prev = node(index - 1);
delNode = prev.next;
prev.next = delNode.next;
}
return delNode.element;
}
@Override
public void clear() {
first = null;
size = 0;
}
private Node<E> node(int index) {
rangeCheck(index);
Node<E> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[");
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (i != 0) {
sb.append(", ");
}
sb.append(node.element.toString());
node = node.next;
}
sb.append("]");
return sb.toString();
}
private static class Node<E> {
E element;
Node<E> next;
public Node(E element, Node<E> next) {
this.element = element;
this.next = next;
}
}
}
双向链表
双向链表的实现
public class LinkedList<E> extends AbstractList<E> {
private Node<E> first;
private Node<E> last;
@Override
public E get(int index) {
return node(index).element;
}
@Override
public E set(int index, E element) {
rangeCheck(index);
Node<E> node = node(index);
E oldValue = node.element;
node.element = element;
return oldValue;
}
@Override
public void add(E element) {
add(size, element);
}
@Override
public void add(int index, E element) {
rangeCheckForAdd(index);
if (index == size) {
Node<E> oldLast = last;
last = new Node<>(element, oldLast, null);
if (oldLast == null) {
first = last;
} else {
oldLast.next = last;
}
} else {
Node<E> next = node(index);
Node<E> prev = next.prev;
Node<E> newNode = new Node<E>(element, prev, next);
next.prev = newNode;
if (prev == null) {
first = newNode;
} else {
prev.next = newNode;
}
}
size++;
}
@Override
public E remove(int index) {
rangeCheck(index);
Node<E> delNode = node(index);
Node<E> next = delNode.next;
Node<E> prev = delNode.prev;
if (prev == null) {
first = next;
} else {
prev.next = next;
}
if (next == null) {
last = prev;
} else {
next.prev = prev;
}
size--;
return delNode.element;
}
@Override
public int indexOf(E element) {
Node<E> node = first;
if (element == null) {
for (int i = 0; i < size; i++) {
if (node.element == null)
return i;
node = node.next;
}
} else {
for (int i = 0; i < size; i++) {
if (element.equals(node.element))
return i;
node = node.next;
}
}
return -1;
}
@Override
public void clear() {
first = null;
last = null;
size = 0;
}
private Node<E> node(int index) {
Node<E> node = null;
if (index < (size >> 1)) {
node = last;
for (int i = 0; i < index; i++) {
node = node.next;
}
} else {
node = last;
for (int i = size - 1; i > index; i--) {
node = node.prev;
}
}
return node;
}
private static class Node<E> {
E element;
Node<E> prev;
Node<E> next;
public Node(E element, Node<E> prev, Node<E> next) {
this.element = element;
this.next = next;
this.prev = prev;
}
}
}