Java数据结构和集合框架Collection

7 阅读13分钟

计算机核心基础之数据结构

  • 什么是数据结构

    • 是计算机科学中一个非常重要的概念,它指的是相互之间存在一种或多种特定关系的数据元素的集合。
    • 简单来说,数据结构就是组织、存储和操作数据的方式或方法。
    • 在计算机程序中,合理的数据结构能够大大提高程序的运行效率,减少存储空间的使用,并使程序更易于理解和维护
  • 用途场景

    • 提高程序效率:通过选择合适的数据结构,可以优化程序的性能,减少不必要的计算和存储开销。
    • 简化算法设计:数据结构为算法的实现提供了基础,通过抽象数据之间的关系,可以使算法更加清晰和易于理解。
  • 数据结构分类

    • 线性数据结构

      • 数组(Array):固定大小、连续存储的数据元素集合。
      • 链表(LinkedList):由节点组成,每个节点包含数据元素和指向下一个节点的指针。
      • 栈(Stack):后进先出(LIFO)的数据结构,只允许在一端进行插入和删除操作。
      • 队列(Queue):先进先出(FIFO)的数据结构,在一端插入元素,在另一端删除元素。
    • 非线性数据结构

      • 树(Tree):由节点和边组成的层次结构,每个节点可以有零个或多个子节点。
      • 图(Graph):由节点(或顶点)和边(或弧)组成的集合,用于表示复杂的数据关系。

Java进阶核心之Collection集合框架概要

  • 什么是Java的集合框架

    • Java的集合框架(Collection Framework)是一个用于表示和操作对象的集合的统一架构。
    • 它包含了许多接口、实现类以及算法,可以高效地存储和操作多个对象。
    • 集合框架是Java API的一部分,它允许我们将对象组合成更大的结构,同时提供了对这些结构的高层次操作。
    • 通俗来说:就是java已经封装好的数据结构类,我们开发可以直接用
  • 集合框架的主要接口和类

    • Collection接口
      • 是所有集合类的根接口,定义了集合类应该具备的一些基本方法,如添加、删除、遍历等。
      • 常见方法列表
        boolean add(E e) 向集合中添加指定的元素。如果集合已经包含该元素,则此方法可能不执行任何操作(对于Set而言)。
        boolean addAll(Collection<? extends E> c) 将指定集合中的所有元素添加到此集合中(可选操作)。
        void clear() 移除集合中的所有元素(可选操作)。
        boolean contains(Object o) 如果此集合包含指定的元素,则返回trueboolean containsAll(Collection<?> c)如果此集合包含指定集合中的所有元素,则返回true
        boolean isEmpty() 如果此集合不包含任何元素,则返回true。
        Iterator<E> iterator()返回在此集合中的元素上进行迭代的迭代器。
        boolean remove(Object o)从此集合中移除指定的元素(如果存在)。
        boolean removeAll(Collection<?> c)从此集合中移除指定集合中包含的所有元素(可选操作)。
        boolean retainAll(Collection<?> c)仅保留此集合中也包含在指定集合中的元素(可选操作)。
        int size()返回此集合中的元素数(其容量)。
        
    • List接口
      • 继承了Collection接口,代表一个有序集合,允许有重复的元素。
      • 实现类有ArrayList、LinkedList、Vector等。
    • Set接口
      • 继承了Collection接口,代表一个无序集合,不允许有重复的元素。
      • 实现类有HashSet、TreeSet等。
    • Queue接口
      • 代表一个队列,用于保存等待处理的元素,队列是一种特殊的线性表
      • 它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。
      • 实现类有LinkedList(它同时实现了List和Queue接口)、PriorityQueue等。
    • Map接口(没继承Collection接口,本身是顶级接口)
      • 代表一个映射关系,将键(Key)映射到值(Value),键不允许重复,但值可以重复。
      • 实现类有HashMap、TreeMap、Hashtable等。
  • 迭代器

    • 集合框架中的一个重要概念,它提供了一种遍历集合元素的方式,而不需要了解集合底层的实现细节。
    • 使用迭代器可以安全地遍历集合,并且可以在遍历过程中安全地修改集合(除了并发修改外)。
  • 例:

    import java.util.ArrayList;
    import java.util.List;
    
    public class CollectionDemo {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("c");
            for (String str : list) {
                System.out.println(str);
            }
            list.remove("c");
            for (String str : list) {
                System.out.println(str);
            }
        }
    }
    
  • 总结

    • Java的集合框架为我们提供了一种统一的方式来操作对象集合,它包括了多种类型的集合(如List、Set、Queue、Map等)
    • 以及许多用于操作这些集合的算法和工具类,掌握集合框架是Java编程中非常重要的一部分。

