Day14——数据结构和集合源码

1.数据结构

简单来说,数据结构,就是一种程序设计优化的方法论,研究数据的逻辑结构物理结构以及它们之间相互关系,并对这种结构定义相应的运算,目的是加快程序的执行速度、减少内存占用的空间

1.1 数据的逻辑结构

数据的逻辑结构指反映数据元素之间的逻辑关系,而与数据的存储无关,是独立于计算机的。

  1. 集合结构:数据结构中的元素之间除了“同属一个集合” 的相互关系外,别无其他关系。集合元素之间没有逻辑关系。
  2. 线性结构:数据结构中的元素存在一对一的相互关系。比如:排队。结构中必须存在唯一的首元素和唯一的尾元素。体现为:一维数组、链表、栈、队列。
  3. 树形结构:数据结构中的元素存在一对多的相互关系。比如:家谱、文件系统、组织架构。
  4. 图形结构:数据结构中的元素存在多对多的相互关系。比如:全国铁路网、地铁图。

1.2 数据的存储结构(物理结构)

数据的物理结构/存储结构:包括数据元素的表示和关系的表示。数据的存储结构是逻辑结构用计算机语言的实现,它依赖于计算机语言。

  1. 结构 1:顺序结构:顺序结构就是使用一组连续的存储单元依次存储逻辑上相邻的各个元素。
    • 优点: 只需要申请存放数据本身的内存空间即可,支持下标访问,也可以实现随机访问。
    • 缺点: 必须静态分配连续空间,内存空间的利用率比较低。插入或删除可能需要移动大量元素,效率比较低。
  2. 结构 2:链式结构:不使用连续的存储空间存放结构的元素,而是为每一个元素构造一个节点。节点中除了存放数据本身以外,还需要存放指向下一个节点的指针。
    • 优点:不采用连续的存储空间导致内存空间利用率比较高,克服顺序存储结构中预知元素个数的缺点。插入或删除元素时,不需要移动大量的元素。
    • 缺点:需要额外的空间来表达数据之间的逻辑关系,不支持下标访问和随机访问。
  3. 结构 3:索引结构:除建立存储节点信息外,还建立附加的索引表来记录每个元素节点的地址。索引表由若干索引项组成。索引项的一般形式是:(关键字,地址)。
    • 优点:用节点的索引号来确定结点存储地址,检索速度快。
    • 缺点: 增加了附加的索引表,会占用较多的存储空间。在增加和删除数据时要修改索引表,因而会花费较多的时间。
  4. 结构 4:散列结构:根据元素的关键字直接计算出该元素的存储地址,又称为 Hash 存储。
    • 优点:检索、增加和删除结点的操作都很快。
    • 缺点:不支持排序,一般比用线性表存储需要更多的空间,并且记录的关键字不能重复。

1.3 运算结构

施加在数据上的运算包括运算的定义和实现。运算的定义是针对逻辑结构的,指出运算的功能;运算的实现是针对存储结构的,指出运算的具体操作步骤。

  1. 分配资源,建立结构,释放资源
  2. 插入和删除
  3. 获取和遍历
  4. 修改和排序

2.一维数组

在 Java 中,数组是用来存放同一种数据类型的集合,注意只能存放同一种数据类型。

3.链表

链表中的基本单位是节点(Node)。

3.1 单向链表

class Node{Object data;Node next;public Node(Object data){this.data = data;}
}
Node node1 = new Node("AA");
Node node2 = new Node("AA");
node1.next = node2;

3.2 双向链表

class Node{Node prev;Object data;Node next;public Node(Object data){this.data = data;}public Node(Node prev,Object data,Node next){this.prev = prev;this.data = data;this.next = next;}
}Node node1 = new Node(null,"AA",null);
Node node2 = new Node(node1,"BB",null);
Node node3 = new Node(node2,"CC",null);
node1.next = node2;
node2.next = node3;

4.二叉树

class TreeNode{TreeNode left;Object data;TreeNode right;public TreeNode(Object data){this.data = data;}public TreeNode(TreeNode left,Object data,TreeNode right){this.left = left;this.data = data;this.right = right;}
}TreeNode node1 = new TreeNode(null,"AA",null);
TreeNode leftNode = new TreeNode(null,"BB",null);
TreeNode rightNode = new TreeNode(null,"CC",null);
node1.left = leftNode;
node2.right = rightNode;

5.栈

  1. 特点为先进后出。
  2. 属于抽象数据类型ADT。
  3. 可以使用数组或链表来构建。
