双向链表相对于单向链表的优点:
1、单向链表在需要对列表尾部进行操作时,需要通过遍历的方式获取尾部的结点,很浪费时间
2、对于需要频繁使用deleteFromTail()和addToTail()方法的程序,程序效率会非常低
3、双向链表存储了每个结点前面的结点,在对尾部进行操作时,能非常方便的获取尾部的结点信息,方便对尾部进行操作,大大提高了程序效率
4、但是,双向链表比单向链表多存储了一个对象的引用,空间复杂度更高
下方是Java代码:
package com.DoublyLinkedList;
//双向链表类
public class DoublyLinkedList {
Node head; //链表头结点引用
Node tail; //链表尾结点引用
int length; //链表长度
//构造函数
public DoublyLinkedList(){
head = tail = null;
length = 0;
}
//判断链表是否为空
int isEmpty(){
return head == null?1:0;
}
//判断链表是否包含某个值
int contains(int value){
//遍历链表查找值
for (Node now=head; now!=null; now=now.next)
if (now.value == value)
return 1;
return 0;
}
//向链表头添加结点
void addToHead(int value){
//如果链表为空,直接添加
if (head == null)
head = tail = new Node(value, null, null);
else
//链表不为空,添加结点,更新head
head = head.pre = new Node(value, null, head);
length++;
}
//向链表尾添加结点
void addToTail(int value){
//如果链表为空,直接添加
if (head == null)
head = tail = new Node(value, null, null);
//链表不为空,添加结点,更新tail
else{
tail = tail.next = new Node(value, tail, null);
}
length++;
}
//向指定下标添加结点
void addNode(int value, int index){
//如果指定下标不合法,直接返回
if (index > length+1 || index <= 0) return ;
//如果链表为空,且指定下标不是1,直接返回
if (head==null && index!=1)
return ;
//如果链表为空,需要新加入结点
if (head==null && index==1){
head = tail = new Node(value, null, null);
}
//如果链表不为空,需要在头部加入结点
else if (index==1)
head = head.pre = new Node(value, null, head);
//链表不为空,在链表中加入结点
else {
int cnt = 0;
Node aheadOfAdd=head;
//找到要加入结点的前一个结点
for(cnt=1; cnt+1<index; cnt++)
aheadOfAdd = aheadOfAdd.next;
//如果在尾部之后加入结点,更新tail
if (aheadOfAdd == tail)
tail = tail.next = new Node(value, tail, null);
//否则直接加入
else
aheadOfAdd.next = aheadOfAdd.next.pre = new Node(value, aheadOfAdd, aheadOfAdd.next);
}
length++;
}
//删除链表的第一个结点
int deleteFromHead(){
Node deletedNode = null;
//如果链表为空,直接返回
if (head == null)
return -1;
//如果链表只有一个结点,删除这个结点,更新head和tail
if (head == tail)
deletedNode = head;
//正常删除
else{
deletedNode = head;
head = head.next;
head.pre = null;
}
length--;
return deletedNode.value;
}
//删除链表的最后一个结点
int deleteFromTail(){
Node deletedNode = null;
//如果链表为空,直接返回
if (head == null)
return -1;
//如果链表只有一个结点,删除这个结点,更新head和tail
if (head == tail){
deletedNode = head;
head = tail = null;
}
//其他情况
else{
deletedNode = tail;
tail = tail.pre;
tail.next = null;
}
length--;
return deletedNode.value;
}
//按照给定下标删除结点
int deleteNode(int index){
//如果给定index明显不合法,直接返回
if (index<=0 || index>length)
return -1;
//要删除的结点
Node deletedNode = head;
//如果链表为空,直接返回
if (head == null) return -1;
//如果链表只有一个元素且要求删除其他的元素,直接返回
if (head == tail && index != 1)
return -1;
//如果链表只有一个元素且要求删除该元素,更新head和tail
if (head == tail && index == 1){
deletedNode = head;
head = tail = null;
}
//如果需要删除链表头结点
else if(index == 1){
deletedNode = head;
head = head.next;
head.pre = null;
}
//如果需要删除链表尾结点
else if(index == length){
deletedNode = tail;
tail = tail.pre;
tail.next = null;
}
//其他情况
else{
int cnt;
for(deletedNode=head,cnt=1; cnt<index; cnt++, deletedNode=deletedNode.next);
deletedNode.pre.next = deletedNode.next;
deletedNode.next.pre = deletedNode.pre;
}
length--;
return deletedNode.value;
}
//打印链表
//从前向后和从后向前打印,确保前向和后向指针完全正确
void printSelf(){
System.out.print("DoublyLinkedList: [");
for (Node now=head; now!=null; now=now.next)
System.out.print(now.value + " ");
System.out.print("] Backside front: [");
for (Node now=tail; now!=null; now=now.pre)
System.out.print(now.value + " ");
System.out.print("]\n\t\t");
String str = String.format("Head: %d\t\ttail: %d\t\tLength: %d\n", head.value, tail.value, length);
System.out.print(str);
}
//测试函数
static public void main(String[] argv) {
DoublyLinkedList list = new DoublyLinkedList();
list.addToHead(100);list.printSelf();
list.addToHead(200);list.printSelf();
list.addToTail(1);list.printSelf();
list.addToTail(2);list.printSelf();
list.addToTail(3);list.printSelf();
list.deleteFromTail();list.printSelf();
list.deleteFromTail();list.printSelf();
list.addNode(10000, 1);list.printSelf();
System.out.print("\n\n");
//list.deleteNode(1);list.printSelf();
System.out.println("empty?:" + list.isEmpty());
System.out.println("123456?: " + list.contains(123456));
System.out.println("10000?: " + list.contains(10000));
}
}
//双向链表结点类
class Node{
int value; //结点数据
Node pre; //前一个结点的引用
Node next; //后一个结点的引用
//构造函数1,最常用
public Node(int aValue){
value = aValue;
pre = null;
next = null;
}
//构造函数2
public Node(int aValue, Node aPre, Node aNext){
value = aValue;
pre = aPre;
next = aNext;
}
}