Java进阶核心之集合框架List

  • 什么是List数据结构

    • 在Java的集合框架中,List接口是一个有序的集合,允许元素有重复。
    • List接口继承了Collection接口,提供了许多额外的功能,比如基于索引的插入、删除和访问元素等。
    • 常见的List接口的实现类有ArrayListLinkedListVector
  • List接口的实现类

    • ArrayList
      • 底层基于数组实现,查询效率高,增删效率低(因为需要移动元素)。
      • 线程不安全,但性能较高。
      • 适用于需要频繁查询的场景。
    • LinkedList
      • 底层基于双向链表实现,查询效率低(需要从头或尾遍历),增删效率高。
      • 提供了额外的头尾操作方法,如addFirst(), addLast(), getFirst(), getLast(), removeFirst(), removeLast()等。
      • 线程不安全。
      • 适用于需要频繁增删的场景,尤其是首尾操作。
  • List接口的主要方法

    • void add(int index, E element): 在指定位置插入元素。
    • E get(int index): 返回指定位置的元素。
    • int indexOf(Object o): 返回此列表中指定元素的首次出现的索引,如果此列表不包含该元素,则返回-1。
    • int lastIndexOf(Object o): 返回此列表中指定元素的最后一次出现的索引,如果此列表不包含该元素,则返回-1。
    • E remove(int index): 移除指定位置的元素。
    • boolean contains(Object o): 如果此列表包含指定的元素,则返回true
    • Iterator<E> iterator(): 返回在此列表中的元素上进行迭代的迭代器
  • 例:

    import java.util.ArrayList;
    import java.util.List;
    
    public class ListDemo {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
    
            list.add("a");
            list.add("b");
            list.add("c");
    
            System.out.println(list.get(1));
    
            list.add("d");
    
            for (String fruit : list) {
                System.out.println(fruit);
            }
    
            list.remove(2);
    
            for (String str : list) {
                System.out.println(str);
            }
        }
    }
    
  • 使用注意事项

    • 使用List集合时,要注意索引越界的问题,即不要访问或操作不存在的索引位置。
    • 在多线程环境下,如果需要对List进行并发操作,需要考虑线程安全的问题,可以选择使用线程安全的实现类。
    • 根据实际需求选择合适的List实现类,获得更好的性能