class Stack{Object[] values;int size;public Stack(int length){values = new Object[length];}//入栈public void push(Object ele){if(size >= values.length){throw new RuntimeException("栈空间已满,入栈失败");}values[size] = ele;size++;}//出栈public Object pop(){if(size <= 0){throw new RuntimeException("栈空间已空,出栈失败");}Object obj = values[size - 1];values[size - 1] = null;size--;return obj;}
}

6.队列

  1. 特点为先进先出。
  2. 属于抽象数据类型ADT。
  3. 可以使用数组或链表来构建。
class Queue{Object[] values;int size;public Queue(int length){values = new Object[length];}//入队public void add(Object ele){if(size >= values.length){throw new RuntimeException("队列空间已满,入队失败");}values[size] = ele;size++;}//出队public Object get(){if(size <= 0){throw new RuntimeException("队列空间已空,出队失败");}Object obj = values[0];for(int i = 0;i < size - 1;i++){values[i] = values[i + 1];}values[size - 1] = null;size--;return obj;}
}

7.List实现类源码分析

7.1 ArrayList

7.1.1 ArrayList的特点

  1. 实现了List接口,存储有序的、可以重复的数据。
  2. 底层使用Object[]数组存储。
  3. 线程不安全的。

7.1.2 ArrayList源码解析

  1. JDK7.0版本:
//底层会初始化数组,数组的长度为10。Object[] elementData = new Object[10];
ArrayList<String> list = new ArrayList<>();	
list.add("AA");	//elementData[0] = "AA";
list.add("BB");	//elementData[0] = "BB";
//当要添加第11个元素时,底层的elementData数组已满,则需要进行扩容。默认扩容到原来长度的1.5倍,并将原有数组中的元素复制到新的数组中。
  1. JDK8.0版本:
//底层会初始化数组,即:Object[] elementData = new Object[]{};
ArrayList<String> list = new ArrayList<>();	
list.add("AA");	//首次添加元素时,会初始化数组elementData = new Object[10]。elementData[0] = "AA";
list.add("BB");	//elementData[0] = "BB";
//当要添加第11个元素时,底层的elementData数组已满,则需要进行扩容。默认扩容到原来长度的1.5倍,并将原有数组中的元素复制到新的数组中。

7.2 Vector

7.2.1 Vector的特点

  1. 实现了List接口,存储有序的、可以重复的数据。
  2. 底层使用Object[]数组存储。
  3. 线程安全的。

7.2.2 Vector源码解析(以JDK1.8.0_271为例)

//底层初始化数组,长度为10。Object[] elementData = new Object[10];
Vector v = new Vector();
v.add("AA");	//elementData[0] = "AA";
v.add("BB");	//elementData[1] = "BB";
//当添加到第11个元素时,需要扩容。默认扩容到原来的2倍。

7.3 LinkedList

7.3.1 LinkedList的特点

  1. 实现了List接口,存储有序的、可以重复的数据。
  2. 底层使用双向链表存储。
  3. 线程不安全的。

7.3.2 LinkedList在JDK8中的源码解析

LinkedList<String> list = new LinkedList<>();
list.add("AA");	//将"AA"封装到一个Node对象1中,list对象的属性first、last都指向此Node对象1。
list.add("BB");	//将"BB"封装到一个Node对象2中,对象1和对象2构成一个双向链表,同时last指向此Node对象2。
//因为LinkedList使用双向链表,不需要考虑扩容问题//LinkedList内部声明:
private static class Node<E>{E item;Node<E> next;Node<E> prev;
}

7.4 启示与开发建议

  1. 开发中基本不使用Vector。
  2. ArrayList底层使用数组结构:
    • 查找和添加(尾部添加)操作效率高,时间复杂度为O(1)。
    • 删除和插入操作效率低,时间复杂度为O(n)。
  3. LinkedList底层使用双向链表结构:
    • 删除和插入操作效率高,时间复杂度为O(1)。
    • 查找和添加(尾部添加)操作效率低,时间复杂度为O(n)。
  4. 在选择了ArrayList的前提下:
    • new ArrayList():底层创建长度为10的数组。
    • new ArrayList(int capacity):底层创建指定capacity长度的数组。
    • 如果在开发中,大致可以确定数组的长度,则推荐使用ArrayList(int capacity)构造器,避免了底层的扩容和复制数组操作。

8.Map实现类源码分析

8.1 HashMap

