这一篇来写循环双链表,循环双链表,包含两个关键字:双链表,循环。
先说双链表,双链表是在单链表的基础上加上一个指向前面的指针。较之单链表,双链表可以从任意位置进行遍历,而不需要每一次遍历都要从头开始。
再说循环,我们在对普通非循环链表进行操作时,需要考虑链表的索引范围,容易造成空指针错误。循环则可以规避这种情况的发生,因为即使选择操作的索引范围超过链表的长度,链表会重头继续遍历,可以成功规避索引越界。一般情况下,双链表都是以循环的形式存在。在双循环链表中,头节点的 pre 指向尾节点,尾节点的 next 指向头结点。
因为在双循环链表中,引用了头结点(区别于首节点),因此对于双循环链表的操作更简单了一些,不再考虑我们所执行操作的位置是否位于首节点,以及该链表是否为空。不管链表是否为空,链表中都存在头结点head,head可以null,可以存放链表相关的信息。即使链表为空,head节点依然存在。
下面是关于双循环链表的基本操作实现代码,有写得不周全的地方欢迎讨论指正。
package DoubleList;
import ListLink.Node;
import ListLink.Teacher;
/*
* 循环双链表
* 为了操作方便
* 在链表中加入了头结点
* 使得插入删除操作不需要再考虑插入删除数据是位于首节点位置以及链表是否为空的情况
*
*/
public class DoubleLinkList {
public DoubleNode head; //头结点
public int len=1; //实际节点个数
public int tmp=0; //节点位置
public DoubleLinkList()
{
head=new DoubleNode(null);
head.pre=head.next=head;
}
/*
* 头插法插入节点
* 头插法即插入的数据总是在头结点之后
* 即所在位置为head.next
*/
public void addNodeHead(Teacher teacher)
{
DoubleNode node=new DoubleNode(teacher);
node.next=head.next;
head.next.pre=node;
head.next=node;
node.pre=head;
len++;
}
/*
* 尾插法插入节点
* 尾插法即插入的数据总是在最后
* 即所在位置为head.pre
*/
public void addNodeTail(Teacher teacher)
{
DoubleNode node=new DoubleNode(teacher);
node.next=head;
node.pre=head.pre;
head.pre.next=node;
head.pre=node;
len++;
}
//在任何节点插入数据
public void addNode(int index,Teacher teacher)
{
DoubleNode node=new DoubleNode(teacher);
DoubleNode previous=head;
DoubleNode current=head;
while(tmp!=index)
{
previous=current;
current=current.next;
tmp++;
}
node.next=current;
current.pre=node;
previous.next=node;
node.pre=previous;
tmp=0;
len++;
}
//删除节点
public void deleteNode(int index)
{
int temp=index%len; //这一步是为了防止将head删除,这会导致错误。
DoubleNode previous=head;
DoubleNode current=head;
while(tmp!=temp)
{
previous=current;
current=current.next;
tmp++;
}
current.next.pre=previous;
previous.next=current.next;
tmp=0;
len--;
}
public void PrintAll()
{
DoubleNode node=head.next;
while(node!=head)
{
node.display();
node=node.next;
}
}
public static void main(String[] args)
{
DoubleLinkList dll=new DoubleLinkList();
Teacher teacher1=new Teacher("001","小明","男",22,"1222","wewew");
dll.addNodeHead(teacher1);
Teacher teacher2=new Teacher("002","小明","男",22,"1222","wewew");
dll.addNodeHead(teacher2);
Teacher teacher3=new Teacher("003","小明","男",22,"1222","wewew");
dll.addNodeTail(teacher3);
Teacher teacher4=new Teacher("004","小明","男",22,"1222","wewew");
dll.addNodeTail(teacher4);
// Teacher teacher5=new Teacher("005","小明","男",22,"1222","wewew");
// dll.addNode(2,teacher5);
dll.deleteNode(5);
dll.PrintAll();
}
}
package DoubleList;
import ListLink.Teacher;
public class DoubleNode {
protected DoubleNode next;
protected DoubleNode pre;
protected Teacher teacher;
public DoubleNode(Teacher teacher)
{
this.teacher=teacher;
}
public void display()
{
System.out.println(" 教工编号: "+teacher.getSno()+" 教工姓名: "+teacher.getSname()+" 性别: "+teacher.getSex()+" 年龄: "+teacher.getAge()+" 电话: "+teacher.getTel()+" 邮箱:"+teacher.getEmail());
}
}
这里的Teacher类与之前写的Teacher类一致,可以查看前几章写的Teacher类,在代码中,也是直接引应别的包中的Teacher类。大家可以定义自己的类来测试。