模拟LinkedList实现的双向链表

ops/2024/10/18 21:25:16/

1. 前言

前文我们用java语言实现了无哨兵的单向链表.稍作修改即可实现有哨兵的单向链表.有哨兵的单向链表相较与无哨兵的而言,其对链表的头结点的增删操作更为方便.而在此我们实现了带有头节点和尾节点的双向链表(该头节点和尾节点都不存储有效的数据).

2. 带有头节点和尾节点的双向链表

例 : 

java">public class BinaryLinkedList implements Iterable<Integer> {//头指针指向头节点static Node prev = new Node(null, 0, null);//尾指针指向尾节点static Node tail = new Node(null, 0, null);public BinaryLinkedList() {//将头节点的next指针指向尾节点//将尾节点的prev指针指向头节点prev.next = tail;tail.prev = prev;}private static class Node {int value;Node prev;Node next;public Node(Node prev, int value, Node next) {this.prev = prev;this.value = value;this.next = next;}}//头插法public void addHead(int value) {Node p = new Node(prev, value, prev.next);prev.next.prev = p;prev.next = p;}//从头开始遍历public void Traverse1Head() {Node p;for (p = prev.next; p != tail; p = p.next) {//空链表时, p==nullif (p == null) {return;}System.out.println("该节点的值为" + p.value);}}//从尾开始遍历public void Traverse1Tail() {Node p;for (p = tail.prev; p != prev; p = p.prev) {if (p == null) {return;}System.out.println("该节点的值为" + p.value);}}//获取指定位置的值public static int get(int index) {Node p = findIndex(index);return p.value;}//从头指针开始找指定索引的节点的值private static Node findIndex(int index) {int count = -1;Node p = prev;//这里允许index==-1的原因是此时返回的是头节点//有实际意义, 因为此时insert函数就无需对插入位置为0时做出分析if (index < -1) {throw new RuntimeException("index输入不合法");}while (count < index) {p = p.next;//此时p可能为null, 所以需要判断if (p == null) {throw new RuntimeException("输入无效的index");}count++;}//如果p是尾节点, 将抛出异常if (p == tail) {throw new RuntimeException("尾节点不可操作");}return p;}//尾插法public static void addLast(int value) {Node p = new Node(tail.prev, value, tail);tail.prev.next = p;tail.prev = p;}public void Insert(int index, int value) {//如果index==0, 则p是头节点Node p = findIndex(index - 1);Node insert = new Node(p, value, p.next);p.next.prev = insert;p.next = insert;}public int remove(int index) {//找到要删除的节点Node p = findIndex(index);int value = p.value;p.next.prev = p.prev;p.prev.next = p.next;return value;}//迭代器迭代的数据类型是整形, 又由于泛型不能是基本数据类型, 所以用到包装类@Overridepublic Iterator<Integer> iterator() {//使用到了匿名内部类return new Iterator<Integer>() {//成员变量p(实例变量)Node p = prev.next;@Overridepublic boolean hasNext() {if (p != null && p != tail) {return true;}return false;}@Overridepublic Integer next() {int value = p.value;p = p.next;return value;}};}public void Traverse2(Consumer<Integer> consumer) {Node p;for (p = prev.next; p != tail; p = p.next) {if (p == null) {return;}consumer.accept(p.value);}}
}

3. 单元测试(测试案例)

测试案例供参考 : 