8.1.1 HashMap中元素的特点

  1. HashMap中的所有的key彼此之间是不可重复的、无序的。所有的key构成一个Set集合。key所在的类要重写hashCode()和equals()方法。
  2. HashMap中的所有的value彼此之间是可重复的、无序的。所有的value就构成了一个Collection集合。value所在的类要重写equals()方法。
  3. HashMap中的一个key-value构成一个entry。HashMap中所有的entry彼此之间是不可重复的、无序的。所有的entry构成了一个Set集合。

8.1.2 HashMap源码解析

  1. JDK7中创建对象和添加数据过程
//创建对象的过程中,底层会初始化数组Entry[] table = new Entry[16];
HashMap<String,Integer> map = new HashMap<>();
//"AA"和11封装到一个Entry对象中,考虑将此对象添加到table数组中。
map.put("AA",11);
/*** 添加/修改的过程:将(key1,value1)添加到当前的map中* 首先,需要调用key1所在类的hashCode()方法,计算key1对应的哈希值1,此哈希值1经过某种算法(hash())之后,得到哈希值2.* 哈希值2再经过某种算法(indexFor())之后,就确定了(key1,value1)在数组table中的索引位置1。* 1.1 如果此索引位置i的数组上没有元素,则(key1,value1)添加成功。--->情况1* 1.2 如果此索引位置i的数组上有元素(key2,value2),则需要继续比较key1和key2的哈希值2--->哈希冲突*      2.1 如果key1的哈希值2与key2的哈希值2不相同,则(key1,value1)添加成功。--->情况2*      2.2 如果key1的哈希值2与key2的哈希值2相同,则需要继续比较key1和key2的equals()。要调用key1所在类的equals(),将key2作为参数传递进去。*          3.1 调用equals(),若返回false:则(key1,value1)添加成功。--->情况3*          3.2 调用equals(),若返回true:则认为key1和key2是相同的,默认情况下value1替换原有的value2。** 说明:情况1:将(key1,value1)存放到数组的索引i的位置*      情况2和情况3:(key1,value1)元素与现有的(key2,value2)构成单向链表结构,(key1,value1)指向(key2,value2)** 随着不断添加元素,在满足如下条件下考虑扩容:*    (size >= threshold) && (null != table[bucketIndex])*    当元素个数达到临界值(->数组长度 * 加载因子)时,考虑扩容。默认临界值=16*0.75=12。*    默认扩容到原来的2倍。*/
  1. JDK8与JDK7的不同之处

    • 在JDK8中,当我们创建了HashMap实例之后,底层并没有初始化table数组。当首次添加(key,value)时进行判断,如果发现table尚未初始化,则对数组进行初始化。
    • 在JDK8中,HashMap底层定义了Node内部类,替换JDK7中的Entry内部类。这意味着创建的数组为Node[]。
    • 在JDK8中,如果当前的(key,value)经过一系列判断之后,可以添加到当前的数组角标i中。若此时角标i位置上有元素,在JDK7中是将新的(key,value)指向已有的旧元素(头插法)。而在JDK8中是旧元素指向新的(key,value)元素(尾插法)。
    • JDK7的结构组成为:数组+单向链表。
    • JDK8的结构组成为:数组+单向链表+红黑树。
    • 如果数组索引i位置上的元素个数达到8,并且数组的长度达到64时,我们就将此索引i位置上的多个元素改为使用红黑树的结构进行存储。因为在红黑树上进行put()/get()/remove()操作的时间复杂度为O(logn),比单向链表O(n)的性能较好。
  2. 属性/字段

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 默认的初始容量16
static final int MAXIMUM_CAPACITY = 1 << 30; //最大容量 1 << 30
static final float DEFAULT_LOAD_FACTOR = 0.75f; //默认加载因子
static final int TREEIFY_THRESHOLD = 8; //默认树化阈值 8,当链表的长度达到这个值后,要考虑树化
static final int UNTREEIFY_THRESHOLD = 6;//默认反树化阈值 6,当树中结点的个数达到此阈值后,要考虑变为链表
//当单个的链表的结点个数达到 8,并且 table 的长度达到 64,才会树化。
//当单个的链表的结点个数达到 8,但是 table 的长度未达到 64,会先扩容
static final int MIN_TREEIFY_CAPACITY = 64; //最小树化容量 64
transient Node<K,V>[] table; //数组
transient int size; //记录有效映射关系的对数,也是 Entry 对象的个数
int threshold; //阈值,当 size 达到阈值时,考虑扩容
final float loadFactor; //加载因子,影响扩容的频率

8.2 LinkedHashMap

