五种List集合的简单实现

五种List集合的简单实现

    • 一、数组形式
    • 二、单向链表形式
    • 三、含哨兵节点的单向链表形式
    • 四、含哨兵节点的双向链表形式
    • 五、含哨兵节点的环形链表形式

本文是对不同形式List集合的增删改查实现,仅是对学习过程进行记录

一、数组形式

关键点:

  1. 有三个成员变量:集合对象array、元素个数size、数组长度capacity
  2. 在扩容时,将旧array中的数据拷贝到新array对象中
  3. 新增先处理add(int index, int data)方法,考虑扩容、后移元素、赋值三个步骤
public class SelfArrayList {/*** 真实的数据*/private int[] array = {};/*** 集合真实大小*/private int size = 0;/*** 集合容量*/private int capacity = 8;public void add(int data) {initAndGroup();add(size, data);}public void add(int index, int data) {initAndGroup();// 仅支持将元素添加到当前集合最后位置if (index <= size) {for (int i = size; i > index; i--) {array[i] = array[i - 1];}array[index] = data;size++;}}public int delete() {return array[--size];}public void update(int index, int data) {if (index > 0 && index < size) {array[index] = data;}}public int get(int index) {return array[index];}public void forEach(Consumer<Integer> consumer) {for (int i = 0; i < size; i++) {consumer.accept(array[i]);}}private void initAndGroup() {if (size == 0) {array = new int[capacity];} else if (size == capacity) {capacity += capacity >> 1;int[] newArray = new int[capacity];System.arraycopy(array, 0, newArray, 0, size);array = newArray;}}
}

二、单向链表形式

关键点:

  1. 成员变量就一个Node head节点
  2. 主要是三个关键方法add(int index, int value)、delete(int index)、findNode(int index),三个方法里面findNode(int index)又是关键
public class SelfLinkList {private Node head = null;public void addHead(int value) {head = new Node(value, head);}public void addTail(int value) {Node tail = findTail();// 加入的节点为第一个节点if (tail == null) {addHead(value);} else {tail.next = new Node(value, null);}}/*** 核心方法 1 of 3*/public void add(int index, int value) {if (index <= 0) {addHead(value);return;}// 找到对应索引的上一个节点Node pre = findNode(index - 1);if (pre == null) {return;}pre.next = new Node(value, pre.next);}public Node deleteFirst() {Node deleteNode = head;head = head.next;return deleteNode;}/*** 核心方法 2 of 3*/public Node delete(int index) {Node pre = findNode(index - 1);// 删除头节点数据if (pre == null) {return deleteFirst();}Node cur = pre.next;// 删除末尾不存在数据if (cur == null) {return null;}pre.next = cur.next;return cur;}/*** 核心方法 3 of 3* index 小于0或者大于链表长度 返回null*/public Node findNode(int index) {Node temp = head;int nodeSize = 0;// 循环遍历 找到对应的节点while (temp != null) {if (index == nodeSize) {return temp;}temp = temp.next;nodeSize++;}return null;}public void forEach(Consumer<Integer> consumer) {Node temp = head;while (temp != null) {consumer.accept(temp.value);temp = temp.next;}}private Node findTail() {if (head == null) {return head;}Node tail = head;while (tail.next != null) {tail = tail.next;}return tail;}@AllArgsConstructorpublic static class Node {public int value;public Node next;}
}

三、含哨兵节点的单向链表形式

关键点:

  1. 自带一个head节点,其目的是为了简化后续的操作流程,避免出现null的场景
  2. 主要是三个关键方法add(int index, int value)、delete(int index)、findNode(int index),三个方法里面findNode(int index)又是关键,特别注意哨兵节点和普通参数节点返回下标的差异
public class SelfSentinelLinkList {private final SelfSentinelLinkList.Node head = new SelfSentinelLinkList.Node(0, null);public void addHead(int value) {add(0, value);}public void addTail(int value) {SelfSentinelLinkList.Node tail = findTail();tail.next = new SelfSentinelLinkList.Node(value, null);}/*** 核心方法 1 of 3*/public void add(int index, int value) {SelfSentinelLinkList.Node pre = findNode(index - 1);// 添加元素超过链表长度if (pre == null) {return;}pre.next = new SelfSentinelLinkList.Node(value, pre.next);}public SelfSentinelLinkList.Node deleteFirst() {return delete(0);}/*** 核心方法 2 of 3*/public SelfSentinelLinkList.Node delete(int index) {SelfSentinelLinkList.Node pre = findNode(Math.max(-1, index - 1));// 删除索引下标超过链表长度if (pre == null) {return null;}SelfSentinelLinkList.Node deleted = pre.next;// 删除索引下标超过链表长度if (deleted == null) {return null;}pre.next = deleted.next;return deleted;}/*** 核心方法 3 of 3* 哨兵节点 index=-1* 数据节点 index>=0*/public SelfSentinelLinkList.Node findNode(int index) {SelfSentinelLinkList.Node temp = head;int nodeSize = -1;while (temp != null) {if (index == nodeSize) {return temp;}temp = temp.next;nodeSize++;}return null;}public void forEach(Consumer<Integer> consumer) {SelfSentinelLinkList.Node temp = head.next;while (temp != null) {consumer.accept(temp.value);temp = temp.next;}}private SelfSentinelLinkList.Node findTail() {SelfSentinelLinkList.Node tail = head;while (tail.next != null) {tail = tail.next;}return tail;}@AllArgsConstructorpublic static class Node {public int value;public SelfSentinelLinkList.Node next;}
}

四、含哨兵节点的双向链表形式

关键点:

