双向循环链表跟单向链表一样,都是头尾相连,不过单向是尾指向头,双向是头尾互相指,可以从前往后查,也可以从后往前查

无头结点的双向循环链表

public class CircleLinkedList<E> extends AbstractList<E> {
private Node<E> first;
private Node<E> last; private static class Node<E> {
E element;
Node<E> prev;
Node<E> next;
public Node(Node<E> prev, E element, Node<E> next) {
this.prev = prev;
this.element = element;
this.next = next;
} @Override
public String toString() {
StringBuilder sb = new StringBuilder(); if (prev != null) {
sb.append(prev.element);
} else {
sb.append("null");
} sb.append("_").append(element).append("_"); if (next != null) {
sb.append(next.element);
} else {
sb.append("null");
} return sb.toString();
}
} @Override
public void clear() {
size = 0;
first = null;
last = null;
} @Override
public E get(int index) {
return node(index).element;
} @Override
public E set(int index, E element) {
Node<E> node = node(index);
E old = node.element;
node.element = element;
return old;
} @Override
public void add(int index, E element) {
rangeCheckForAdd(index); // size == 0
// index == 0
if (index == size) { // 往最后面添加元素
Node<E> oldLast = last;
last = new Node<>(oldLast, element, first);
if (oldLast == null) { // 这是链表添加的第一个元素
first = last;
first.next = first;
first.prev = first;
} else {
oldLast.next = last;
first.prev = last;
}
} else {
Node<E> next = node(index);
Node<E> prev = next.prev;
Node<E> node = new Node<>(prev, element, next);
next.prev = node;
prev.next = node; if (next == first) { // index == 0
first = node;
}
} size++;
} @Override
public E remove(int index) {
rangeCheck(index);
return remove(node(index));
} private E remove(Node<E> node) {
if (size == 1) {
first = null;
last = null;
} else {
Node<E> prev = node.prev;
Node<E> next = node.next;
prev.next = next;
next.prev = prev; if (node == first) { // index == 0
first = next;
} if (node == last) { // index == size - 1
last = prev;
}
} size--;
return node.element;
} @Override
public int indexOf(E element) {
if (element == null) {
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (node.element == null) return i; node = node.next;
}
} else {
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (element.equals(node.element)) return i; node = node.next;
}
}
return ELEMENT_NOT_FOUND;
} /**
* 获取index位置对应的节点对象
* @param index
* @return
*/
private Node<E> node(int index) {
rangeCheck(index); if (index < (size >> 1)) {
Node<E> node = first;
for (int i = 0; i < index; i++) {
node = node.next;
}
return node;
} else {
Node<E> node = last;
for (int i = size - 1; i > index; i--) {
node = node.prev;
}
return node;
}
} @Override
public String toString() {
StringBuilder string = new StringBuilder();
string.append("size=").append(size).append(", [");
Node<E> node = first;
for (int i = 0; i < size; i++) {
if (i != 0) {
string.append(", ");
} string.append(node); node = node.next;
}
string.append("]");
return string.toString();
}
}

java数据结构-06双向循环链表的更多相关文章

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

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

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

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

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

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

  4. java实现双向循环链表

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

  5. 数据结构8: 双向链表(双向循环链表)的建立及C语言实现

    之前接触到的链表都只有一个指针,指向直接后继,整个链表只能单方向从表头访问到表尾,这种结构的链表统称为 “单向链表”或“单链表”. 如果算法中需要频繁地找某结点的前趋结点,单链表的解决方式是遍历整个链 ...

  6. (java实现)双向循环链表

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

  7. java数据结构和算法06(红黑树)

    这一篇我们来看看红黑树,首先说一下我啃红黑树的一点想法,刚开始的时候比较蒙,what?这到底是什么鬼啊?还有这种操作?有好久的时间我都缓不过来,直到我玩了两把王者之后回头一看,好像有点儿意思,所以有的 ...

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

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

  9. Java数据结构——循环链表

    一.单向循环链表表中的最后一个节点的指针域指向头结点,整个链表形成一个环.其他的与单链表相同. (以下图片均来自网络,侵删) 插入操作 删除操作 简单实现 public class CiNode { ...

随机推荐

  1. Java Web学习(一)Web基础

    文章更新时间:2020/07/24 一.基本概念 web资源 Internet上供外界访问的Web资源分为两种: 静态web资源(如html 页面):指web页面中供人们浏览的数据始终是不变. 动态w ...

  2. leetcode1558题解【贪心】

    leetcode1558.得到目标数组的最少函数调用次数 题目链接 算法 贪心 时间复杂度O(nlogN),N为数组中最大的那个数. 1.题意就是给定一个函数,该函数有两种功能,一种就是将数组中的所有 ...

  3. springboot项目整合rabbitMq涉及消息的发送确认,消息的消费确认机制,延时队列的实现

    1.引入maven依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactI ...

  4. HTML中css水平居中的几种方式

    1. 子元素为行内元素时,父元素使用 text-align: center; 实现子元素的水平居中: 2. 子元素为块级元素时, 2.1. 将子元素设置 margin: 0 auto; 实现居中: 2 ...

  5. Windows 无法验证此设备所需的驱动程序的数字签名”的问题

    转载: 1.https://jingyan.baidu.com/article/375c8e19c2b25b25f2a229a3.html 2. https://jingyan.baidu.com/a ...

  6. AE2018简单的编辑

    来源:https://jingyan.baidu.com/article/1876c8525cf522890a137651.html Ae 2018 怎样锁定图层,阻止对图层进行编辑? 听语音 原创 ...

  7. chattr 和 lsattr 命令详解

    lsattr 命令 lsattr 命令用于查看文件的第二扩展文件系统属性. 语法: lsattr(选项)(参数) 选项: -E:可显示设备属性的当前值,但这个当前值是从用户设备数据库中获得的,而不是从 ...

  8. JVM 第五篇:命令行 JVM 故障处理工具

    本文内容过于硬核,建议有 Java 相关经验人士阅读. 1. 引言 虽然我们前面介绍了各种图形化 JVM 故障处理工具,但是很多情况下,我们在处理问题的时候并没有图形化的操作环境可以使用,这时候,就需 ...

  9. ubuntu19.10如何添加开机启动项

    $sudo vi /lib/systemd/system/rc-local.service内容如下[Unit]Description=/etc/rc.local CompatibilityDocume ...

  10. MySQL - 常用三种数据库存储引擎

    数据库存储引擎:是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建.查询.更新和删除数据.不同的存储引擎提供不同的存储机制.索引技巧.锁定水平等功能,使用不同的存储引擎,还可以获得特 ...