8.2.1 LinkedHashMap与HashMap的关系

LinkedHashMap是HashMap的子类,LinkedHashMap在HashMap使用的数组+单向链表+红黑树的基础上,又增加了一对双向链表,记录添加的(key,value)的先后顺序。便于遍历所有的key-value。
LinkedHashMap重写了HashMap的方法:

Node<K,V> newNode(int hash, K key, V value, Node<K,V> e) {LinkedHashMap.Entry<K,V> p = new LinkedHashMap.Entry<K,V>(hash,key,value,e);linkedNodeLast(p);return p;
}

8.2.2 底层结构

LinkedHashMap内部定义了一个Entry:

static class Entry<K,V> extends HashMap.Node<K,V>{Entry<K,V> before,after;	//增加的双向链表Entry(int hash,K key,V value,Node<K,V> next){super(hash,key,value,next);}
}

8.3 HashSet和LinkedHashSet的源码分析

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

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

相关文章

小航助学题库白名单竞赛考级蓝桥杯等考scratch(12级)(含题库教师学生账号)

需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09; 需要在线模拟训练的题库账号请点击 小航助学编程在线模拟试卷系统&#xff08;含题库答题软件账号&#xff09;

webpack学习-2.管理资源

webpack学习-2.管理资源 1.这章要干嘛2.加载css注意顺序&#xff01; 3.总结 1.这章要干嘛 管理资源&#xff0c;什么意思呢&#xff1f;管理什么资源&#xff1f;项目中经常会 导入各种各样的css文件&#xff0c;图片文件&#xff0c;字体文件&#xff0c;数据文件等等&#…

C#-并行编程的概念及其运用

目录 一、介绍 二、并行编程 1、Parallel类 2、Timer类 1、使用Timer类 一、介绍 并行编程实际就是同一时间处理不同任务&#xff0c;可分为数据并行性&#xff08;在不同任务间同时处理相同数据&#xff09;和任务并行性&#xff08;同时执行不同的功能&#xff09;&…

一个潜水多年的体制内的生意人来实际谈谈老百姓该怎么办?

建议大家去看看天涯神贴《一个潜水多年的体制内的生意人来实际谈谈老百姓该怎么办&#xff1f;》 天涯神帖&#xff1a;《一个潜水多年的体制内的生意人来实际谈谈老百姓该怎么办&#xff1f;》 原作者&#xff1a;龙卧草庐 原文PDF链接&#xff1a;https://pan.quark.cn/s/7f8…

qt相关宏

官网宏&#xff1a; https://doc.qt.io/qt-5/qtglobal.html Q_UNLIKELY&#xff08;expr&#xff09;&#xff1a; 向编译器提示封闭条件&#xff0c;expr&#xff0c;很可能评估为false。 使用该宏可以帮助编译器优化代码。 Q_LIKELY&#xff08;expr&#xff09;&#xff1a;…

(整理中)01 - 模块机制

---- 整理自 王利涛老师 课程 文章目录 1. 可加载模块1.1 Linux内核的模块机制1.2 实验&#xff1a;hello模块1.3 内核模块的构成 KDIR : ${PWD}/../../linux-5.10.4clean:make -C ( K D I R ) M (KDIR) M (KDIR)M(PWD) modules cleanKDIR : ${PWD}/../../linux-5.10.4clean:…

Vue3网站用户引导功能【Intro.js】

一、介绍 Intro.js 是一个用于创建网站用户引导、功能介绍和教程的 JavaScript 库。它允许开发者通过步骤和提示突出显示网站上的特定元素&#xff0c;以帮助用户更好地了解和使用网站的功能。以下是 Intro.js 的一些关键特点和用法介绍&#xff1a; 更多Intro.js 功能网址&a…

mac批量修改图片格式

1. 当前窗口在word文档&#xff0c;选择工具-》宏-》点击宏 2. 弹出弹框&#xff0c;起个宏名1&#xff0c;点击2添加一个宏。 输入以下代码&#xff1a; Sub 图片格式统一()图片格式统一 宏Dim iDim Height, WeightHeight 200 改成自己的高度Weight 350 改成自己的宽度On E…

STM32-GPIO

一、GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口 可配置8种输入输出模式 引脚电平&#xff1a;0V~3.3V&#xff0c;部分引脚可容忍5V 输出模式下&#xff1a;可控制端口输出高低电平&#xff0c;用以驱动LED、控制蜂鸣器、模拟通信协议输…

MIT_线性代数笔记:第 12 讲 图、网络、关联矩阵

