Java学习_15_集合进阶及基本数据结构


前言

博客仅记录个人学习进度和一些查缺补漏。
学习内容:BV17F411T7Ao


一、单列集合

在这里插入图片描述
collection中每次添加一个元素,而map中每次添加一组元素,类似于索引匹配具体的值一样。
在这里插入图片描述

在写C的时候vector用的很多,结果在JAVA中就成了已经淘汰的集合了
在这里插入图片描述
set就可以用来去重等操作。

顶层父类collection

基本方法

在这里插入图片描述
collection是一个接口,不能直接创建对象,其中提供了一些方法,为了学习这些方法,只能通过多态,创建它的底层实现类ArrayList的对象。

// 使用多态创建collection
        Collection<String> coll = new ArrayList<>();

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
基本都是返回Boolean类型,因为集合不像数组一样存在明确索引。
在这里插入图片描述
如果是自定义类型,在使用contain判断两个对象是否为同一个对象的时候,需要注意有没有在自定义类中重写equals方法,因为contain底层调用的就是该对象的equals方法,没有重写的时候会自动去调用object类的equals而判断地址值是否一致,因为S4和S1都是new出来的,地址值显然不一样,所以重写equals方法之前contain不包含S4。
在这里插入图片描述

1、迭代器遍历

单纯for循环遍历只有List那边能用,Set这边用不了
在这里插入图片描述

在这里插入图片描述
其中,Iterator是一个迭代器对象,可以用list的iterator方法来进行赋值(实际上就是创建了指向当前集合内0索引的指针)。
hasNext() 方法返回Boolean值,表示的当前指针是有值,有返回true,指向null返回false。
next() 方法返回对应元素类型值,表示当前指向元素的对象地址值,然后向指向下一个索引。
例如:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
对于上述代码,最后指针已经指向了没有元素的位置了,再获取当前指针内部数值是没有该元素的。
同理也可以说明在迭代完成的时候,指针是不会回到第一个元素位置的。

也不难理解,如果一个循环中出现两次next方法的时候,如果元素中的个数无法整除next方法出现的次数,就会产生后续next方法已经指空而产生报错的情况。

在这里插入图片描述
注意,在迭代进行的过程中,无法通过集合的方法进行remove,只能使用迭代器提供的remove方法。
在这里插入图片描述

2、增强for遍历

底层就是由迭代器实现的,仅是为了简化迭代器的代码书写而出现的。
所有的单列集合和数组才能使用增强for遍历。
在这里插入图片描述
在这里插入图片描述
简写方式:集合名字+for
修改s(第三方临时变量)是不会修改原本集合中的数据的。

3、lambda表达式遍历

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
此处accept就是在匿名内部类中重写的那一部分一样,也就是遍历s所需要做的事。
表达式可以简写为:
在这里插入图片描述

collection总结

在这里插入图片描述

List系列集合

List集合是有序的,有索引并且可重复的元素的集合.

同样的,List也是一个接口,需要使用ArrayList来进行实现。
在这里插入图片描述
按索引插入不会挤占原有的元素,而是将原有元素向后移动。在这里插入图片描述
删除有两种方式:通过索引删除或者通过元素值进行删除。虚拟机会给我们提供方法具体使用哪一个重载。
(再调用方法的时候,会优先调用实参与形参相符合的方法)
在这里插入图片描述

在这里插入图片描述
如果需要删除元素值为1的那个元素,可以使用手动装箱的方法(remove不会自动装箱,因为要优先匹配索引),先创造出对应元素的那个类型。
在这里插入图片描述

被修改的元素会被返回。
在这里插入图片描述

List系列集合的遍历

在这里插入图片描述

1.迭代器遍历
在这里插入图片描述
2.增强for遍历
在这里插入图片描述

3.lambda表达式遍历

