集合
什么是集合
集合是java中提供的一种容器,可以用来存储多个数据,并且可以存储任意类型的数据!
数组和集合区别
数组的长度是固定的。集合的长度是可变的
数组中存储的是同一类型的元素,可以存储基本数据类型值
集合存储的都是对象。而且对象的类型可以不一致,不能存放基本数据类型
集合体系图
Collection 集合
Collection概述
Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。
Collection常用方法
public boolean add(E e) | 把给定的对象添加到当前集合中 。 |
---|---|
public boolean remove(E e) | 把给定的对象在当前集合中删除。 |
public boolean contains(E e) | 判断当前集合中是否包含给定的对象。 |
public boolean isEmpty() | 判断当前集合是否为空。 |
public int size() | 返回集合中元素的个数。 |
public Object[] toArray() | 把集合中的元素,存储到数组中。 |
public void clear() | 清空集合中所有的元素。 |
Iterator迭代器
接口来专门用于遍历集合
迭代器是一个接口,通过集合对象调用iterator方法来创建Iterator对象
快捷键 itit +回车
什么是迭代
以取集合元素为例,先判断该集合中是否存在元素,存在则取出,在判断下一个,直至判断到没有元素截至,这种取出方式专业术语叫迭代
Iterator接口的常用方法
public E next() 返回迭代的下一个元素。
public boolean hasNext() 如果仍有元素可以迭代,则返回 true。
增强for
它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,[不能对集合中的元素进行增删操作]。
增强for格式
快捷键 iter + 回车 或者 I + 回车
for(元素的数据类型 变量 : Collection集合or数组的变量名){ //写操作代码 }
它用于遍历Collection和数组。通常只进行遍历元素
增强for plus
对数组: int[] arr ={.........};
Arrays.stream(arr).forEach(System.out::println;
对集合:
Collection<String> s = new ArrayList<>(); s.add("a"); s.add("s"); s.add("d"); s.add("w"); s.forEach(System.out::println);
List集合
List集合的特点
有序,可重复
它是一个带有索引的集合
通过元素的equals方法,来比较是否为重复的元素
List集合常用方法
public void add(int index, E element)
将指定的元素,添加到该集合中的指定位置上。
public E get(int index)
返回集合中指定位置的元素·。
public E remove(int index)
移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element)
用指定元素替换集合中指定位置的元素,返回值的更新前的元素。
ArrayList集合
是List集合常用的实现类
ArrayList常用的方法
和list中的常用方法一样
多了一个Collection 常用的 add方法
LinkedList集合
常用方法
###
方法名 | 说明 |
---|---|
public void addFirst(E e) | 将指定元素插入此列表的开头。 |
public void addLast(E e) | 将指定元素添加到此列表的结尾。 |
public E getFirst() | 返回此列表的第一个元素。 |
public E getLast() | 返回此列表的最后一个元素。 |
public E removeFirst() | 移除并返回此列表的第一个元素。 |
public E removeLast() | 移除并返回此列表的最后一个元素。 |
public E pop() | 从此列表所表示的堆栈处弹出一个元素。 |
public void push(E e) | 将元素推入此列表所表示的堆栈。 |
public boolean isEmpty() | 如果列表不包含元素,则返回true。 |
Vector集合
常用方法
vector是list的子类,list中所有方法vector都可以使用,这里就介绍vector特有方法
-
1:添加功能
-
public void addElement(Object obj) -- add()
-
2:获取功能
-
public Object elementAt(int index) -- get()
-
public Enumeration elements() -- Iterator iterator()
-
boolean hasMoreElements() -- hasNext()
-
Object nextElement() -- next()
ArrayList和LinkedList、Vector集合的区别
ArrayList: 底层数据结构是数组,查询快,增删慢 线程不安全,效率高 LinkedList: 底层数据结构是链表,查询慢,增删快 线程不安全,效率高 Vector: 底层数据结构是数组,查询快,增删慢 线程安全,效率低
数据结构
常见的数据结构
栈
特点:先进后出
栈的入口、出口的都是栈的顶端位置
栈的名词:
压栈:就是存元素。
弹栈**:就是取元素。
队列
特点:先进先出
数组
数组特点:查询快 , 增删慢
查询快的原因:数组中具有索引,可以通过索引直接查取元素
增删慢的原因:要是增删得单独创建一个数组,根据需求来对这两个数组进行操作
链表
链表特点:查询慢 , 增删快
查询慢的原因:无论查那个元素都要从头查
增删快的原因:可以直接对该链表进行增删操作
具体步骤如下:
树
树的特点:既继承了数组查询快的优点又继承了链表增删快的优点
常见的树有哪些:二叉树,二叉查找数,平衡二叉树,红黑树
二叉查找数,平衡二叉树,红黑树三者属于二叉树
二叉树又分为满二叉树和完全二叉树
二叉树最多有两个子节点,左子节点和右子节点
二叉查找树
查找
查找某一个节点,我们必须从根节点查找。
1、查找的值比当前节点大,则搜索右子树 2、查找的值比当前节点小,则搜索左子树 3、查找的值等于当前值,停止搜索 4、查找最小值先找根节点的左边查询,一直找到左节点的节点,反之查找最大值从根节点右边查询一直到右节点的节点
插入
插入某一个节点,我们必须从根节点查找。
插入的值要从根节点开始比较,小于根节点,在左子树比较。大于根节点,在右子树比较
删除
删除某一个节点,根据根节点比较,找到该节点的位置直接删除,之后的其他节点再挂上去
优点
二叉查找树是为了实现快速查找产生的。它不仅支持快速查找,还支持快速插入和删除。这主要归功于二叉查找树的一个特性,那就是树中任一节点,这个节点的左子树的值总是小于这个节点的值,这个节点右子树的值总是大于这个节点的值
缺点
普通的二叉查找树容易失去平衡,退化成线性的链表。当我们插入一组元素正好是有序的时候,这时会让排序二叉树退化成链表
平衡二叉树
解决二叉树退化成一棵链表而诞生的
平衡二叉树 (AVL) 树是一种自平衡二叉查找树 (BST)
平衡二叉树在二叉查找树的基础上多了一个特性:所有节点的左右子树的高度差不能超过1 ;从而实现自平衡
红黑树
为什么有了平衡树还需要红黑树?
因为平衡树要求每个节点的左子树和右子树的高度差至多等于1,这个要求实在是太严了,导致每次进行插入/删除节点的时候,几乎都会破坏平衡树的第二个规则,进而我们都需要通过左旋和右旋来进行调整,使之再次成为一颗符合要求的平衡树
红黑树概述
红黑树是一种平衡树,他复杂的定义和规则都是为了保证树的平衡性。*如果树不保证他的平衡性,很显然这就变成一个链表了。 保证平衡性的最大的目的就是降低树的高度,因为树的查找性能取决于树的高度。所以树的高度越低搜索的效率越高! 这也是为什么存在二叉树、搜索二叉树等,各类树的目的
二叉树的一种比较有意思的叫做红黑树(红黑树是一种自平衡的二叉树,不是绝对的平衡),红黑树本身就是一颗二叉查找树,将节点插入后,该树仍然是一颗二叉查找树。也就意味着,树的键值仍然是有序的。
红黑树的约束
-
节点可以是红色的或者黑色的
-
根节点是黑色的
-
叶子节点(特指空节点)是黑色的
-
每个红色节点的子节点都是黑色的
-
任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同
红黑树的三个操作
-
左旋: 左旋用于修正红黑树中的不平衡情况
-
右旋:右旋同样用于修正红黑树中的不平衡情况
-
变色 : 变色是指改变节点的颜色,是维护红黑树平衡性的另一个重要操作。红黑树的变色操作通常与旋转操作(左旋和右旋)一起使用,用于修正红黑树在插入和删除节点后可能破坏的平衡性。
平衡二叉树和红黑树区别
平衡二叉树(Balanced Binary Tree)和红黑树(Red-Black Tree)都是为了解决普通二叉搜索树在动态操作时可能退化成链表而引入的自平衡二叉搜索树数据结构。虽然它们都具有自平衡性质,但是有一些主要区别:
-
平衡性要求:
-
平衡二叉树:平衡二叉树要求每个节点的左右子树高度差不超过1,即左子树高度和右子树高度之差的绝对值不超过1。这样的平衡要求较为严格,导致插入和删除节点时需要进行较多的旋转操作。
-
红黑树:红黑树放宽了平衡的要求,只要满足一定的性质,即可保持树的平衡。红黑树的性质包括:节点是红色或黑色、根节点是黑色、红色节点的子节点都是黑色、任何一个节点到其每个叶子节点的所有路径上黑色节点数目相同。这种放宽的平衡要求使得红黑树的插入和删除操作相对较快。
-
-
旋转操作数量:
-
平衡二叉树:在平衡二叉树中,由于要求严格的平衡,插入和删除节点时可能需要进行多次旋转操作,以恢复树的平衡性。
-
红黑树:红黑树的平衡性维护相对简单,通常情况下插入和删除节点时只需要进行一次或少数几次旋转操作和颜色变换即可。
-
-
节点存储额外信息:
-
平衡二叉树:平衡二叉树的每个节点只需要存储值和左右子节点指针即可,不需要额外存储信息。
-
红黑树:红黑树的每个节点除了值和左右子节点指针外,还需要额外存储节点的颜色信息(红色或黑色)。
-
-
适用场景:
-
平衡二叉树:由于平衡二叉树的平衡要求较为严格,适用于对平衡性要求较高的场景,例如在对树的平衡性要求非常严格的数据库索引中使用。
-
红黑树:红黑树在大多数实际应用中广泛使用,它的平衡性维护相对简单,适用于对平衡性要求较为宽松的场景,例如在大多数编程语言的标准库中用于实现集合和映射等数据结构。
-
虽然平衡二叉树和红黑树在某些方面有区别,但它们都是为了解决普通二叉搜索树的退化问题而设计的,能够在动态数据集合中保持平衡,并在查找、插入和删除等操作上具有较好的性能表现。选择使用哪种树取决于具体的应用需求和性能要求
自己总结
List和Set集合中的三个子类的特点
ArrayList类 有序、可重复、有索引、单列集合 数据结构是数组,查询快,增删慢 线程不安全,效率高
LinkedList类 有序、可重复、有索引、单列集合 数据结构是链表,查询慢,增删快 线程不安全,效率高
Vector类 有序、可重复、有索引、单列集合 数据结构是数组,查询快,增删慢 线程安全,效率低
set集合:
HashSet集合
key无序、唯一、无索引的集合
底层是HashMap
数据结构是 数组+链表+红黑树(哈希表)
LinkedHashSet集合
key有序、唯一、无索引的集合
底层LinkedHashMap
数据结构是 数组+双向链表+红黑树
TreeSet集合
key排序、唯一、无索引集合
底层是TreeMap
数据结构是 二叉查找树
hashSet是如何保证唯一的
HashSet底层是HashMap的底层,是通过hashCode()和equals()方法来保证唯一性的 具体详解 关键代码 第一步 判断是否为空 if ((tab = table) == null || (n = tab.length) == 0) n = (tab = resize()).length; 第二步 计算在数组中的索引值,并判断该索引值位置是否为空 if ((p = tab[i = (n - 1) & hash]) == null) tab[i] = newNode(hash, key, value, null); 第三步 先比较哈希值是否相等,在比较key的地址值是否相等,若不想等在比较(key是否为空和两个key通过equals比较是否相等) if (p.hash == hash && ((k = p.key) == key || (key != null && key.equals(k)))) 在添加元素前先判断该集合是否为空若为空,则给该集合赋予一个长度,然后在使用哈希值(这里通过对key进行哈希计算得到的)和哈希表的大小 n,通过对 n 进行位运算,得到一个索引值,判断该索引位置是否为空,若为空,直接添加,若不为空,则在判断 第三步 若是 true则比较链表的下一个位置的元素,若比较到最后都是false则添加进去,若出现true 则覆盖掉原value值
LinkedHashSet 和 HashSet 的关系
LinkedHashSet 是 HashSet 的子类 二者特点: HashSet 是 无序 唯一 无索引的集合 底层是HashMap 数据结构是 数组+链表+红黑树(哈希表) LinkedHashSet 是 有序 唯一 无索引的集合 底层LinkedHashMap 数据结构是 数组+双向链表+红黑树
你了解的数据结构有哪些?它们的特点分别是?
(上述记得数据结构基本无需再看,看下面的即可)
栈、队列、数组、链表、树 栈:遵循先进后出的规则 队列:遵循先进先出的规则 数组:查询快,增删慢 为什么查询快? 数组有索引,可以通过索引直接查找 为什么增删慢? 因为进行增删操作要在创建一个数组,根据要求对数据进行操作,最终再放入另一个数组中 链表: 增删快,查询慢 为什么增删快? 因为可以直接在该链表要增删的位置进行操作,不用再创建另一个链表 为什么查询慢? 因为每次查找一个数都要从链表的头部开始 树: 优点: 结合了数组和链表的优点,即查询快又增删快 分类: 树包含二叉树 二叉树又有满二叉树、完全二叉树 二叉树又包含 二叉查找树、平衡二叉树、红黑树 二叉查找树 特点: 每个父节点的左子节点值都小于父节点值,每个右节点值都大于父节点值 查找: 先和根节点比较,大的在右边找,小的在左边找 插入: 插入某一结点,查找方式和上述一样 删除: 和查找一样,找到节点删除,再把后面的拼接上 优点: 实现快速查找、插入、删除,归功于他的特点 缺点: 容易失去平衡,退化成线性链表 平衡二叉树 特点: 每个父节点的左子节点值都小于父节点值,每个右节点值都大于父节点值,且左子节点数和右子节点数高度差不能超过1 优点: 基于他的特点形成了自平衡状态,解决了二叉树退化成线性链表而诞生 缺点: 每次增删都会破坏自平衡状态,需要频繁的调整,使平衡树的性能大大折扣 红黑树 特点: 根节点和叶子节点是黑色,其他节点可以是黑色也可以是红色,每个红色节点的子节点都是黑色,任何一个节点 到其子节点路径上的黑节点个数都是相等的 操作: 左旋:用于修正红黑树中的不平衡情况 右旋:和左旋一样 变色:旋转后改变节点颜色,也是维护平衡性的一个重要操作