目录 图和网络 Graphs & Networks关联矩阵&#xff08;Incidence matrices&#xff09;矩阵的零空间矩阵列空间矩阵的左零空间矩阵的行空间 本讲讨论线性代数在物理系统中的应用。 图和网络 Graphs & Networks “图”就是“结点”和“边”的一个集合。 边线上的箭头代…

力扣11.盛最多水的容器

题目描述 思路 用双指针法。 每次向内移动较短的那个板&#xff0c;能带来更大的效益。 代码 class Solution {public int maxArea(int[] height) {int res 0;int i 0,j height.length - 1;while(i < j){res height[i] < height[j] ? Math.max((j - i) * height…

2023.12.4 关于 Spring Boot 统一异常处理

目录 引言 统一异常处理 异常全部监测 引言 将异常处理逻辑集中到一个地方&#xff0c;可以避免在每个控制器或业务逻辑中都编写相似的异常处理代码&#xff0c;这降低了代码的冗余&#xff0c;提高了代码的可维护性统一的异常处理使得调试和维护变得更加容易&#xff0c;通…

photoshop实现抠图的步骤

实现抠图的主要步骤如下&#xff1a; 打开图片&#xff1a;用Photoshop打开需要抠图的图片。 选择抠图工具&#xff1a;在Photoshop工具栏中找到“套索工具”、“魔术棒工具”、“快速选择工具”等工具&#xff0c;选择其中一个作为抠图工具。 选择抠图区域&#xff1a;用抠图…

pytorch学习9-优化器学习

系列文章目录 pytorch学习1-数据加载以及Tensorboard可视化工具pytorch学习2-Transforms主要方法使用pytorch学习3-torchvisin和Dataloader的使用pytorch学习4-简易卷积实现pytorch学习5-最大池化层的使用pytorch学习6-非线性变换&#xff08;ReLU和sigmoid&#xff09;pytorc…

Linux swatch命令教程:如何监控系统活动(附案例详解和注意事项)

Linux swatch命令介绍 Swatch&#xff0c;全称为Simple Watcher&#xff0c;是一个简单的监视器&#xff0c;设计用于监控系统活动。为了使Swatch有用&#xff0c;它需要一个配置文件&#xff0c;该文件包含要查找的模式和在找到每个模式时要执行的操作。 Linux swatch命令适…

[头歌系统数据库实验] 实验3 MySQL的DDL语言

目录 第1关&#xff1a;将P表中的所有红色零件的重量增加6 第2关&#xff1a;把P表中全部红色零件的颜色改成蓝色 第3关&#xff1a;将SPJ表中由S5供给J4的零件P6改为由S3供应 第4关&#xff1a;将SPJ表中所有天津供应商的QTY属性值减少11&#xff08;用子查询方式&#x…

C标准输入输出函数

介绍 C语言中常用的输入输出函数包括&#xff1a; scanf&#xff1a;从标准输入设备&#xff08;通常是键盘&#xff09;读取数据。printf&#xff1a;将数据输出到标准输出设备&#xff08;通常是显示器&#xff09;。getchar&#xff1a;从标准输入设备读取一个字符。putcha…

云轴科技ZStack助力彬长矿业建设智能矿山

陕西彬长矿业集团有限公司&#xff08;简称彬长矿业&#xff09;选择云轴科技ZStack智能矿山云解决方案建设云基础设施&#xff1a;ZStackCube超融合一体机部署在西咸云基地机房构建私有云资源池&#xff0c;ZStackCMP多云管理平台对西咸云基地机房以及各矿井生产服务中心资源进…

【每日OJ —— 94. 二叉树的中序遍历】

每日OJ —— 94. 二叉树的中序遍历 1.题目&#xff1a;94. 二叉树的中序遍历2.解法2.1.算法讲解2.2.代码实现2.3.提交通过展示 1.题目&#xff1a;94. 二叉树的中序遍历 2.解法 2.1.算法讲解 1.首先如果在每次每个节点遍历的时候都去为数组开辟空间&#xff0c;这样的效率太低…

quickapp_快应用_快应用与h5交互

快应用与h5交互 h5跳转到快应用[1] 判断当前环境是否支持组件跳转快应用[2] h5跳转到快应用(1)deeplink方式进行跳转(推荐)(2)h5点击组件(接收参数存在问题)(3)url配置跳转(官方不推荐) 问题-浏览器问题 web组件h5页面嵌入快应用快应用发送消息到h5页面h5页面接收快应用发送的消…