链表是非常常见的一类线性结构的数据结构,每个节点包含有指针域和数据域,常见的包括单项列表、双向列表、循环列表。这篇文章将详细介绍双向链表。
双端链表不同于单向链表仅有一个指针域指向下一个节点,而是同时持有下一个和上一个指针域,分别指向下一个和上一个节点,如下:
本文将介绍双向链表的插入节点、根据位置插入节点、删除头结点、删除尾节点、删除指定位置节点,查看链表元素、查看头结点、查看尾节点、查看链表长度、判断链表是否为空。
链表的节点表示:
class Node {
//数据域
public String data;
//上一个节点
public Node prev;
//下一个节点
public Node next;
public Node(String data) {
this.data = data;
}
}
在创建好链表节点之后下来看链表的构造方法和成员变量,成员方法包括一个完整链表的头结点、尾节点以及链表的长度:
class DoubleLinkedList {
private Node tailNode;
private Node headNode;
private int length;
public DoubleLinkedList() {
tailNode = null;
headNode = null;
}
}
1、插入元素:尾部插入
/**
* 插入元素
*/
public void insert(String value) {
if (value == null || value.isEmpty()) {
throw new NullPointerException();
}
Node node = new Node(value);
if (headNode == null) {
headNode = node;
tailNode = headNode;
tailNode.prev = null;
tailNode.next = null;
} else {
tailNode.next = node;
node.prev = tailNode;
tailNode = node;
}
length++;
}
2、插入元素:指定位置
/**
* 根据位置插入节点
*/
public void insert(int position, String value) {
//创建要插入的节点
Node node = new Node(value);
if (position >= length) {
//直接插入到尾部
insert(value);
return;
}
if (position == 0) {
Node firstNode = headNode;
headNode = node;
headNode.prev = null;
headNode.next = firstNode;
firstNode.prev = node;
} else {
//获取到该位置的节点
Node nodeByPosition = getNodeByPosition(position);
//上一个节点
Node prevNode = nodeByPosition.prev;
//下一个节点
Node nextNode = nodeByPosition.next;
//上一个节点next指向他
prevNode.next = node;
//他的上一个节点指向prev
node.prev = prevNode;
//他的下一个节点指向next
node.next = nodeByPosition;
//下一个节点的pre指向他
nodeByPosition.prev = node;
}
length++;
}
3、删除元素:删除头部
/**
* 删除链表头部
*/
public Node deleteHead() {
//获取根节点的下一个节点
Node nextNode = null;
Node firstNode = null;
if (headNode != null) {
nextNode = headNode.next;
} else {
return null;
}
if (nextNode == null) {
headNode = null;
} else {
firstNode = headNode;
nextNode.prev = null;
headNode.next = null;
headNode = nextNode;
}
length--;
return firstNode;
}
4、删除元素:删除尾部
/**
* 删除链表尾部
*/
public Node deleteTail() {
//获取根节点的下一个节点
Node preNode = null;
Node lastNode = null;
if (tailNode != null) {
preNode = tailNode.prev;
} else {
return null;
}
if (preNode == null) {
headNode = tailNode;
} else {
lastNode = tailNode;
tailNode.prev = null;
preNode.next = null;
tailNode = preNode;
}
length--;
return lastNode;
}
5、删除元素:删除指定位置
/**
* 删除指定位置节点
*/
public Node deleteByPosition(int position) {
if (position >= length) {
throw new IllegalArgumentException(" position must be less than linklist all length ");
} else {
Node nodeByPosition = getNodeByPosition(position);
if (position == 0) {
//删除头结点
Node deleteHead = deleteHead();
return deleteHead;
} else if (position == length - 1) {
//删除尾节点
Node deleteTail = deleteTail();
return deleteTail;
} else {
//有头有尾
//获取该节点的前一个和后一个节点
Node prevNode = nodeByPosition.prev;
Node nextNode = nodeByPosition.next;
prevNode.next = nextNode;
nextNode.prev = prevNode;
length--;
return nodeByPosition;
}
}
}
6、根据位置获取节点
/**
* 根据位置获取节点
*/
public Node getNodeByPosition(int position) {
Node current = headNode;
if (position >= length) {
throw new IllegalArgumentException(" position must be less than linklist all length ");
} else {
for (int i = 0; i < length; i++) {
if (i == position) {
break;
}
if (current != null) {
current = current.next;
}
}
}
return current;
}
7、查看所有节点
/**
* 打印所有节点
*/
public void displayAll() {
Node current = headNode;
while (current != null) {
System.out.print(current.data + " ");
current = current.next;
}
}
8、查看头结点
/**
* 查看头结点
*/
public Node getheadNode() {
return headNode;
}
9、查看尾节点
/**
* 查看当尾节点
*/
public Node getTailNode() {
return tailNode;
}
10、获取链表长度
/**
* 链表长度
*/
public int length() {
return length;
}
11、判断链表是否为空
/**
* 判断链表是否为空
*/
public boolean isEmpty() {
return length == 0;
}