匿名内部类:
在这里插入图片描述
lambda:
在这里插入图片描述
4.普通for遍历
在这里插入图片描述
5.列表迭代器
ListIterator,专为列表设计的迭代器,专门添加了向前移动指针的方法,并且在遍历的过程中,可以添加一个元素(跟remove一样,不能使用原本集合的remove、add,只能用迭代器自身方法来添加)

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
细节:迭代器用于找到某一个指定元素后,在其前后插入新元素或者删除对应的元素。增强for和lambda表达式用于遍历集合中所有的元素。普通for用于对索引的数学计算有所要求的情况,例如索引参与了遍历中某些方法的使用的时候。

ArrayList集合

底层原理

ArrayList底层是数组结构的
再利用空参创建集合以后,在底层会创建一个默认长度为0的数组。
size表示元素的个数,也表示下次存入的位置(索引)
在这里插入图片描述

添加第一个元素的时候,底层会创建一个新的长度为10的而数组,然后将一开始创建的指针指向这个数组

在这里插入图片描述

存满时,会创建一个新数组,长度为原来的1.5倍,再将原来的数组全部拷贝进来。

在这里插入图片描述
如果一次添加多个数组,1.5倍当不下,则新创建的长度以实际长度为准
在这里插入图片描述

alt + 7 显示方法大纲

添加第一个元素:
在这里插入图片描述

后续添加元素:
在这里插入图片描述
记录:多听几遍,确实有点模糊

LinkList集合

底层数据结构是双向链表,查询慢,增删快,适合用于操作首尾元素,也为此增添了很多独有API
其中Node是LinkList独有的内部类,也是双向链表实现的基础
在这里插入图片描述
在这里插入图片描述

添加第一个节点:
在这里插入图片描述
添加第二个节点:
在这里插入图片描述
添加第三个节点:
在这里插入图片描述

迭代器原理

在创建迭代器的时候,本质上就是创建了一个迭代器集合,其中每一个迭代器指向了集合中对应的元素。
在这里插入图片描述
并发修改异常:使用了非迭代器方法来修改或者删除元素,这样不会修改迭代器相关信息,会造成迭代器指针对应不上集合中的元素从而产生异常,所以需要使用迭代器提供的修改或者删除,其底层也会调用集合的删改方法,对两边同时进行修改
在这里插入图片描述

二、基本数据结构


常见数据结构:
栈、队列、数组、链表、二叉树、二叉查找树、平衡二叉树、红黑树。
都是408的重要考点,之前就很熟悉了,但是都是建立在C++可以使用指针和结构体的情况下,Java中没有指针,就需要通过特定的类来实现具体的数据结构。

1、栈

特点:先进后出,后进先出。开口方向是栈顶,最下方是栈底。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
同时也是递归方法的主要存储思想。方法被压进栈内存,从而实现递归栈。

2、队列

特点:先进先出,后进后出,一个通道分为仅入和仅出,队首是最开始进入的那一个元素,队尾是最后加入的那个元素。

在这里插入图片描述

3、数组

特点:顺序表,在内存中相邻元素的地址值也是相邻的。可以实现随机存取,查询快,增删慢
在这里插入图片描述

4、链表

特点:非顺序表,每一个独立节点在内存中可以存在不同的地方,每一个节点应该存储下一个节点的位置信息。查询慢(查询任何一个元素都要从头开始往后找),增删快
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
双向链表也是非常实用的链表结构了,专用于查找位于表两头的数据。
在这里插入图片描述

5、二叉树

类似于链式存储,但是树形结构的每个节点都会有各自的子节点与父节点。
其中每个节点有一个父节点,两个子节点的数据结构成为二叉树(根节点没有父节点)(二叉树中,任意节点的度小于2)
在这里插入图片描述
在这里插入图片描述

度:每一个节点的子节点数量。
树高:总层数,从根节点开始算第一层。
子树:以左或者右节点为根节点的一棵树。

二叉树的遍历:

前序遍历

从根节点开始,按照根左右方式进行遍历
在这里插入图片描述

中序遍历

从根节点开始,按照左右根方式进行遍历
这个顺序对于二叉排序树则是排序顺序。
在这里插入图片描述

后序遍历

从根节点开始,按照左右中的方式进行遍历
在这里插入图片描述

层序遍历

从根节点开始一层一层的遍历
在这里插入图片描述

