集合实现类研究底层(部分):手撕ArrayList底层源码、手撕LinkedList底层源码、手写单向链表和双向链表

day26上

集合框架图

标绿已经学习底层,深入底层主要是研究实现类底层
集合框架图上

继承关系图

继承关系图

手撕ArrayList底层源码

ps:研究添加元素的过程

思路:

1.研究继承关系

2.研究属性

3.理解创建集合的过程 – 构造方法的底层原理

4.研究添加元素的过程

提升:

1.研究删除集合的过程

2.研究遍历集合的过程

场景//ArrayList<String> list = new ArrayList<>();ArrayList<String> list = new ArrayList<>(10000);list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");

底层

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {//回顾:其中抽象类的构造方法由子类调用//外部操作数(记录添加和删除的次数)protected transient int modCount = 0;//最终4
}
额外补充://空数据,没有对象,输出长度为空指针异常private static final Object[] EMPTY_ELEMENTDATA = null;    //空内容的数组,有对象,输出长度为0private static final Object[] EMPTY_ELEMENTDATA = {};//默认容量的空内容的数组,有对象,(后面两个对象不同)private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};    
public class ArrayList<E> extends AbstractList<E> implements List<E>{//默认初始化容量private static final int DEFAULT_CAPACITY = 10;//空内容的数组private static final Object[] EMPTY_ELEMENTDATA = {};//默认容量的空内容的数组private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//数据容器最大容量private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;//数据容器 - [“aaa”,"bbb","ccc","ddd",null,null,null,null,null,null]transient Object[] elementData;//new Object[10];//元素个数private int size;//最终4//无参构造,默认容量的空内容的数组public ArrayList() {this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;}//有参构造,初始化容量//initialCapacity - 10000public ArrayList(int initialCapacity) {if (initialCapacity > 0) {this.elementData = new Object[initialCapacity];} else if (initialCapacity == 0) {this.elementData = EMPTY_ELEMENTDATA;} else {throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity);}}//e - 最终"ddd"public boolean add(E e) {ensureCapacityInternal(size + 1);elementData[size++] = e;//添加一个元素size+1return true;}//minCapacity - 10--11(超)private void ensureCapacityInternal(int minCapacity) {//使用无参构造创建ArrayList,第一次添加元素时进入的判断if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {//minCapacity =  Math.max(10, 1);minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);}ensureExplicitCapacity(minCapacity);}//minCapacity - 10--11(超)private void ensureExplicitCapacity(int minCapacity) {modCount++;// 有溢出意识的代码(准备扩容的长度必须大于数据容器的长度)if (minCapacity - elementData.length > 0)grow(minCapacity);}//minCapacity - 10--11(超)private void grow(int minCapacity) {// oldCapacity - 10int oldCapacity = elementData.length;// newCapacity - 15,超过默认容量,开始扩容int newCapacity = oldCapacity + (oldCapacity >> 1);//ArrayList的扩容机制(1.5倍)if (newCapacity - minCapacity < 0)//newCapacity-10,没有超过默认容量newCapacity = minCapacity;//当超过最大容量Integer.MAX_VALUE-8if (newCapacity - MAX_ARRAY_SIZE > 0)newCapacity = hugeCapacity(minCapacity);elementData = Arrays.copyOf(elementData, newCapacity);}//内存中一般不会存很多数据,一般几万都很多了,后面会讲解大量数据的处理情况//其他地方调用,minCapacity可能为负private static int hugeCapacity(int minCapacity) {if (minCapacity < 0) // overflowthrow new OutOfMemoryError();//minCapacity > 0return (minCapacity > MAX_ARRAY_SIZE) ?Integer.MAX_VALUE :MAX_ARRAY_SIZE;}}

面试题

ArrayList的数据结构是什么?

Object类型的一维数组

ArrayList默认初始化容量是多少?

10

ArrayList最大容量是多少?

Integer.MAX_VALUE-8

ArrayList最大容量为什么是Integer.MAX_VALUE-8?

减8是为了腾出空间存放数组的头部信息

ArrayList扩容机制是什么?

扩容后的长度是原来长度的1.5倍

如何减少集合的伸缩性及其目的是什么?

根据需求判断元素大概的长度,在创建集合时指定长度,减少扩容次数,提高效率

手撕LinkedList底层源码

ps:研究添加元素的过程

思路:

1.研究继承关系

2.研究属性

3.理解创建集合的过程 – 构造方法的底层原理

4.研究添加元素的过程

提升:

1.研究删除集合的过程

2.研究遍历集合的过程

场景:LinkedList<String> list = new LinkedList<>();list.add("小小");list.add("奇男子");list.add("大大");

底层

public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {//外部操作数(记录添加和删除的次数)protected transient int modCount = 0;//0
}
public abstract class AbstractSequentialList<E> extends AbstractList<E> {
}
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>{//元素个数transient int size = 0;//0//首节点transient Node<E> first;//null//尾节点transient Node<E> last;//nullpublic LinkedList() {}//new对象,系统赋默认值//添加在inkLast(),所以研究linkLast()public boolean add(E e) {linkLast(e);return true;}void linkLast(E e) {final Node<E> l = last;final Node<E> newNode = new Node<>(l, e, null);last = newNode;if (l == null)first = newNode;elsel.next = newNode;size++;modCount++;}//回顾:静态内部类应用场景(此处不需要调用外部类的成员属性)//节点类private static class Node<E> {E item; ------------ 元素Node<E> next; ------ 下一个节点的地址Node<E> prev; ------ 上一个节点的地址Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}}}

节点对象理解图

在这里插入图片描述

补充:双向链表【站在数据结构的角度:结点】【站在java底层的角度:节点】

LinkedList理解图

LinkedList理解图

添加过程解析

第一次添加:

LinkLast()

1.首先e-小小,l = last为null

2.newNode对象(l,e,null)找到第一个节;所以第一个节点为【0x001】

3.然后last =newNode【0x001】

4.然后判断条件,first = newNode【0x001】

5.然后size++,变成1;modCount++变成1

第二次添加:

重新LinkLast()

e;l;newNode重新赋值

1.首先e-奇男子,l = last为0x001(上一个节点地址即赋值给下一个首节点,第二个节点的首节点可以找到上一个节点)

2.newNode对象(l,e,null)找到第二个节;所以第二个节点为【0x002】;

3.然后last =newNode【0x002】

4.然后判断条件,l.next = newNode【0x002】(下一个节点地址即赋值给上一个尾节点,上一个节点可以找到下一个节点)

5.然后size++,变成2;modCount++变成2

第三次添加:

重新LinkLast()

e;l;newNode重新赋值

1.首先e-奇男子,l = last为0x002(上一个节点地址即赋值给下一个首节点,第二个节点的首节点可以找到上一个节点)

2.newNode对象(l,e,null)找到第二个节;所以第二个节点为【0x003】;

3.然后last =newNode【0x003】

4.然后判断条件,l.next = newNode【0x003】(下一个节点地址即赋值给上一个尾节点,上一个节点可以找到下一个节点)

5.然后size++,变成3;modCount++变成3

面试题

LinkedList底层数据结构是什么?

双向链表

ArrayList 和 LinkedList的效率区别:

​ ArrayList底层:一维数组

​ LinkedList底层:双向链表

​ 添加数据 – ArrayList扩容的情况:LinkedList快

​ 添加数据 – ArrayList不扩容的情况:ArrayList快(size指针指哪里添加到哪里)

​ 查询数据:ArrayList快(ArrayList下标查找,LinkedList需要遍历数据 )

​ 删除数据:LinkedList快(ArrayList删除要往前移动元素,LinkedList删除只要断链接添链接)

​ 修改数据:ArrayList快(修改需要先查询)

补充:平时我们一般使用ArrayList,是因为众多业务中查询功能使用最为频繁,而ArrayList查询功能比LinkedList更快,所以我们选择使用ArrayList会更多

LinkedList如何实现删除?

​ 1.通过下标找到要删除的节点

​ 2.把要删除的节点的下一个节点地址赋值给上一个节点的next

​ 3.把要删除的节点的上一个节点地址赋值给下一个节点的prev

手写单向链表和双向链表

手写单向链表

简单实现

粗略思路:

节点(元素,下一个节点,有参构造)

首节点,尾节点,size

添加(new节点,判断赋值给节点相应位置)

遍历 迭代器 方法实现(仿写底层)判断有没有元素,获取下一个元素

public class UnidirectionalLinkedList<E> {private Node<E> first;private Node<E> last;private int size;public void add(E e){Node<E> node = new Node<>(e, null);if(first == null){first = node;}else{last.next = node;}last = node;size++;}public Iterator<E> iterator(){return new Itr();}public class Itr implements Iterator<E>{private int cursor;private Node<E> node = first;@Overridepublic boolean hasNext() {return cursor != size;}@Overridepublic E next() {E item = node.item;node = node.next;cursor++;return item;}}public static class Node<E>{E item;Node<E> next;public Node(E item, Node<E> next) {this.item = item;this.next = next;}}}public class Test01 {public static void main(String[] args) {UnidirectionalLinkedList<String> list = new UnidirectionalLinkedList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");Iterator<String> it = list.iterator();while(it.hasNext()){String element = it.next();System.out.println(element);}}
}

手写双向链表

简单实现

粗略思路:

节点(上一个节点,元素,下一个节点,有参构造)

首节点,尾节点,size

添加(获取上一个节点,new节点,判断赋值给节点相应位置)

遍历 迭代器 方法实现(仿写底层)判断有没有元素,获取下一个元素

package com.qf.bidirectional_linked_list;import java.util.Iterator;public class BidirectionalLinkedList<E> {private Node<E> first;private Node<E> last;private int size;public void add(E e){Node<E> l = last;Node<E> node = new Node<>(l,e, null);if(first == null){first = node;}else{last.next = node;}last = node;size++;}public Node<E> getLast() {return last;}public Iterator<E> iterator(){return new Itr();}public class Itr implements Iterator<E>{private int cursor;private Node<E> node = first;@Overridepublic boolean hasNext() {return cursor != size;}@Overridepublic E next() {E item = node.item;node = node.next;cursor++;return item;}}public static class Node<E>{Node<E> prev;E item;Node<E> next;public Node(Node<E> prev,E item, Node<E> next) {this.prev = prev;this.item = item;this.next = next;}}}public class Test01 {public static void main(String[] args) {BidirectionalLinkedList<String> list = new BidirectionalLinkedList<>();list.add("aaa");list.add("bbb");list.add("ccc");list.add("ddd");list.add("eee");//正序遍历Iterator<String> it = list.iterator();while(it.hasNext()){String element = it.next();System.out.println(element);}System.out.println("-----------------------");//倒序遍历Node<String> node = list.getLast();while(node != null){System.out.println(node.item);node = node.prev;}}
}

总结

手撕实现类

1.手撕ArrayList底层源码
2.手撕LinkedList底层源码
ArrayList 和 LinkedList的效率区别
手写单向链表
手写双向链表

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

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

相关文章

jmeter发送请求参数如何使用变量

问题描述 发送jmeter请求时&#xff0c;想设置请求参数为变量 解决方法

基于yolov5的草莓成熟度检测系统,可进行图像目标检测,也可进行视屏和摄像检测(pytorch框架)【python源码+UI界面+功能源码详解】

功能演示&#xff1a; 基于yolov5的草莓成熟度检测系统&#xff0c;系统既能够实现图像检测&#xff0c;也可以进行视屏和摄像实时检测_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov5的草莓成熟度系统是在pytorch框架下实现的&#xff0c;这是一个完整的项目…

基于YOLOv8/YOLOv7/YOLOv6/YOLOv5的条形码二维码检测系统(深度学习+UI界面+训练数据集+Python代码)

摘要&#xff1a;在物流和制造业中&#xff0c;开发一套高效的条形码与二维码识别系统显得尤为关键。本博文深入探讨了如何利用深度学习技术打造出一套先进的条形码及二维码检测系统&#xff0c;并且提供了一套完整的实施方案。该系统搭载了性能卓越的YOLOv8算法&#xff0c;并…

php7.3.4连接sqlserver(windows平台)

前言 有个项目需要手上laravel连接客户的sqlserver数据库读取数据&#xff0c;故在本地开发的lnmp环境中&#xff0c;php需要增加扩展 过程 从微软官网下载sqlsrv扩展,注意注意php版本&#xff0c;下载地址 解压的文件会有nts和ts两个版本&#xff0c;本地打开phpinfo查看 将…

如何在Linux系统安装SVN并配置固定公网地址远程访问【内网穿透】

文章目录 前言1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件 3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口 5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6…

C++开发基础——IO操作与文件流

一&#xff0c;基础概念 C的IO操作是基于字节流&#xff0c;并且IO操作与设备无关&#xff0c;同一种IO操作可以在不同类型的设备上使用。 C的流是指流入/流出程序的字节序列&#xff0c;在输入操作中数据从外部设备(键盘&#xff0c;文件&#xff0c;网络等)流入程序&#x…

关于c++的protected关键字

关于c的protected关键字 分类引言例子1&#xff09;错误的demo2&#xff09;改正的demo protected在c中的含义与作用 分类 c基础知识 引言 做了很业务&#xff0c;c基础知识却忘了很多&#xff0c;今天看了一个例子&#xff0c;唤醒了我关于c三大特性之一----封装&#xff0…

信息抽取在旅游行业的应用:以景点信息抽取为例

开源项目推荐 今天先给大家推荐一个开源项目&#xff0c;多模态AI能力引擎平台: 免费的自然语言处理、情感分析、实体识别、图像识别与分类、OCR识别、语音识别接口&#xff0c;功能强大&#xff0c;欢迎体验。 https://gitee.com/stonedtx/free-nlp-api 场景描述 在旅游行业…

echarts vue里画一个简单的环状饼图

<!--观察记录--><div class"teach-plan observe-record"><div class"title-common"><div class"title-common-left">观察记录</div></div><div class"teach-plan-cont"><div class"…

pytest生成allure的报告

首先要下载安装配置allure allure serve ./outputs/allure_report 可以生成html的文件自动在默认浏览器中打开

蓝桥杯每日一题 走迷宫bfs 超超详细解释!!!

昨天学习了bfs的基本概念&#xff0c;今天来做一道经典习题练练手吧&#xff01; bfs常用的两类题型 1.从A出发是否存在到达B的路径(dfs也可) 2.从A出发到B的最短路径&#xff08;数小:<20才能用dfs&#xff09; 遗留的那个问题的答案- 题目&#xff1a;走迷宫 答案&…

Biomedical knowledge graph-enhanced prompt generation for large language models

1. 生物医学知识图谱增强大语言模型提示生成 论文地址&#xff1a;[2311.17330] Biomedical knowledge graph-enhanced prompt generation for large language models (arxiv.org) 源码地址&#xff1a;https://github.com/BaranziniLab/KG_RAG 2. 摘要 大语言模型&#xff0…

【PHP+代码审计】PHP基础——流程控制

&#x1f36c; 博主介绍&#x1f468;‍&#x1f393; 博主介绍&#xff1a;大家好&#xff0c;我是 hacker-routing &#xff0c;很高兴认识大家~ ✨主攻领域&#xff1a;【渗透领域】【应急响应】 【Java、PHP】 【VulnHub靶场复现】【面试分析】 &#x1f389;点赞➕评论➕收…

[nlp入门论文精读] | Transformer

写在前面 最近工作从CV转向了NLP&#xff0c;于是空余时间便跟着哔哩哔哩李沐老师的视频学习。其实研一NLP课程讲论文的时候&#xff0c;我们小组就选择了经典的Attention和Bert&#xff0c;但还有很多细节并不完全理解&#xff0c;实际使用时也很困惑。 因此这个系列就来记…

C语言快速入门之字符函数和字符串函数

一.字符分类函数和字符转换函数 C语言中有一系列的函数专门做字符分类的&#xff0c;就是区分一个字符是属于什么类型的&#xff0c;头文件是 #include <ctype.h> 以下是具体函数&#xff1a; 这些函数的使用方法类似&#xff0c;我们写出一些代码来举例。 例如&…

神经网络线性量化方法简介

可点此跳转看全篇 目录 神经网络量化量化的必要性量化方法简介线性对称量化线性非对称量化方法神经网络量化 量化的必要性 NetworkModel size (MB)GFLOPSAlexNet2330.7VGG-1652815.5VGG-1954819.6ResNet-50983.9ResNet-1011707.6ResNet-15223011.3GoogleNet271.6InceptionV38…

【力扣精选算法100道】——二进制求和

LCR 002. 二进制求和 - 力扣&#xff08;LeetCode&#xff09; 目录 &#x1f388;了解题意 &#x1f388;算法分析 &#x1f6a9;cur1>0 &#x1f6a9;cur2>0 &#x1f6a9;t &#x1f388;实现代码 &#x1f388;了解题意 遵循二进制加法法则&#xff0c;如果俩…

单通道 6 阶高清视频滤波驱动电路芯片D1675,一款高清视频信号译码、编码的滤波器和缓冲器

1、概述&#xff1a; D1675单电源工作电压为2.5V到5V&#xff0c;是一款高清视频信号译码、编码的滤波器和缓冲器。与使用分立元件的传统设计相比&#xff0c;D1675更能节省PCB 板面积&#xff0c;并降低成本以及提高视频信号性能。D1675集成了一个直流耦合输入缓冲器、一个消除…

一分钟就能搞定发成绩这件事,你信吗?

快节奏的现代教育环境中&#xff0c;每一分钟都显得尤为宝贵。对于老师和家长来说&#xff0c;及时、准确地获取学生的成绩信息是关乎学生学习进度和效果的重要环节。那么&#xff0c;有没有一种方法能在短短一分钟内完成成绩的发布和查询呢&#xff1f;答案是肯定的&#xff0…

OceanBase4.2版本 Docker 体验

&#x1f4e2;&#x1f4e2;&#x1f4e2;&#x1f4e3;&#x1f4e3;&#x1f4e3; 哈喽&#xff01;大家好&#xff0c;我是【IT邦德】&#xff0c;江湖人称jeames007&#xff0c;10余年DBA及大数据工作经验 一位上进心十足的【大数据领域博主】&#xff01;&#x1f61c;&am…