Java进阶核心之哈希表和Map

  • 什么是散列表(Hash table,也叫哈希表)

    • 是根据关键码值(Key value)而直接进行访问的数据结构。
    • 它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度
    • 这个映射函数叫做散列函数,存放记录的数组叫做散列表。
      • 给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址
      • 则称表M为哈希(Hash)表,函数f(key)为哈希(Hash) 函数
    • 散列函数 能使对一个数据序列的访问过程更加迅速有效,通过散列函数,数据元素将被更快地定位
  • 什么是Map

    • 在Java的集合框架中,Map接口是一种存储键值对(key-value pair)的数据结构。
    • Map不允许出现重复的键(key),但允许多个键映射到相同的值(value)。
    • Map接口并不继承自Collection接口,而是与Collection接口并行存在,用于处理键值对映射数据。
    • 常见的Map接口实现类有HashMapLinkedHashMapTreeMap等。
  • Map接口的实现类

    • HashMap
      • 基于哈希表实现,允许null键和null值。
      • 不保证映射的顺序,特别是它不保证该顺序恒久不变。
      • 性能通常优于HashtableTreeMap
    • LinkedHashMap
      • 类似于HashMap,但遍历顺序是按照键值对插入到映射中的顺序(插入顺序)或最近最少使用(LRU)顺序。
      • 提供了按访问顺序(访问顺序)或插入顺序(插入顺序)遍历映射的方法。
    • TreeMap
      • 基于红黑树实现,能够按照键的自然顺序或自定义顺序进行排序。
      • 所有的元素都根据键的自然顺序(或创建TreeMap时提供的Comparator进行排序)。
      • 适用于需要有序遍历的场景。
  • Map接口的主要方法

    • V put(K key, V value): 将指定的值与此映射中的指定键关联(可选操作)。如果包含一个该键的映射关系,则旧值被替换。
    • V get(Object key): 返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回null
    • V remove(Object key): 如果存在一个键的映射关系,则从此映射中移除它(可选操作)。
    • boolean containsKey(Object key): 如果此映射包含指定键的映射关系,则返回true
    • boolean containsValue(Object value): 如果此映射将一个或多个键映射到指定值,则返回true
    • int size(): 返回此映射中的键-值映射关系的数量。
    • boolean isEmpty(): 如果此映射不包含键-值映射关系,则返回true
    • Set<K> keySet(): 返回此映射中包含的键的Set视图。
    • Collection<V> values(): 返回此映射中包含的值的Collection视图。
    • Set<Map.Entry<K,V>> entrySet(): 返回此映射中包含的映射关系的Set视图。
  • 例:

    import java.util.HashMap;
    import java.util.Map;
    
    public class MapDemo {
        public static void main(String[] args) {
            Map<String, Integer> map = new HashMap<>();
    
            map.put("a", 1);
            map.put("b", 2);
            map.put("c", 3);
    
            System.out.println(map.get("a"));
    
            // 遍历键
            for (String key : map.keySet()) {
                System.out.println(key);
            }
    
            // 遍历值
            for (Integer value : map.values()) {
                System.out.println(value);
            }
    
            // 遍历键值对
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                System.out.println(entry.getKey() + ":" + entry.getValue());
            }
    
            map.remove("c");
    
            for (Map.Entry<String, Integer> entry : map.entrySet()) {
                System.out.println(entry.getKey() + ":" + entry.getValue());
            }
        }
    }
    
  • 注意事项

    • 在使用Map时,要注意键的唯一性,不要试图插入重复的键。
    • 如果需要在多线程环境下使用Map,需要考虑线程安全的问题。

第5集 Java进阶核心之集合框架Set

  • 什么是Set

    • 在Java的集合框架中,Set接口是一个不包含重复元素的集合。
    • 它继承自Collection接口,包含了Collection接口的所有方法,如add(), remove(), contains(), size(), isEmpty()
    • Set集合主要用于存储无序且不重复的元素,不保证集合中元素的顺序,某些Set实现类可能会对元素进行排序)
  • Set接口的实现类

    • HashSet
      • 基于哈希表实现,不保证元素的迭代顺序,也不保证元素的顺序在长时间内保持不变。
      • 性能通常优于其他Set实现类,因为它提供了常数时间的添加、删除和查找操作。
    • LinkedHashSet
      • 类似于HashSet,但迭代顺序是元素插入到集合中的顺序(插入顺序)。
      • 在需要保持元素插入顺序的场景中很有用。
    • TreeSet
      • 基于红黑树实现,能够对元素进行自然排序或根据创建TreeSet时提供的Comparator进行排序。
      • 适用于需要有序集合的场景。
  • Set接口的主要方法

    • boolean add(E e): 如果此集合尚未包含指定元素,则添加指定元素。
    • boolean addAll(Collection<? extends E> c): 如果指定集合中的所有元素都尚未添加到此集合中
    • boolean contains(Object o): 如果此集合包含指定的元素,则返回true
    • boolean containsAll(Collection<?> c): 如果此集合包含指定集合中的所有元素,则返回true
    • boolean removeAll(Collection<?> c): 移除此集合中那些也包含在指定集合中的所有元素(可选操作)。
    • boolean retainAll(Collection<?> c): 仅保留此集合中也包含在指定集合中的元素(可选操作)。
  • 例:

    import java.util.HashSet;
    import java.util.Set;
    
    public class SetDemo {
        public static void main(String[] args) {
            Set<String> set = new HashSet();
    
            set.add("a");
            set.add("b");
            set.add("c");
    
            for (String str : set) {
                System.out.println(str);
            }
    
            System.out.println(set.contains("a"));
    
            set.remove("c");
    
            for (String str : set) {
                System.out.println(str);
            }
        }
    }
    
  • 注意事项

    • 在使用Set集合时,要注意集合中元素的唯一性,不要添加重复的元素。
    • 如果需要在集合中保持元素的插入顺序或进行排序,请选择适当的Set实现类(如LinkedHashSetTreeSet)。
    • 在多线程环境下使用Set集合时,需要考虑线程安全的问题。
    • 如果需要线程安全的Set集合,可以使用Collections.synchronizedSet()方法

