基于LinkedList的双链表实现
使用LinkedList的优点在于新项的插入和现有项的删除都是常熟时间的操作。但缺点是他不容易做索引,因此对get的调用是非常昂贵的,所以我们得想方设法尽量减少开销。
存储节点Node
我们首先要根据双链表的特性设置相应的节点,该节点具有头节点跟尾节点还有相应的数据存放。
private static class Node<AnyType>{
public AnyType data; //存放数据
public Node<AnyType> prev; //头节点
public Node<AnyType> next; //尾节点
public Node(AnyType d,Node<AnyType>p,Node<AnyType>n)
{data=d;prev=p;next=n;} //使用构造方法进行赋值
}
链表初始化
我们首先要建立一个初始节点和一个结尾节点,并让结尾节点的pre指向初始节点,初始节点的尾节点指向结尾节点。
private int theSize;
private int modCount=0; //记录从创建以来对链表操作的次数
private Node<AnyType> beginN;
private Node<AnyType> endN;
public MyLinkedList(){doClear();}
public void clear(){doClear();}
private void doClear(){
beginN=new Node<AnyType>(null,null,null);
endN=new Node<AnyType>(null,beginN,null);
beginN.next=endN;
theSize=0;
modCount++;
}
public int size(){return theSize;}
public boolean isEmpty(){return size()==0;}
链表的增删改查
由于用户操作的时候是通过位置来实现增删改查的,所以我们需要编写多个方法也就是利用Java的方法重载对用户行为和后台处理进行一个链接。
public boolean add(AnyType x){
add(size(),x);
return true;
}
//在当前位置加入一个节点,并把当前节点的pre改为加入的这个节点
public void add(int idx,AnyType x){addBefore(getNode(idx,0,size()),x);}
public AnyType get(int idx){return getNode(idx).data;} //根据用户输入的位置,获取该位置的节点信息并返回数据
public AnyType set(int idx,AnyType x){
Node<AnyType> node=getNode(idx);
AnyType oldVal=node.data;
node.data=x;
return oldVal;
}
public AnyType remove(int idx){return remove(getNode(idx));} //用户输入想要移除的位置
public void addBefore(Node<AnyType> node,AnyType x){ //添加一个节点在 node节点和node.pre节点前
Node<AnyType> newNode=new Node<>(x,node.prev,node);
newNode.prev.next=newNode;
node.prev=newNode;
theSize++;
modCount++;
}
public AnyType remove(Node<AnyType> node){ //移除当前节点
// 把node节点的pre的next链接到node的next
node.prev.next=node.next;
//把node节点的next的pre链接到node的pre
node.next.prev=node.prev;
theSize--;
modCount++;
return node.data;
}
public Node<AnyType> getNode(int idx){return getNode(idx,0,size()-1);} //根据位置获得节点信息
public Node<AnyType> getNode(int idx,int first,int end){
Node<AnyType> node;
if(idx<first||idx>end) //r如果用户输入的位置超出界限,则抛出下标越界
throw new IndexOutOfBoundsException();
//根据idx与中间位置的比较,判断靠前还是靠后,有利于减少时间复杂度
if(idx<size()/2){
node=beginN.next;
for(int i=0;i<idx;i++)
node=node.next;
}
else {
node=endN;
for (int i=size();i>idx;i--)
node=node.prev;
}
return node;
}
迭代器的实现
@Override
public Iterator<AnyType> iterator() {
return new LinkedListIterator();
}
private class LinkedListIterator implements Iterator<AnyType>{
private Node<AnyType> current=beginN.next;
private int expectedMdoCount=modCount;
private boolean okToRemove=false;
@Override
public boolean hasNext() {
return current!=endN;
}
@Override
public AnyType next() {
if(modCount!=expectedMdoCount)
throw new ConcurrentModificationException();
if(!hasNext())
throw new NoSuchElementException();
AnyType x=current.data;
current=current.next;
okToRemove=true;
return x;
}
@Override
public void remove() {
if(modCount!=expectedMdoCount)
throw new ConcurrentModificationException();
if(!okToRemove)
throw new IllegalStateException();
BookLinkedList.this.remove(current.prev);
expectedMdoCount++;
okToRemove=false;
}
}