双向链表是一种对称结构,它克服了单链表上指针单向性的缺点,其中每一个节点即可向前引用,也可向后引用,这样可以更方便的插入、删除数据元素。
由于双向链表需要同时维护两个方向的指针,因此添加节点、删除节点时指针维护成本更大;但双向链表具有两个方向的指针,因此可以向两个方向搜索节点,因此双向链表在搜索节点、删除指定索引处节点时具有较好的性能
双向链表的每一个结点都有一条指向其后继结点的next链和一条指向其前结点的pre链。双向链表既可以从第一项开始遍历也可以从最后一项开始往前遍历,双向链表可以用下图表示:
代码的实现
import java.util.Iterator;
public class TwoWayLinkList<T> implements Iterable<T>{
//首结点
private Node head;
//最后一个结点
private Node last;
//链表的长度
private int N;
//结点类
private class Node{
//储存数据
public T data;
//指向上一个结点
public Node pre;
//指向下一个结点
public Node next;
public Node(T data,Node pre,Node next){
this.data=data;
this.pre=pre;
this.next=next;
}
}
//构造方法
public TwoWayLinkList(){
//初始化头结点和尾结点
this.head=new Node(null,null,null);
this.last=null;
//初始化元素个数
this.N=0;
}
//清空链表
public void clear(){
this.head.next=null;
this.last=null;
this.N=0;
}
//获取链表元素个数
public int length(){
return N;
}
//判断链表是否为空
public boolean isEmpty(){
return N==0;
}
//获取链表中第一个元素
public T getFirst(){
if(isEmpty()){
return null;
}
return head.next.data;
}
//获取链表最后一个元素
public T getLast(){
if(isEmpty()){
return null;
}
return last.data;
}
//插入元素t
public void insert(T t){
//链表为空的情况下
if(isEmpty()){
//创建新结点
Node newNode=new Node(t,head,null);
//新结点成为尾结点
last=newNode;
//头结点指向尾结点
head.next=last;
}else{ //链表不为空的情况下
Node oldLast=last; // 记录尾结点
Node newNode = new Node(t, oldLast, null);
//当前尾结点指向新节点
oldLast.next=newNode;
//新节点成为尾结点
last=newNode;
}
//元素个数+1
N++;
}
//指定i位置插入新结点
public void insert(int i,T t){
//找到i位置前一个结点
Node pre=head;
for(int index=0;index<i;index++){
pre=pre.next;
}
//当前结点(i位置结点)
Node curr = pre.next;
//创建新结点
Node newNode = new Node(t, pre, curr);
//i位置前一个结点的下一个结点变为新结点
pre.next=newNode;
//i位置前一个结点变为新结点
curr.pre=newNode;
//元素个数+1
N++;
}
//获取指定位置i处的元素
public T get(int i){
Node n=head.next;
for(int index=0;index<i;index++){
n=n.next;
}
return n.data;
}
//找到元素t在链表中第一次出现的位置
public int indexOf(T t){
Node n=head;
for(int index=0;n.next!=null;index++){
n=n.next;
if(n.next.equals(t)){
return index;
}
}
return -1;
}
//删除位置i处元素,并返回该元素
public T remove(int i){
//找到i位置前一个结点
Node pre=head;
for(int index=0;index<i;index++){
pre=pre.next;
}
//找到i位置结点
Node curr=pre.next;
//找到i位置下一个结点
Node nextNode = curr.next;
//i位置前一个结点的下一个结点指向i位置下一个结点
pre.next=nextNode;
//i位置下一个结点的前一个结点指向i位置前一个结点
nextNode.pre=pre;
N++;
return curr.data;
}
@Override
public Iterator<T> iterator() {
return new TIterator();
}
private class TIterator<T> implements Iterator {
private Node n;
public TIterator(){
this.n=head;
}
@Override
public boolean hasNext() {
return n.next!=null;
}
@Override
public Object next() {
n=n.next;
return n.data;
}
}
}
测试
package cn.itcast.algorithm.linearTest;
import cn.itcast.algorithm.linear.TwoWayLinkList;
public class TwoWayLinkLIstTest {
public static void main(String[] args) {
//创建双向链表对象
TwoWayLinkList<String> s1 = new TwoWayLinkList<>();
s1.insert("吴磊");
s1.insert("ASD");
s1.insert("Messi");
s1.insert(1,"詹姆斯");
for(String s:s1){
System.out.println(s);
}
System.out.println("------------------------");
System.out.println("第一个元素是:"+s1.getFirst());
System.out.println("最后一个元素是:"+s1.getLast());
System.out.println("------------------------");
//测试获取
String getResult=s1.get(1);
System.out.println("获取索引1处的结果为:"+getResult);
//测试删除
String removeResult=s1.remove(0);
System.out.println("删除的元素是:"+removeResult);
s1.clear();
System.out.println("清空后线性表中元素个数为:"+s1.length());
}
}