二叉查找树

又称二叉排序树或者二叉搜索树
每一个节点上最多有两个子节点,任意节点的左子树上的所有值都小于当前节点,任意节点的右子树上的所有值都大于当前节点。

在添加节点的时候:
小的存左边,大的存右边,相同的不存(再根据平衡二叉树规则进行调整)

在这里插入图片描述

平衡二叉树

规则:任意节点的左右子树高度差不超过1
如下图,明显不是平衡二叉树:
明显不是
如下图,明显是平衡二叉树:
在这里插入图片描述

平衡二叉树的旋转

平衡二叉树为了保持平衡,需要对整体进行检查以及调整,分为左旋和右旋,在拆入新节点时触发,触发后开始调整。
(408基础,平衡调整的难度跟红黑调整完全不是一个难度,更别说红黑删了)
从添加的节点开始想上寻找第一个不平衡的节点。

对于任何一个最小不平衡子树A,不平衡分为四种情况:
LL:在A的左孩子的左子树中插入导致不平衡
RR:在A的右孩子的右子树中插入导致不平衡
LR:在A的左孩子的右子树中插入导致不平衡
RL:在A的右孩子的左子树中插入导致不平衡

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

红黑树

究极难点,408年年说要考三年了没考过一次。红黑删至今没有学明白。
在这里插入图片描述
每个叶子节点都是null,这是B树的性质。

红黑规则:

根叶黑,不红红,黑相等
在这里插入图片描述
简单路径:最短单向联通路径,无重复节点的一个顶点到另一个顶点的最短路径。

插入时违背规则的例子:
在这里插入图片描述

调整后:
在这里插入图片描述

添加节点

在这里插入图片描述

根据父、叔的颜色规则有不同的情况需要考虑

红黑删除

//后续有时间再更新

三、泛型

就是之前集合中写的<>内的内容,提示数据类型

在这里插入图片描述
如果集合创建时没有规定是什么类型的集合,在add的时候就可以加入任何数据类型。
注意:
1、泛型中只能写引用数据类型,如Integer,不能写基本数据类型,如int。(因为基本数据类型不能转object)
2、泛型在被指定具体类型后,传入数据时仅能传入该类型或者其子类类型。
3、如果不写泛型,类型默认是object。

在这里插入图片描述
在这里插入图片描述
但如果集合元素不一致,在遍历的时候就无法使用对象本身的任何功能了(除了继承自object类的几个基本方法,如toString)
在这里插入图片描述

所以泛型就出现需要了,在创建集合的时候就规定好了这个集合只能使用哪种类型。这样就可以避免强制类型转换出现的异常(要注意,在集合内部存储的时候仍然看作object类型,在使用的时候虚拟机会先将指定对象强转成指定类型再使用。),也可以使用该对象的特有功能。
在这里插入图片描述

class文件中不存在泛型这一概念,编译成class文件时会产生泛型的擦除。因为JDK5以前代码量已经很多了,只能在入口处添加审核机制,其内部处理
在这里插入图片描述

泛型类

当一个类中,某个变量的数据类型不确定的时候,就可以定义带有泛型的类,ArrayList就是一个很好的例子。

在这里插入图片描述
此处E可以理解为变量,但不是记录数据用,是用来标记数据的类型。可以写E,也可以写T V K
例如ArrayList,底层就是一个object类的数组;
E表示一个不确定的类型,该类名在后面已经定义过了。
e表示形参的名字,指一个变量。


细节:
Arrays.toString(数组)可以拼接数字成为字符串。

在这里插入图片描述

泛型方法

方法中形参类型不确定的时候,可以使用类名后面定义的泛型来预指定传入形参的类型
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
例如此时想要创建一个对于所有E的集合都能使用的一个工具方法,在不确定E的类型的时候虚拟机就会报错
在这里插入图片描述
直接写E也会报错
在这里插入图片描述

需要在修饰符后面进行定义。

扩展:不定数量形参
在这里插入图片描述

泛型接口