java">@Testpublic void test1() {BinaryLinkedList b = new BinaryLinkedList();b.addHead(12);b.addHead(23);b.addHead(34);b.addHead(45);b.addHead(56);b.addHead(67);b.addHead(78);
//        b.Traverse1Head();
//        b.Traverse1Tail();
//        System.out.println(b.get(0));}@Testpublic void test2() {BinaryLinkedList b = new BinaryLinkedList();b.addLast(12);b.addLast(23);b.addLast(34);b.addLast(45);b.addLast(56);b.addLast(67);b.addLast(78);//只有实现了Intrable接口的类才能使用foreach循环,//因为foreach底层就是使用迭代器不断调用hasNext(), next()方法//迭代出值赋值给临时变量elementfor (Integer element : b) {System.out.println("该节点的数据域是" + element);}}@Testpublic void test3() {BinaryLinkedList b = new BinaryLinkedList();b.addLast(12);b.addLast(23);b.addLast(34);b.addLast(45);b.addLast(56);b.addLast(67);b.addLast(78);//使用lambda表达式b.Traverse2(value -> System.out.println("该节点的数据域的值是" + value));System.out.println("*******************");//还可以使用方法引用b.Traverse2(System.out :: println);}

http://www.ppmy.cn/ops/20894.html

相关文章

手机照片传到电脑的最快方法有哪些?手把手教程来啦!

当我们需要将手机中的照片导入到电脑时&#xff0c;往往会因为速度慢、操作复杂而感到困扰。那么&#xff0c;手机照片传到电脑的最快方法有哪些呢&#xff1f;本文将为您详细介绍2个超快的方法&#xff0c;并附上详细教程&#xff0c;针对每种方法提供详细的操作步骤&#xff…

学习操作系统路线

操作系统 简介 本课程为计算机专业学生量身定制&#xff0c;补足计算机操作系统相关知识&#xff0c;查漏补缺&#xff0c;也可用于考研复习。内容包括&#xff1a;操作统概述、进程管理、内存管理、文件管理、输入/输出管理等章节。内容力求精炼、重点突出、条理清晰、深入浅…

GNU Radio之Frequency Mod底层C++实现

文章目录 前言一、频率调制原理二、Frequency Mod 模块三、底层 C 代码实现 前言 频率调制&#xff08;Frequency Modulation, FM&#xff09;是一种重要的调制技术&#xff0c;广泛应用于无线广播和通信&#xff0c;本文对 GNU Radio 中的 Frequency Mod 模块进行深入剖析。 …

亚远景科技-什么是R.A.S.I.C角色职权矩阵

什么是 R.A.S.I.C角色职权矩阵 在流程定义过程中&#xff0c;亚远景科技推荐使用RASIC 矩阵。RASIC 矩阵是一个非常有用的管理方法。可以明确流程定义中的角色和其相关责任。 "RASIC" 是"Responsible" 、"Accountable" 、"Supportive"…

【论文阅读】EgoPCA: A New Framework for Egocentric Hand-Object Interaction

论文主要贡献 提出一种新的框架&#xff1a;Ego-HOI recognition by Probing, Curation and Adaption (EgoPCA)。构建了全面的预训练集&#xff0c;平衡的测试集&#xff0c;以及一个包含了微调策略的baseline。 在Ego-HOI达到了SOTA&#xff0c;并且建立了有效的机制方法。 …

[移动端] “viewport“ content=“width=device-width, initial-scale=1.0“ 什么意思

布局视口, 代码如下 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><title>Document</title><style>body,html {margin: 0;padding: 0;}.box {width: 200px;height: 200px;background-color: pi…

vue 的 keep-alive 详解

目录 keep-alive 是什么&#xff1f; keep-alive 属性 keep-alive 使用场景及用法 keep-alive 匹配规则 缓存实例的生命周期 缓存后如何获取数据 原理分析 keep-alive 是什么&#xff1f; <KeepAlive> 是一个内置组件&#xff0c;它的功能是在多个组件间动态切换…

【高阶数据结构】B树 {B树的概念;B树的实现:节点设计,查找,插入,遍历,删除;B树的性能分析;B+树和B*树;B树的应用}

一、常见的搜索结构 以上结构适合用于数据量相对不是很大&#xff0c;能够一次性存放在内存中&#xff0c;进行数据查找的场景。如果数据量很大&#xff0c;比如有100G数据&#xff0c;无法一次放进内存中&#xff0c;那就只能放在磁盘上了&#xff0c;如果放在磁盘上&#xff…