(1)如果为每个节点保留两个引用prve和next,让prev指向当前节点的上一个节点,让next指向当前节点的下一个节点。此时链表既可以向前依次访问每个节点,也可以向后依次访问每个节点,这种形式的节点称为双向链表。
(2)双向链表的查找
因为双向链表既可以向前搜索也可以向后搜索,当被搜索节点更靠近head或者tail中的某一端时,就从那一端开始搜索 index<size/2从head开始搜索,index>size/2从tail开始搜索
(3)双向链表的插入
(4)双向链表的删除
实现
public class DoubleLinkedList<T>
{
//节点类
private class Node
{
//每个节点有三个成员变量
private T data;
private Node next;
private Node prev;
public Node()
{}
public Node(T data,Node next,Node prev)
{
this.data = data;
this.next = next;
this.prev = prev;
}
}
//分别用来指向链表的头节点、尾节点、保存链表的长度
private Node head;
private Node tail;
private int size;
//链表的构造函数
public DoubleLinkedList()
{
head = null;
tail = null;
}
public DoubleLinkedList(T element)
{
head = new Node(element,null,null);
tail = head;
size++;
}
//链表的长度
public int length()
{
return size;
}
//查找指定索引处的节点
private Node getNodeByIndex(int index)
{
if(index < 0 || index > size-1)
{
throw new IndexOutOfBoundsException("双向链表索引越界");
}
if(index < size / 2)//如果索引在前半段的位置则从头节点开始遍历
{
Node current = head;
for (int i = 0; i < size / 2 && current != null; i++,current = current.next)
{
if(i == index)
{
return current;
}
}
}
else
{
Node current = tail;
for (int i = size-1; i > size / 2 && current!= null; i++,current = current.prev)
{
if(i == index )
{
return current;
}
}
}
return null;
}
//查找指定元素的索引位置
public int locateIndexByElement(T element)
{
Node current = head;
for (int i = 0; i < size && current != null; i++,current = current.next)
{
if(current.data == element)
{
return i;
}
}
return -1;
}
//插入 将指定的元素插入到指定的位置处
public void insert(T element,int index)
{
if(index < 0 || index > size )
{
throw new IndexOutOfBoundsException("双向链表插入索引越界");
}
if(null == head)
{
add(element);
}
else
{
if(index == 0)
{
addAtHead(element);
}
else
{
Node prev = getNodeByIndex(index-1);//获取要出入位置的前一个节点
Node next = prev.next;//第index位置的节点将会变为新节点的下一个节点
Node newNode = new Node(element,next,prev);//新节点的前一个节点是prev 后一个节点是next
prev.next = newNode;
next.prev = newNode;
size++;
}
}
}
//插入 尾差法
public void add(T element)
{
if (head == null)
{
addAtHead(element);
}
else
{
Node newNode = new Node(element,null,tail);
tail.next = newNode;
tail = newNode;
}
size++;
}
//插入 头差法
public void addAtHead(T element)
{
Node newNode = new Node(element,head,null);
if(head==null)
{
head = newNode;
tail = head;
}
else
{
head.prev = newNode;
head = newNode;
}
size++;
}
//删除
public T delete(int index)
{
if(index < 0 || index > size)
{
throw new IndexOutOfBoundsException("双向链表插入索引越界");
}
Node deleteNode;
if(index == 0)//若是删除第一个节点 要重新得到头节点
{
deleteNode = head;
head = head.next;//新的头节点的是原来头节点的下一个节点
deleteNode.next = null;
}
else
{
Node prev = getNodeByIndex(index-1);//找到要删除节点的前一个节点
deleteNode = prev.next;//找到要删除的节点
prev.next = deleteNode.next;//把prev的next指向要删除节点的下一个节点
if(deleteNode.next != null)
{
deleteNode.next.prev = prev;//要删除节点的下一个节点指向的前一个节点是prev
}
deleteNode.prev = null;
deleteNode.next = null;
}
size--;
return deleteNode.data;
}
//判断链表是否为空
public boolean isEmpty()
{
return size == 0;
}
//清空线性变
public void clear()
{
head = null;
tail = null;
size = 0;
}
public String toString()
{
if(isEmpty())
{
return "[]";
}
else
{
StringBuilder sb = new StringBuilder("[");
for ( Node current = head;current != null; current = current.next)
{
sb.append(current.data.toString() + ",");
}
int len = sb.length();
return sb.delete(len-1,len).append("]").toString();
}
}
}
测试
public class DoubleLlinkedListTest
{
public static void main(String[] args)
{
DoubleLinkedList<String> list = new DoubleLinkedList<String>();
list.addAtHead("HELLO");
list.add("world");
System.out.println(list);
list.insert("111",1);
list.insert("222",1);
System.out.println(list);
list.addAtHead("head");
System.out.println(list);
list.delete(2);
System.out.println(list);
list.clear();
System.out.println(list );
}
}
结果
[HELLO,world]
[HELLO,222,111,world]
[head,HELLO,222,111,world]
[head,HELLO,111,world]
[]