在这里插入图片描述
对于方式1,就是在接口集合的基础上,做一个新的子接口,在实现类时直接给出具体类型,如String。
在这里插入图片描述

对于方式2,就跟泛型方法一样,在类名后面给出泛型的定义,这样就能在创建对象的时候对应上具体的泛型。
在这里插入图片描述
在实现时指定泛型的具体类型
在这里插入图片描述

泛型的继承以及通配符

泛型本身不具备继承性(就是说泛型里面是什么类型,就只能是什么类型,即使这些类型是继承而来的),但是数据具有继承性。

例如:
在这里插入图片描述
但是集合本身可以添加泛型指定那个类型的子类对象,例如:
在这里插入图片描述

回到第一个例子中,如果希望传入数据可以是ye,fu或zi,可以使用前一节的泛型方法实现:
在这里插入图片描述
但是这种方法会使得任意类型都可以传入该方法。
如果需要限定成一个家族类可以访问,那么就可以使用泛型的通配符。
在这里插入图片描述
任意类型:
在这里插入图片描述
继承类型:
在这里插入图片描述

在这里插入图片描述

四、Set

是一种无序、不可重复、没有索引的集合。
在这里插入图片描述

Set集合常见方法

在这里插入图片描述
在这里插入图片描述
此时注意set中add方法的返回值,实际上是检测当前集合中是否能添加该元素(实现去重)
在这里插入图片描述

集合本身没有顺序不能通过索引遍历,但是可以使用迭代器进行遍历
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

HashSet

在这里插入图片描述

哈希表,即将元素通过hash计算公式计算出哈希值,然后将对象挂在对应的索引上,而hashset的底层HashMap

在这里插入图片描述在这里插入图片描述
这样会导致堆叠,所以还需要碰撞处理
在这里插入图片描述

在这里插入图片描述

没有重写hashcode的情况下是通过不同对象的地址来处理得到hash值
hashcode方法在对应的类中去重写
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
小部分情况下,不同的属性值也会产生相同的hashcode
在这里插入图片描述
加载因子就是已存入元素数量/数组长度
在这里插入图片描述
在这里插入图片描述
注意是与计算,而不是取余。

在这里插入图片描述
在这里插入图片描述
一种碰撞处理方式:挂载
在这里插入图片描述
当链表长度大于等于64的时候会转换成红黑树来增加查找速度。
在这里插入图片描述

hashset的三个问题

在这里插入图片描述

在这里插入图片描述
存是挂载,取是顺序
在这里插入图片描述
链表不是顺序结构,自然没有索引

在这里插入图片描述
通过hashcode和equals方法实现去重

LinkedHashSet

继承自HashSet,一种有序、不重复、无索引的集合
在这里插入图片描述
有序是通过双链表机制实现的,每次添加到集合的时候额外添加到一个双向链表中,在遍历的时候直接遍历这个双向链表

在这里插入图片描述

TreeSet

底层是TreeMap
在这里插入图片描述

排序是根据红黑树来实现的。默认从小到大的顺序。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

实际上是按照ASCII码表中的顺序排列的。和字符串长度无关,仅比较首字母。
在进行插入的时候,需要重写排序规则Comparable

仅需要比较元素的属性的时候。
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
需要按照特殊规则比较对应元素的时候(多值比较)或者说更改默认的从小到大的升序。并且方式二的优先级更高。
在这里插入图片描述
此时compare是默认的方法
在这里插入图片描述
重写compare方法,使用了比较器。

在这里插入图片描述
之前用的C写这个题,用的结构体比较,头都是麻的,现在可以使用集合的方法来进行排序了。
在这里插入图片描述
继承Comparable接口,使得该JavaBean可以被排序。

在这里插入图片描述

总结

集合、泛型是各种算法和数据结构中非常常用的功能,基本数据结构更是408考试的重中之重。
对集合这一特性有了更深刻的认识,相比以前考研时,现在更多的会去都底层源码,了解实现过程,而不是单纯的记忆。
相比C、C++,JAVA的继承和重载使得代码更加规范,虽然繁冗但是思路也较为简单便于思考实现。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值