原创作品,转载请注明出处。
概述
1.基于双向链表实现,容量无限制。但双向链表本身使用了更多空间,也需要额外的链表指针操作。
2.按下标访问元素—get(i)/set(i,e) 要悲剧的遍历链表将指针移动到位(如果i>数组大小的一半,会从末尾移起),时间复杂度O(N/2)
3.插入和删除:只须修改前后节点的指针即可,但还是要遍历部分链表的指针才能移动到下标所指的位置,只有在链表两头的操作—add(), addFirst(),removeLast()或用iterator()上的remove()能省掉指针的移动
链表结构定义
public class LinkedList<E> extends AbstractSequentialList<E>
implements List<E>, Deque<E>, Cloneable, java.io.Serializable {
transient int size = 0;
transient Node<E> first;
transient Node<E> last;
// 其余省略
}
典型的双向链表实现,看个示例代码:
LinkedList<String> list = new LinkedList<String>();
list.add("语文: 1");
list.add("数学: 2");
list.add("英语: 3");
结构也相对简单一些,如下图所示:
结构图add方法
public boolean add(E e) {
linkLast(e);
return true;
} void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
新增元素总是添加到链表末尾。
set和get方法
public E set(int index, E element) {
checkElementIndex(index);
Node<E> x = node(index);
E oldVal = x.item;
x.item = element;
return oldVal;
} public E get(int index) {
checkElementIndex(index);
return node(index).item;
}
这两个方法都用node(index)方法找链表节点,查找的方法会比对索引下标,如果小于size的一半就从头部开始查找,如果大于size的一半就从尾部从后向前查找,实现时间复杂度为O(n/2),提高效率,
Node<E> node(int index) {
// assert isElementIndex(index);
if (index < (size >> 1)) {
Node<E> x = first;
for (int i = 0; i < index; i++)
x = x.next;
return x;
} else {
Node<E> x = last;
for (int i = size - 1; i > index; i--)
x = x.prev;
return x;
}
}
白天在加班加点的干活,还要抽出时间成为技术知识的分享者,分享不易。
喜欢我的文章请点赞,欢迎打赏,成为我们坚持的动力。