胆大心细,加油。
简单实现一个双向循环链表
最近看公司代码的时候,发现有些业务是自己实现和封装的数据结构,以双向循环链表居多(大佬们写的代码真好),所以就复习一下双向循环链表的知识并自己实现了一个双向循环链表。
双向循环链表特征
双向链表是每个结点除后继指针外还有一个前驱指针。和单链表类同,双向链表也有带头结点结构和不带头结点结构两种,带头结点的双向链表更为常用;另外,双向链表也可以有循环和非循环两种结构,循环结构的双向链表更为常用。
双向循环链表数据结构
在双向链表中,每个结点包括三个域,分别是element域、next域和prior域,其中element域为数据元素域,next域为指向后继结点的对象引用,prior域为指向前驱结点的对象引用。双向链表结点的图示结构如下:
双向循环列表关系图示和插入删除操作
在双向链表中,有如下关系:设对象引用p表示双向链表中的第i个结点,则p.next表示第i+1个结点,p.next.prior仍表示第i个结点,即p.next.prior == p;同样地,p.prior表示第i-1个结点,p.prior.next仍表示第i个结点,即p.prior.next == p。下图是双向链表上述关系的图示。
循环双向链表的插入过程如下图所示。图中的指针p表示要插入结点的位置,s表示要插入的结点,①、②、③、④表示实现插入过程的步骤。
循环双向链表的删除过程如下图所示。图中的指针p表示要插入结点的位置,①、②表示实现删除过程的步骤。
代码实现
1. 链表常见操作接口
public interface List {
int size();
void insert(int index,Object value) throws Exception;
void delete(int index) throws Exception;
Object get(int index) throws Exception;
boolean isEmpty();
}
2. 链表节点
/**
* @author wencai.xu
*/
public class DoubleListNode {
/**
* 节点值
*/
Object element;
/**
* 前驱
*/
DoubleListNode prior;
/**
* 后继
*/
DoubleListNode next;
/**
* 头节点
* @param nextval
*/
public DoubleListNode(DoubleListNode nextval) {
this.next = nextval;
}
/**
* 非头节点
* @param element
* @param next
*/
public DoubleListNode(Object element, DoubleListNode next) {
this.element = element;
this.next = next;
}
public Object getElement() {
return element;
}
public void setElement(Object element) {
this.element = element;
}
public DoubleListNode getPrior() {
return prior;
}
public void setPrior(DoubleListNode prior) {
this.prior = prior;
}
public DoubleListNode getNext() {
return next;
}
public void setNext(DoubleListNode next) {
this.next = next;
}
@Override
public String toString(){
return this.element.toString();
}
}
3. 数据结构操作实现
public class DoubleLinkedList implements List{
/**
* 链表长度
*/
private int size;
/**
* 头指针
*/
private DoubleListNode head;
/**
* 当前指针
*/
private DoubleListNode current;
public DoubleLinkedList() {
this.head = current = new DoubleListNode(null);
// 初始长度为0
this.size = 0;
// 头节点的前趋和后继都指向头节点
this.head.next = head;
this.head.prior = head;
}
@Override
public int size() {
return this.size;
}
/**
* 定位函数
*/
private void index(int index) throws Exception {
if(index < -1 || index > size - 1){
throw new Exception("参数失败");
}
// 头节点
if(index == -1){
return;
}
int j = 0;
current = head.next;
while(current != head && j < index){
current = current.next;
j++;
}
}
@Override
public void insert(int index, Object value) throws Exception {
if(index < 0 || index > size){
throw new Exception("参数错误");
}
index(index - 1);
current.setNext(new DoubleListNode(value,current.next));
current.next.setPrior(current);
current.next.next.setPrior(current.next);
size ++;
}
@Override
public void delete(int index) throws Exception {
if(isEmpty()){
throw new Exception("链表为空,无法删除");
}
if(index < 0 || index > size){
throw new Exception("参数错误");
}
index(index - 1);
current.setNext(current.next.next);
current.next.setPrior(current);
size --;
}
@Override
public Object get(int index) throws Exception {
if(index < 0 || index > size - 1){
throw new Exception("参数失败");
}
index(index);
return current.element;
}
@Override
public boolean isEmpty() {
return this.size == 0;
}
}
4. 测试
public static void main(String[] args) throws Exception {
// TODO Auto-generated method stub
DoubleLinkedList list = new DoubleLinkedList();
for(int i=0;i<10;i++)
{
int temp = ((int)(Math.random()*100))%100;
list.insert(i, temp);
System.out.print(temp+" ");
}
list.delete(4);
System.out.println("\n------删除第五个元素之后-------");
for(int i=0;i<list.size;i++)
{
System.out.print(list.get(i)+" ");
}
}