双向链表结构实现
本文转自 :双向链表代码实现和详解—java实现 有少许改动
双向链表:
双向链表是可以正向遍历链表节点和反向遍历链表节点的一种链表数据结构。在单向链表中,每个节点只有一个指向下一个节点的引用,在双向链表中节点添加一个指向前一个节点的引用,添加相应的反向遍历方法,即可实现访问前一个节点的。
添加和删除节点时需要解决四个指向(引用)操作,相对来说更复杂,但是解决好在边界处链表头部和尾部节点的添加和删除操作后,编码变得相对容易。
代码实现:
package algorithms.model;
public class DoublyLinkList<T> {
private Link<T> first;
private Link<T> last;
public DoublyLinkList(){
this.first = null;
this.last = null;
}
@SuppressWarnings("hiding")
class Link<T>{
public T val;
public Link<T> next;
public Link<T> pre;
public Link(T val){
this.val = val;
}
public void showCurrentNode(){
System.out.print(this.val+" ");
}
}
public boolean isEmpty(){
return first == null;
}
//处理好每个节点的前后指向是关键;先处理哪个节点的哪个指向问题;
public void addFirst(T value){
Link<T> newLink = new Link<T>(value);
if(isEmpty())
last = newLink; //保证last正确引用;
else{
first.pre = newLink;
newLink.next = first;
}
first = newLink;
//newLink.pre = null;
}
public void addLast(T value){
Link<T> newLink = new Link<T>(value);
if(isEmpty())
first = newLink; //保证first正确引用;
else{
last.next = newLink;
newLink.pre = last;
}
last = newLink;
//newLink.next = null;
}
//先考虑普遍性,再考虑特殊性;在找到的第一个key前面插入
public boolean addBefore(T key, T value){
Link<T> cur = first;
if(first.val == key){
addFirst(value);
return true;
}
else{
while(cur.val != key){
cur = cur.next;
if(cur == null)
return false;
}
}
//断开连接后保证断开前指向的连接还能获取到;
Link<T> newLink = new Link<T>(value);
cur.pre.next = newLink;
newLink.pre = cur.pre;
newLink.next = cur;
cur.pre = newLink;
return true;
}
public boolean addAfter(T key, T value){
Link<T> cur = first;
while(cur.val != key && cur != null)
cur = cur.next;
if(cur == null)
return false;
if(cur == last){
addLast(value);
return true;
}
Link<T> newLink = new Link<T>(value);
cur.next.pre = newLink;
newLink.next = cur.next;
cur.next = newLink;
newLink.pre = cur;
return true;
}
public void deleteFirst(){
if(first.next == null) //链表没有节点或者仅含有一个节点时;
last = null;
else
first.next.pre = null;//链表至少含有两个节点时;
first = first.next;
}
public void deleteLast(){
if(first.next == null) //链表没有节点或者仅含有一个节点时;
first = null;
else
last.pre.next = null;//链表至少含有两个节点时;
last = last.pre;
}
public Link<T> deleteKey(T key){//删除第一找到的键
Link<T> cur = first;
while(cur.val != key){
cur = cur.next;
if(cur == null)
return null;
}
if(cur == first)
first = first.next; //保证first引用的指向正确;
else
cur.pre.next = cur.next;
if(cur == last)
last = last.pre; //保证last引用的指向正确;
else
cur.next.pre = cur.pre;
return cur;
}
public T showPre(T value){
Link<T> cur = first;
if(value == first.val)
return null;
while(cur.next.val != value){
cur = cur.next;
if(cur.next == null)
return null;
}
return cur.val;
}
public void showForward(){
Link<T> cur = first;
while(cur != null){
cur.showCurrentNode();
cur = cur.next;
}
System.out.println();
}
public void showBackward(){
Link<T> cur = last;
while(cur != null){
cur.showCurrentNode();
cur = cur.pre;
}
System.out.println();
}
public static void main(String[] args) {
DoublyLinkList<Integer> d = new DoublyLinkList<Integer>();
for(int i = 1; i < 6; i++)
d.addFirst(i);
for(int i = 6; i < 10; i++)
d.addLast(i);
d.showForward();
d.showBackward();
System.out.println(d.showPre(4));
System.out.println(d.showPre(0));
d.deleteFirst();
d.showForward();
d.deleteLast();
d.showForward();
d.deleteKey(1);
d.showForward();
d.addAfter(6, 11);
d.showForward();
d.addBefore(6, 12);
d.showForward();
}
}
输出:
5 4 3 2 1 6 7 8 9
9 8 7 6 1 2 3 4 5
5
null
4 3 2 1 6 7 8 9
4 3 2 1 6 7 8
4 3 2 6 7 8
4 3 2 6 11 7 8
4 3 2 12 6 11 7 8