今天把jdk1.8的LinkedList源码看了一下,发现使用的数据结构就是双向链表。自己也动手实现了一个简易版本的双向链表
package com.natsuki.lesson2;
/**
* @Author:
* @Date: 2018-12-29
* @Description: 自己根据双向链表定义一个简易linkedList
*/
public class MyLinkedList<E> {
/**
* 链表的元素大小
*/
int size = 0;
/**
* 链表的头节点
*/
private Node<E> first;
/**
* 链表的尾节点
*/
private Node<E> last;
MyLinkedList() {
}
/**
* 链表添加元素
*
* @param index 插入元素的位置
* @param element 插入元素
*/
public void add(int index, E element) {
if (checkPositionIndex(index)) {
if (index == size) {
this.add(element);
} else {
this.linkBefore(element, getNode(index));
}
}
}
/**
* 在指定节点之前插入新节点
*
* @param element
* @param node
*/
public void linkBefore(E element, Node<E> node) {
Node<E> prev = node.prev;
Node<E> newNode = new Node<>(element, prev, node);
node.prev = newNode;
if (prev==null){
first = newNode;
} else {
prev.next = newNode;
}
size++;
}
/**
* 获取指定位置的节点
*
* @param index 位置
* @return 指定位置的节点
*/
public Node<E> getNode(int index) {
//如果index在链表前半部分,从头节点开始遍历,否则从尾节点开始遍历
if (index < (size >> 1)) {
Node<E> p = first;
for (int i = 0; i < index; i++) {
p = p.next;
}
return p;
} else {
Node<E> p = last;
for (int i = size - 1; i > index; i--) {
p = p.prev;
}
return p;
}
}
/**
* 插入一个新元素到底部
*
* @param element
*/
public void add(E element) {
//先将尾节点的位置保存一下
Node<E> l = last;
last = new Node<>(element, l, null);
//判断一下l是否为空,为空的话说明这插入的是第一个节点
if (l != null) {
l.next = last;
last.prev = l;
} else {
first = last;
}
size++;
}
/**
* @param index 操作元素的位置
* @return true表示操作位置没有问题
*/
private boolean checkPositionIndex(int index) {
return index >= 0 && index <= this.size;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
Node<E> p = first;
while (p != null) {
E item = p.element;
p = p.next;
sb.append(item).append("\t");
}
return sb.toString();
}
private 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.prev = prev;
this.next = next;
}
}
}
代码的注释已经很详细了,这里要注意重载了add的方法,默认没有参数是向链表尾部插入新的节点。