/**
* @Title: LinkedList.java
* @Description: 双向链表的实现
* @author glorychou
* @date 2017年2月24日 上午12:23:00
*/
package per.zyf.bds;
/**
* LinkedList的存储结构其实就是链表
* @author glorychou
*
* @param <E>
* @see per.zyf.bds.List<E>
*/
/**
* @author glorychou
*
* @param <E>
*/
/**
* @author glorychou
*
* @param <E>
*/
public class LinkedList<E> implements List<E> {
// 链表头
private Node<E> first;
// 链表尾
private Node<E> last;
// 链表大小
private int size;
/*
* @see per.zyf.bds.List#add(java.lang.Object)
*/
@Override
public boolean add(E e) {
linkLast(e);
return true;
}
/*
* @see per.zyf.bds.List#add(int, java.lang.Object)
*/
@Override
public boolean add(int index, E e) {
// 判断索引是否在合理的位置
rangeCheck(index);
// 索引值为链表长度,则添加到链表末尾
if (index == size) {
linkLast(e);
} else {
// 找到索引指定的节点,然后将新节点插入该节点后面
final Node<E> p = node(index);
final Node<E> newNode = new Node<>(p, e, p.next);
p.next = newNode;
size++;
}
return true;
}
/*
* @see per.zyf.bds.List#get(int)
*/
@Override
public E get(int index) {
return node(index).item;
}
/* (non-Javadoc)
* @see per.zyf.bds.List#remove(int)
*/
@Override
public E remove(int index) {
rangeCheck(index);
Node<E> p = node(index);
E e = p.item;
// 所需删除节点的前面有节点,则改变前一节点的下一跳
if(p.prev != null)
p.prev.next = p.next;
// 所需删除节点的后面有节点,则改变后一节点的上一跳
if(p.next != null)
p.next.prev = p.prev;
// 清空数据
p.prev = null;
p.item = null;
p.next = null;
size--;
return e;
}
/**
* @Description: 在链表头部增加节点
* @param e 新节点数据
* @return void 返回类型
*/
public void addFirst(E e) {
final Node<E> newNode = new Node<>(null, e, first);
first.prev = newNode;
size++;
}
/**
* @Description: 移除首节点
* @return E 所删除节点的数据
*/
public E removeFirst() {
if(first != null) {
final E e = first.item;
final Node<E> n = first.next;
if(n != null)
n.prev = null;
// 清空数据,让GC来回收内存
first.item = null;
first.next = null;
// 指定新的头节点
first = n;
size--;
return e;
} else
return null;
}
/**
* @Description: 删除最后一个节点
* @return 设定文件
* @return E 所删除数据
* @throws
*/
public E removeLast() {
if(last != null) {
final E e = last.item;
final Node<E> p = last.prev;
if(p != null)
p.next = null;
// 清空数据,让GC来回收内存
last.item = null;
last.prev = null;
// 指定新的尾节点
last = p;
size--;
return e;
} else
return null;
}
/* (non-Javadoc)
* @see per.zyf.bds.List#size()
*/
@Override
public int size() {
return size;
}
/* (non-Javadoc)
* @see per.zyf.bds.List#isEmpty()
*/
@Override
public boolean isEmpty() {
return true;
}
/**
* @Description: 在链尾增加节点
* @param e 新节点数据
* @return void 返回类型
*/
private void linkLast(E e) {
// 保存旧链尾节点
final Node<E> p = last;
// 创建新节点,并将新节点设置为链尾节点
final Node<E> newNode = new Node<>(p, e, null);
last = newNode;
// 若链表无节点,则将新节点设置为表头节点
if (p == null)
first = newNode;
else // 若链表已经有节点,则将新节点设置为表尾节点
p.next = newNode;
// 表长度加一
size++;
}
/***
*
* @Description: 索引范围检查
* @param index 索引
* @return void
*/
private void rangeCheck(int index) {
if (index < 0 || index > size)
throw new IndexOutOfBoundsException("Index: " + index + ", Size: " + size);
}
/**
* @Description: 获取索引位置的节点
* @param index 索引
* @return Node<E> 指定的节点
*/
private Node<E> node(int index) {
// 判断索引是否在合理的位置
rangeCheck(index);
Node<E> specifyNode;
// 根据判断索引位置在链表的前半部还是后半部,选择不同的检索方式获取指定节点
if(index < (size >> 1)) {
specifyNode = first;
for (int i = 0; i < index; i++)
specifyNode = specifyNode.next;
} else {
specifyNode = last;
for (int i = 0; i > index; i--)
specifyNode = specifyNode.prev;
}
return specifyNode;
}
// 链表节点
private static class Node<E> {
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E e, Node<E> next) {
this.prev = prev;
this.item = e;
this.next = next;
}
}
}