数据结构上有关双向链表的原理:在单链表(每个节点含后继节点)的每个节点里再增加一个指向其前趋的节点,这样形成的链表含有指向前趋和后继两个方向的链,称为双向链表。网上找了个例子研究了下(http://www.cnblogs.com/matrix1024/archive/2011/12/31/2308380.html),解决原作者的两端极限时出现的空指针问题。
上代码:
Node实体类:
/**
* @projectName:List
* @fileName:Node.java
* @packageName:club.younge.list
* @date:2016年8月25日上午12:17:17
* @copyright (c) 2016, heqy@finansir.nt All Rights Reserved.
*
*/
package club.younge.list;
/**
* @className:Node
* @function: 双向链表节点实体类
* @reason:
* @date: 2016年8月25日 上午12:17:17
* @author Younge
* @version
* @since JDK 1.8
* @see
*/
public class Node<T> {
private T data;
private Node<T> next;
private Node<T> prev;
public Node() {
}
public Node(T data) {
this.data = data;
}
//实现equals和hashCode, 两个最好一同改写
public boolean equals(Node<T> node) {
if (data.equals(node.getData())) {
return true;
}
return false;
}
@Override
public int hashCode() {
return data.hashCode();
}
@Override
public String toString() {
return data.toString();
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
public Node<T> getNext() {
return next;
}
public void setNext(Node<T> next) {
this.next = next;
}
public Node<T> getPrev() {
return prev;
}
public void setPrev(Node<T> prev) {
this.prev = prev;
}
}
BirectionalLinkedList链表操作类:
/**
* @projectName:List
* @fileName:BirectionalLinkedList.java
* @packageName:club.younge.list
* @date:2016年8月25日上午12:22:51
* @copyright (c) 2016, heqy@finansir.nt All Rights Reserved.
*
*/
package club.younge.list;
/**
* @className:BirectionalLinkedList
* @function: 双向链表操作类
* @reason:
* @date: 2016年8月25日 上午12:22:51
* @author Younge
* @version
* @since JDK 1.8
* @see
*/
public class BirectionalLinkedList<T> {
private Node<T> head;
private Node<T> tail;
public BirectionalLinkedList() {
head = new Node<T>();
tail = new Node<T>();
}
public void insertAfterHead(Node<T> data) {
if (head.getNext() == null) {// 头节点后还没有节点,说明链表为空,也可以通过尾节点的前一个节点是否为空作出判断
head.setNext(data);
data.setPrev(head);
tail.setPrev(data);
data.setNext(tail);
} else {
data.setNext(head.getNext()); // 改变该节点的后一个节点为头节点的下一个节点---该节点下一个节点
head.getNext().setPrev(data); // 改变头节点的下一个节点的前一个节点为该节点---下一个节点的前一个节点
// 打通该节点后的两个指向
head.setNext(data); // 最后将头节点的下一个节点指向该节点
// (若一开始指向该节点,则无法获取头节点的原始下一节点,觉得思路不清晰,可以分离出头节点的原始下一节点到一临时节点)
data.setPrev(head); // 头节点没值
}
}
public void insertBeforeTail(Node<T> data) {
if (isEmpty()) {
tail.setPrev(data);
data.setNext(tail);
head.setNext(data);
data.setPrev(head);
} else {
data.setPrev(tail.getPrev());
tail.getPrev().setNext(data);
tail.setPrev(data);
data.setNext(tail); // 尾节点没值
}
}
// 添加某个节点到指定的数值的节点后面
public void insertAfter(Node<T> data, T key) {
if (isEmpty()) {
System.out.println("The biretional linked list is empty!");
} else {
Node<T> temp = head;
while (temp.getNext() != null) {
if (temp.getNext().getData().equals(key)) {
/*if (temp.getNext().getNext() == null) {
temp.getNext().setNext(tail);
}*/
data.setNext(temp.getNext().getNext()); // 该节点的下一个节点
temp.getNext().getNext().setPrev(data); // 下一个节点的前一个节点
temp.getNext().setNext(data);
data.setPrev(temp.getNext());
break;
}
temp = temp.getNext();
}
}
}
// 添加某个节点到指定的数值的节点前面
public void insertBefore(Node<T> data, T key) {
if (isEmpty()) {
System.out.println("The biretional linked list is empty!");
} else {
Node<T> temp = head;
while (temp.getNext() != null) {
if (temp.getNext().getData().equals(key)) {
data.setNext(temp.getNext());
temp.getNext().setPrev(data);
temp.setNext(data); // temp.getNext().getPrev().setNext(data);
// //前一个节点的下一个节点
data.setPrev(temp); // data.setPrev(temp.getNext().getPrev());
// //该节点的前一个节点
break;
}
temp = temp.getNext();
}
}
}
public void traverseFromHead() {
if (isEmpty()) {
System.out.println("The biretional linked list is empty!");
} else {
Node<T> temp = head;
while (temp.getNext() != null) {
if (temp.getNext() == tail) {
break;
}
System.out.print(temp.getNext() + "--->");
temp = temp.getNext();
}
System.out.println();
}
}
public void traverseFromTail() {
if (isEmpty()) {
System.out.println("The biretional linked list is empty!");
} else {
Node<T> temp = tail;
while (temp.getPrev() != null) {
if (temp.getPrev() == head) {
break;
}
System.out.print(temp.getPrev() + "--->");
temp = temp.getPrev();
}
System.out.println();
}
}
public boolean isEmpty() {
if (head.getNext() == null || tail.getPrev() == null) {
return true;
}
return false;
}
}
测试类:
/**
* @projectName:List
* @fileName:BirectionalLinkedListTest.java
* @packageName:club.younge.test
* @date:2016年8月25日上午1:10:52
* @copyright (c) 2016, heqy@finansir.nt All Rights Reserved.
*
*/
package club.younge.test;
import club.younge.list.BirectionalLinkedList;
import club.younge.list.Node;
/**
* @className:BirectionalLinkedListTest
* @function: 双向链表测试类
* @reason: TODO ADD REASON.
* @date: 2016年8月25日 上午1:10:52
* @author Younge
* @version
* @since JDK 1.8
* @see
*/
public class BirectionalLinkedListTest {
public static void main(String[] args) {
final int MAX = 6;
BirectionalLinkedList<Integer> list = new BirectionalLinkedList<Integer>();
System.out.println( "Form insert:");
Node<Integer> node;
for (int i = 0; i < MAX; i++) {
node = new Node<Integer>(i);
System.out.print(node + "--->");
list.insertAfterHead(node);
}
System.out.println("\nTraverse from head:");
list.traverseFromHead();
System.out.println("Traverse from tail:");
list.traverseFromTail();
Node<Integer> node1 = new Node<Integer>(33);
list.insertAfter(node1, 0);
System.out.println("\nTraverse from head(insert 33 after 3):");
list.traverseFromHead();
System.out.println("Traverse from tail(insert 33 after 3):");
list.traverseFromTail();
Node<Integer> node2 = new Node<Integer>(66);
list.insertBefore(node2, 5);
System.out.println("\nTraverse from head(insert 66 before 5):");
list.traverseFromHead();
System.out.println("Traverse from tail(insert 66 before 5):");
list.traverseFromTail();
}
}
测试结果:
Form insert:
0--->1--->2--->3--->4--->5--->
Traverse from head:
5--->4--->3--->2--->1--->0--->
Traverse from tail:
0--->1--->2--->3--->4--->5--->
0--->1--->2--->3--->4--->5--->
Traverse from head:
5--->4--->3--->2--->1--->0--->
Traverse from tail:
0--->1--->2--->3--->4--->5--->
Traverse from head(insert 33 after 0):
5--->4--->3--->2--->1--->0--->33--->
Traverse from tail(insert 33 after 0):
33--->0--->1--->2--->3--->4--->5--->
5--->4--->3--->2--->1--->0--->33--->
Traverse from tail(insert 33 after 0):
33--->0--->1--->2--->3--->4--->5--->
Traverse from head(insert 66 before 5):
66--->5--->4--->3--->2--->1--->0--->33--->
Traverse from tail(insert 66 before 5):
33--->0--->1--->2--->3--->4--->5--->66--->
66--->5--->4--->3--->2--->1--->0--->33--->
Traverse from tail(insert 66 before 5):
33--->0--->1--->2--->3--->4--->5--->66--->
Github:
点击打开链接