  1. 默认初始化两个节点head、tail,每增加一个数据就new一个Node,并且同时维护前后4条关系链(new Node的时候已经维护了两条),删除同理
  2. 主要是三个关键方法add(int index, int value)、delete(int index)、findNode(int index),三个方法里面findNode(int index)又是关键
public class SelfSentinelDoublyLinkedList {/*** 头哨兵*/private final Node head = new Node(null, 0, null);/*** 尾哨兵*/private final Node tail = new Node(null, 0, null);public SelfSentinelDoublyLinkedList() {head.next = tail;tail.prev = head;}public void addFirst(int value) {add(0, value);}/*** 双向链表的特色地方 就是在操作last的时候*/public void addLast(int value) {Node last = tail.prev;Node added = new Node(last, value, tail);last.next = added;tail.prev = added;}/*** 新增数据 核心方法 1 of 3*/public void add(int index, int value) {// 找到要插入数据的上一个节点Node prev = findNode(index - 1);if (prev == null) {return;}Node next = prev.next;Node inserted = new Node(prev, value, next);prev.next = inserted;next.prev = inserted;}public void deleteFirst() {delete(0);}public void deleteLast() {Node removed = tail.prev;if (removed == head) {return;}Node prev = removed.prev;prev.next = tail;tail.prev = prev;}/*** 删除数据 核心方法 2 of 3*/public void delete(int index) {Node prev = findNode(index - 1);if (prev == null) {return;}Node removed = prev.next;if (removed == tail) {return;}Node next = removed.next;prev.next = next;next.prev = prev;}/*** 根据索引查找数据 核心方法 3 of 3*/private Node findNode(int index) {int i = -1;for (Node p = head; p != tail; p = p.next, i++) {if (i == index) {return p;}}return null;}public void forEach(Consumer<Integer> consumer) {Node p = head.next;while (p != tail) {consumer.accept(p.value);p = p.next;}}static class Node {/*** 上一个节点指针*/private Node prev;/*** 下一个节点指针*/private Node next;/*** 具体数据*/private final int value;public Node(Node prev, int value, Node next) {this.prev = prev;this.value = value;this.next = next;}}
}

五、含哨兵节点的环形链表形式

关键点:

  1. 默认只初始化一个节点sentinel,由于是一个环,所以该节点既可以是头哨兵,也可以是尾哨兵。增加一个数据就new一个Node,并且同时维护前后4条关系链(new Node的时候已经维护了两条)
  2. 在初始化SelfRingLinkedListSentinel这个链表的时候,构建好环的关联关系
  3. 新增、删除数据时,都需要维护好四条关系链
public class SelfRingLinkedListSentinel {/*** 哨兵节点*/private final Node sentinel = new Node(null, 0, null);public SelfRingLinkedListSentinel() {sentinel.next = sentinel;sentinel.prev = sentinel;}/*** 添加到第一个*/public void addFirst(int value) {Node next = sentinel.next;Node prev = sentinel;Node added = new Node(prev, value, next);prev.next = added;next.prev = added;}/*** 添加到最后一个*/public void addLast(int value) {Node prev = sentinel.prev;Node next = sentinel;Node added = new Node(prev, value, next);prev.next = added;next.prev = added;}/*** 删除第一个*/public void removeFirst() {Node removed = sentinel.next;if (removed == sentinel) {return;}Node a = sentinel;Node b = removed.next;a.next = b;b.prev = a;}/*** 删除最后一个*/public void removeLast() {Node removed = sentinel.prev;if (removed == sentinel) {return;}Node a = removed.prev;Node b = sentinel;a.next = b;b.prev = a;}/*** 根据值删除节点*/public void removeByValue(int value) {Node removed = findNodeByValue(value);if (removed != null) {Node prev = removed.prev;Node next = removed.next;prev.next = next;next.prev = prev;}}/*** 遍历找到对应的元素*/private Node findNodeByValue(int value) {Node p = sentinel.next;while (p != sentinel) {if (p.value == value) {return p;}p = p.next;}return null;}public void forEach(Consumer<Integer> consumer) {Node p = sentinel.next;while (p != sentinel) {consumer.accept(p.value);p = p.next;}}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;}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/637816.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hive-SQL语法大全

Hive SQL 语法大全 基于语法描述说明 CREATE DATABASE [IF NOT EXISTS] db_name [LOCATION] path; SELECT expr, ... FROM tbl ORDER BY col_name [ASC | DESC] (A | B | C)如上语法&#xff0c;在语法描述中出现&#xff1a; []&#xff0c;表示可选&#xff0c;如上[LOCATI…

面试高频知识点:1集合 1.2 ConcurentHashMap是如何实现线程安全的?(1.8之前后区别)

ConcurrentHashMap&#xff08;并发哈希表&#xff09;是Java集合框架中的一种实现Map接口的类&#xff0c;它专为多线程环境设计&#xff0c;以提供更好的性能和线程安全。在理解 ConcurrentHashMap 是如何实现线程安全的时候&#xff0c;我们可以分别探讨 JDK 1.8 之前和之后…

CGAL 网格法向量计算

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 在计算机图形三维曲面中,严格意义上来讲其实并不存在我们数学层面上所定义的曲面结构,因为计算机中的曲面图形一般都是有一个个三角形或者是多边形而组成的,因此所谓曲面的法向量其实就是在计算每一个三角形或多…

【操作系统和计网从入门到深入】(五)软硬链接和动静态库

前言 这个专栏其实是博主在复习操作系统和计算机网络时候的笔记&#xff0c;所以如果是博主比较熟悉的知识点&#xff0c;博主可能就直接跳过了&#xff0c;但是所有重要的知识点&#xff0c;在这个专栏里面都会提到&#xff01;而且我也一定会保证这个专栏知识点的完整性&…

Lombok:简化JavaBeans的神器

前言 Lombok 是一个 Java 库&#xff0c;它通过注解的方式帮助我们自动生成构造器、getter/setter、equals、hashCode、toString 等方法&#xff0c;极大地简化了 JavaBean 的编写。对于经常需要编写大量的样板代码的工作来说&#xff0c;Lombok 提供了一种优雅的解决方案。 …

Linux内核--网络协议栈(四)sk_buff介绍

目录 一、引言 二、sk_buff ------>2.1、skb介绍 ------>2.2、控制字段 ------>2.3、其他字段 ------>2.4、特定功能字段 ------>2.5、管理字段 ------>2.6、内存分配 ------>2.7、内存释放 ------>2.8、克隆和拷贝 ------>2.9、队列管理…

通信入门系列——连续卷积定理、循环卷积、离散卷积定理

本节目录 一、连续卷积定理 1、时域卷积定理 2、频域卷积定理 二、循环卷积 三、离散卷积定理本节内容 一、连续卷积定理 卷积定理在信号分析中占有重要的地位&#xff0c;包括时域卷积定理和频域卷积定理。在信号分析领域&#xff0c;通常采用基于卷积定理的时频域分析&#…

Zuul1.x 高并发下阻塞分析以及解决方案

背景 由于最近博主在压测接口的时候发现我接口出现卡死状态&#xff0c;最开始以为是我自己接口出现问题&#xff0c;单独压测我自己的服务&#xff08;不经过网关&#xff09;200/qps/10 次循环 是没问题&#xff0c;但是加上网关&#xff08;zuul 1.x&#xff09; 去发现 经…

编曲学习:Cubase12导入Cubasis工程的方法!

Steinberg 发布 Cubasis 3 项目导入器&#xff0c;可将 Cubasis 的项目导入到 Cubase 使用https://m.midifan.com/news_body.php?id35635 我偶然看到这个文章&#xff0c;不过发现Cubase12默认好像没有这个选项&#xff0c;心想着要是移动端能和PC端同步&#xff0c;感觉会挺…

【网站项目】基于jsp的199旅游景点管理系统

&#x1f64a;作者简介&#xff1a;多年一线开发工作经验&#xff0c;分享技术代码帮助学生学习&#xff0c;独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。&#x1f339;赠送计算机毕业设计600个选题excel文件&#xff0c;帮助大学选题。赠送开题报告模板&#xff…

C++中的排序操作:sort与自定义排序(自定义排序函数、匿名函数、运算符重载)

在C编程中&#xff0c;排序是一项常见而又重要的操作。本文将深入介绍C标准库中的sort算法&#xff0c;以及如何利用其强大的自定义排序功能满足各种排序需求。 sort算法简介 C标准库提供了sort算法&#xff0c;能够在O(N log N)的时间内对容器中的元素进行排序。这一高效的排…

快速下载百度网盘的文件——使用motrix

问题描述 下载速度慢 上传速度快 解决方案&#xff1a; Motrix 在该开源程序里面 选windows选择zip 启动之后 &#xff0c;把百度网盘的链接转化成磁力链接。然后输入转化后的连接。转换的网页 每次设置下载认任务是选择高级选项里面的请求头 修改为LogStatistic 然后就能超…

“低绩效”指南

前言 一看这个标题&#xff0c;大家是否有个疑问&#xff0c;为啥是低绩效指南&#xff0c;而不是高绩效指南。可以这么说&#xff0c;能拿到高绩效的人大多有共通之处&#xff0c;然而获得低绩效的同学原因各不相同&#xff0c;针对笔者总结的一些经验或许能帮助大家反向操作…

Qt5编译MySQL数据驱动、部署MySQL服务器、Qt写代码连接MySQL数据库_案例介绍

一、前言 由于Qt 5在高版本中取消了对MySQL数据库的默认支持,要在QT里继续使用mysql需要自己编译库。本篇文章介绍Qt5(我用的Qt5.12.6)里如何编译MySQL的库文件,讲解在Linux下安装配置MySQL数据库,Qt编写代码连接上自己的MySQL数据库完成数据存储。 MySQL是一个开源的关…

Odrive 学习系列四:如何使用脚本自动初始化odrive配置

一、背景: 在学习markbase的教程后,发现odrive的初始化配置命令确实有点多。尽管odrive有自动补全: 且可以通过 ctrl + → 来快速补全: 但是对初学者而言,仍旧有比较大的工作量。 而针对于此,我们可以通过powershell脚本的方式来解决这个问题。 二、设计初始化…

接口测试 03 -- 接口自动化思维 Requests库应用

1. 接口自动化思维梳理 1.1接口自动化的优点 接口测试自动化&#xff0c;简单来讲就是功能测试用例脚本化然后执行脚本&#xff0c;产生一份可视化测试报告。不管什么样的测试方式&#xff0c;都是为了验证功能与发现 BUG。那为什么要做接口测试自动化呢&#xff1f;一句话概括…

【ARM 嵌入式 编译系列 2.1 -- GCC 预处理命令 #error 和 #warning 详细介绍 】

文章目录 #error 和 #warning#error示例 #warning示例 打印行号示例 #error 和 #warning 在C语言中&#xff0c;#error 和 #warning 预处理指令可以用于在编译时生成错误或警告信息&#xff0c;通常用于调试或当代码中某些条件未满足时提醒开发者。当这些指令被编译器处理时&a…

项目解决方案:多地医馆的高清视频监控接入汇聚联网

目 录 一、背景 二、建设目标及需求 1.建设目标 2.现状分析 3.需求分析 三、方案设计 1.设计依据 2.设计原则 3.方案设计 3.1 方案描述 3.2 组网说明 四、产品介绍 1.视频监控综合资源管理平台介绍 2.视频录像服务器和存储 2.1概述 2.2存储设计 …

51单片机流水灯

**led 介绍**LED是“Light Emitting Diode”的缩写&#xff0c;即发光二极管。它是一种半导体器件&#xff0c;能够将电能转化为可见光。LED灯通常由LED芯片、封装材料、铝基板和灯罩等部件组成。 **LED灯具有以下特点&#xff1a;** 节能&#xff1a;LED灯具有较高的光电转换…

oracle篇—19c新特性自动索引介绍

☘️博主介绍☘️&#xff1a; ✨又是一天没白过&#xff0c;我是奈斯&#xff0c;DBA一名✨ ✌✌️擅长Oracle、MySQL、SQLserver、Linux&#xff0c;也在积极的扩展IT方向的其他知识面✌✌️ ❣️❣️❣️大佬们都喜欢静静的看文章&#xff0c;并且也会默默的点赞收藏加关注❣…