Java集合框架遍历之迭代器Iterator

  • 需求

    • 容器里面很多元素,如果需要遍历里面的元素,应该怎么操作?
    • 使用循环遍历集合:普通for循环 和 增强for循环
  • 迭代器 Iterator 概述

    • Iterator是java中的一个接口,核心作用就是用来遍历容器的元素
    • 当容器实现了Iterator接口后,可以通过调用Iterator()方法获取一个 Iterator对象
    • 迭代器本身并不属于集合结构的一部分,而是用于遍历集合的工具。
    • 为啥是调用容器里面的Iterator方法呢?
      • 因为容器的实现有多种,不同的容器遍历规则不一样,比如ArrayList/LinkedList/HashSet/TreeSet等,
      • 能够顺序地访问一个集合(Collection)的元素,而又不需要知道该集合的底层表示。
      • 所以设计了Iterator接口,让容器本身去实现这个接口,实现里面的方法,
      • 从而让开发人员不用关系容器的遍历机制,直接使用对应的方法即可
    • 三个核心方法
      • boolean hashNext() :用于判断iterator内是否有下个元素,如果有则返回true,没有则false
      • Obejct next():返回iterator的下一个元素,同时指针也会向后移动1位
      • void remove():删除指针的上一个元素(容易出问题,删除元素不建议使用容器自己的方法)
  • 使用迭代器的步骤

    • 获取迭代器对象
      • 通过调用集合的iterator()方法,我们可以获取到该集合的迭代器对象。
      • ElementType 是集合中元素的类型,collection 是需要遍历的集合对象。
    • 判断迭代器中是否还有元素
      • 使用iterator.hasNext()方法来判断迭代器中是否还有下一个元素
    • 访问集合中的元素
      • 使用iterator.next()方法来获取迭代器中的下一个元素。
      • 在调用next()方法之前,必须确保迭代器中还有元素,否则会抛出NoSuchElementException异常
    • 安全地遍历集合
      • 在遍历集合的过程中,如果需要删除某个元素,应该使用迭代器的remove()方法,而不是集合的remove()方法
      • 直接使用集合的remove()方法会导致在并发修改集合的情况下抛出ConcurrentModificationException异常。
  • 例:

    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    public class IteratorDemo {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            list.add("a");
            list.add("b");
            list.add("c");
    
            Iterator<String> iterator = list.iterator();
    
            while (iterator.hasNext()) {
                String next = iterator.next();
                System.out.println(next);
    
                if (next.equals("c")) {
                    iterator.remove();
                }
            }
    
            for (String str : list) {
                System.out.println(str);
            }
        }
    }
    
  • 注意事项

    • 迭代器遍历集合时,只能单向遍历,无法从后往前遍历。
    • 如果在遍历过程中需要修改集合(如删除元素),应该使用迭代器的remove()方法,而不是集合的remove()方法。
    • 不同循环找元素方式选择,最终看使用场景,性能会有轻微差别,但是可以忽略