什么是双向循环链表

在了解双向循环链表之前,如果对链表还没有一个清晰的概念,建议你看看单链表单向循环链表,这有利于你更好的理解下面的内容。(废话有点多[逃]

相比单链表,双向循环链表是一个更加复杂的结构。因为双向循环链表的节点不仅包含指向下一个节点的指针(next),还包含指向前一个节点的指针(prev)。

  • 在双向循环链表中,可见的不只有头指针head,还有尾节点end。这是和单链表的区别。
  • 双向循环链表的头指针head的前一个节点指向end,尾节点end的后一个节点指向head。

基本操作

双向循环链表的基本操作有:增(add),删(remove),改(set),查(find),插(insert)等。在这里我们只讲解remove,insert和getNode操作,其他实现可看下方源码。

获取节点

由于双向链表有两个可见的节点(head和end),因此双向循环链表获取节点的操作和单链表有所不同。

  • 把需要获取的节点序号和链表长度/2比较
  • 若小于,说明节点是偏前的,因此从head开始一路next下去
  • 若大于,说明节点是偏后的,因此从end开始一路prev上去
  • 这样的设计能使getNode操作的时间复杂度缩短为O(logN)
删除元素
  • 获取待删除元素的节点node
  • 把node前一个节点的next指针设置为node的后一个节点。具体实现为:node.prev.next=node.next
  • 把node后一个节点的prev指针设置为node的前一个节点。具体实现为:node.next.prev=node.prev
  • 由于没有指针指向node,node会被自动清理
  • 记录链表长度的变量-1
插入元素
  • 获取待插入元素的节点node
  • 创建一个节点mynode,next指向node,prev指向node.prev
  • 把node.prev该节点的next指向mynode
  • 把node的前一个节点prev指向mynode

双向循环链表的优劣

优势
  • 相比单链表,双向循环链表所有基本操作均快于单链表(java源码的LinkList类就是双向循环链表)
  • 能直接获取节点的前一个节点,十分灵活
劣势
  • 相比单链表,双链表的空间内存明显要大很多

双链表的设计应用了算法设计的“空间换时间”思想,通过消耗更多的空间来缩小操作的时间复杂度。


源码实现

public class Node<Anytype> {
public Anytype data;//数据
public Node<Anytype> prev;//前一个节点
public Node<Anytype> next;//后一个节点
public Node(Anytype data,Node<Anytype> prev,Node<Anytype> next){
this.data=data;
this.prev=prev;
this.next=next;
}
} ---------------------------------------------- public class DoubleLink<AnyType> {
Node<AnyType> head;//头指针
Node<AnyType> end;//尾节点
int size;//记录链表长度 //初始化链表
public void initlist(){
end=new Node<>(null,null,null);
head=new Node<>(null,null,end);
end.prev=head;
end.next=head;
size=0;
} //获取长度
public int length(){
return size;
} //获取节点
public Node<AnyType> getNode(int index){
Node<AnyType> n;
if(index>=size/2){
n=end;
for(int i=length();i>index;i--){
n=n.prev;
}
return n;
}
else{
n=head;
for(int i=0;i<=index;i++){
n=n.next;
}
return n;
}
} //添加元素
public void add(AnyType a){
Node<AnyType> renode=new Node<>(a,getNode(size-1),end);
renode.prev.next=renode;
renode.next.prev=renode;
size++;
} //插入元素
public void insert(int i,AnyType a){
Node<AnyType> n=getNode(i);
Node<AnyType> renode=new Node<>(a,n.prev,n);
n.prev.next=renode;
n.prev=renode;
size++;
} //删除元素
public AnyType remove(int i){
Node<AnyType> n=getNode(i);
AnyType data=n.data;
n.prev.next=n.next;
n.next.prev=n.prev;
size--;
return data;
} //获取i位置的数据
public AnyType get(int i){
return getNode(i).data;
} //为i位置元素重新赋值
public AnyType set(int i,AnyType a){
Node<AnyType> n=getNode(i);
AnyType old=n.data;
n.data=a;
return old; } //清空链表
public void clear(){
initlist();
} public void print(){
for(int i=0;i<size;i++){
System.out.println(getNode(i).data);
}
}
}

(java实现)双向循环链表的更多相关文章

  1. java与数据结构(4)---java实现双向循环链表

    线性表之链式存储结构双向循环链表 双向循环链表:每个结点包含了数据.直接前驱地址指针和直接后驱地址指针,头结点的直接前驱指向尾结点,尾结点的直接后驱指向头结点,头尾相连构成一个可正可反的圆环.可以形象 ...

  2. java实现双向循环链表

    java实现循环链表:http://www.cnblogs.com/lixiaolun/p/4643911.html 在单链表中,查询下一个元素的时间是O(1).查询上一个元素的时间却是O(n). 为 ...

  3. Java 用双向循环链表实现 遍历

    package day2; /** * 构建双向循环链表,实现遍历功能 */public class DoubleLB { public static void main(String[] args) ...

  4. 双向循环链表的Java版本实现

    1.单项循环列表 单向循环链表是单链表的另一种形式,其结构特点是链表中最后一个结点的指针不再是结束标记,而是指向整个链表的第一个结点,从而使单链表形成一个环.和单链表相比,循环单链表的长处是从链尾到链 ...

  5. java数据结构-06双向循环链表

    双向循环链表跟单向链表一样,都是头尾相连,不过单向是尾指向头,双向是头尾互相指,可以从前往后查,也可以从后往前查 无头结点的双向循环链表 public class CircleLinkedList&l ...

  6. "《算法导论》之‘线性表’":双向循环链表

    本文双链表介绍部分参考自博文数组.单链表和双链表介绍 以及 双向链表的C/C++/Java实现. 1 双链表介绍 双向链表(双链表)是链表的一种.和单链表一样,双链表也是由节点组成,它的每个数据结点中 ...

  7. 双向链表、双向循环链表的JS实现

    关于链表简介.单链表.单向循环链表.JS中的使用以及扩充方法:  单链表.循环链表的JS实现 关于四种链表的完整封装: https://github.com/zhuwq585/Data-Structu ...

  8. C语言通用双向循环链表操作函数集

    说明 相比Linux内核链表宿主结构可有多个链表结构的优点,本函数集侧重封装性和易用性,而灵活性和效率有所降低.     可基于该函数集方便地构造栈或队列集.     本函数集暂未考虑并发保护. 一  ...

  9. c语言编程之双向循环链表

    双向循环链表就是形成两个环,注意每个环的首尾相连基本就可以了. 程序中采用尾插法进行添加节点. #include<stdio.h> #include<stdlib.h> #de ...

随机推荐

  1. Wireshark过滤命令总结

    1.表达式1 (tcp.flags.reset == )&&(tcp.seq == ) 2.表达式2 (tcp.flags.syn == )&&(tcp.analysi ...

  2. TynSerial结构体序列(还原)

    TynSerial结构体序列(还原) 1)定义一个结构体 type TRec = record id, name: string; end; 2)结构体序列(还原) procedure TForm1. ...

  3. Java List 和 Array 转化

    List to Array List 提供了toArray的接口,所以可以直接调用转为object型数组 List<String> list = new ArrayList<Stri ...

  4. Spring StopWatch源码

    import java.text.NumberFormat; import java.util.LinkedList; import java.util.List; public class Stop ...

  5. 一个读取C#特性Description方法(zhuan)

    class Program { static void Main(string[] args) { string str= DB.write.ToDescription(); Console.Writ ...

  6. iOS12 中的后台下载与上传

    严格意义上来说,iOS并不能像Android一样,真的在后台开启一个下载Service,一直下载.但是它可以进行在系统允许范围内的后台上传和下载. 当使用 NSURLSessionConfigurat ...

  7. nmealib-0.5.3 问题 Build Error: undefined reference to `ceil'

    When building on Ubuntu 12.x the build fails with the following error… gcc samples/generate/main.o - ...

  8. log4j:ERROR setFile(null,true) call failed.错误解决

    首先说明,我是用hive执行bin/hiveserver2时出现的这个错误.如下图所示,红框中的内容也清晰的告诉我们出错的原因和文件路径. 之后,我查看了一下该路径.发现我用的是beifeng的用户, ...

  9. QML之信号与槽

    一.C++的信号和QML的槽 前言: Qt中的信号与槽,通常是一个信号SIGNAL和一个槽SLOT,通过connet连接,而QML中不需要再写槽函数,只需要在合适的地方告诉QML:如果x信号产生则执行 ...

  10. Web登录验证之 Shiro

    1.需要用到的shiro相关包 <!-- shiro begin --> <dependency> <groupId>org.apache.shiro</gr ...