一、链表
数组有一个明显的缺点,就是会有空间的浪费。那么我们能否用多少就申请多少空间呢,链表就能够实现,但是链表的内存地址不一定是连续的。
二、链表的设计
链表的接口和arrayList是完全一样的,但是实现方式完全不一样,LinkedList有三个成员变量:size(链表的大小)、first(头指针)、Node(包含element用于存放数据,next指向下一个node)
private int size; //链表元素的个数
private Node<E> first; //第一个节点
private static class Node<E>{
E element;
Node<E> next;
public Node(E element, Node<E> next) {
this.element = element;
this.next = next;
}
}
添加元素add(index,element)
假设我们要往索引index=1的位置添加元素,那么我们需要找到index=0的节点。如何找呢,就是通过first节点一直next,这个方法就是LinkedList最重要的方法,因为增、删、改、查都要调用它。
private Node<E> node(int index){
rangeCheck(index);
Node<E> node = first;
for(int i=0;i<index;i++){
node = node.next;
}
return node;
}
添加后:
1.首先找到index = 0的节点:
Node<E> pre = node(index - 1);
2.只需要将index = 0的next指针指向新加入的Node就可以了,我们在创建节点Node node = new Node(element, pre.next)的时候,该节点的next已经指向了22。
注意:当index=0时,那么需要做特殊处理,因为它前面的节点不存在。
public void add(int index, E element) {
if(index == 0){
first = new Node(element,first);
}else{
Node<E> pre = node(index - 1);
Node node = new Node(element, pre.next);
pre.next = node;
}
size++;
}
删除元素remove(int index)
假设现在要删除index=1的节点,那么需要找到index=0的节点,然后将index=0的指针指向index=2就行了。和添加类似,删除index=0位置的节点时也需要特殊处理。
public E remove(int index) {
Node<E> node = first;
if(index == 0){
first = first.next;
}else{
Node<E> prev = node(index-1); //找到index-1位置的节点
node = prev.next; //返回的节点
prev.next = prev.next.next; //prev的next指向node的next
}
size--; //删除节点后size--
return node.element;
}
修改元素set(int index,E element)
只需要找到index位置的节点,然后赋值就行了。
public E set(int index, E element) {
Node<E> node = node(index);
node.element = element;
return node.element;
}
查找元素get(int index)
public E get(int index) {
Node<E> node = node(index);
return node.element;
}
清空元素:
public void clear() {
size = 0;
first = null;
}
二、双向链表
JDK中的LinkedList就是一个双向链表,如下图以index=2为界限,当index<2时,我们可以从左边查找,反之就从右边开始查找,这就减少了查找的次数,提升了性能。