【数据结构】List、Set、Map的联系和区别(通俗易懂,清晰直观!!)

目录

List(列表):

ArrayList

LinkedList

ArrayList和LinkedList的关系

Set(集合):

HashSet

TreeSet

HashSet和TreeSet的关系和区别

Map(映射):

HashMap

TreeMap

List、Set、Map这三个大类的关系和区别


     

   当涉及到数据集合时,List、Set和Map是常用的数据结构。它们之间有一些相似之处,同时也有一些区别。

List(列表):

  • List 是一个有序的集合,允许重复元素。
  • 可以通过索引访问列表中的元素,索引从0开始。
  • List 通常实现为动态数组或链表的形式。
  • 常见的 List 实现包括 ArrayList 和 LinkedList。
  • 示例:[1, 2, 3, 2, 4]

    ArrayList

    • ArrayList 是一个基于动态数组的集合,它能够自动增长和缩小。
    • 它允许快速随机访问任意位置的元素,因为它在内部使用数组来存储元素。
    • 数组可以被直接访问,所以 ArrayList 的随机访问非常快速。
    • 在添加和删除时需要移动大量元素,效率较低。
    • 示例代码:
      import java.util.ArrayList;
      public class ArrayListExample {
          public static void main(String[] args) {
              ArrayList list = new ArrayList();
              list.add("Alice");
              list.add("Bob");
              list.add("Charlie");
              list.add("David");
              System.out.println("List size: " + list.size());
              for(String name : list) {
                  System.out.println(name);
              }
          }
      }

      LinkedList

      • LinkedList 是一个基于链表的集合,每个元素都包含了一个指向下一个元素的引用。
      • 它不允许快速随机访问任意位置的元素,因为必须从头结点开始遍历链表才能到达目标元素。
      • 在添加和删除时无需移动元素,效率较高。
      • 链表的节点之间可以插入新的节点,构建复杂的数据结构。
      • 示例代码:
        import java.util.LinkedList;
        public class LinkedListExample {
            public static void main(String[] args) {
                LinkedList list = new LinkedList();
                list.add("Alice");
                list.add("Bob");
                list.add("Charlie");
                list.add("David");
                System.out.println("List size: " + list.size());
                for(String name : list) {
                    System.out.println(name);
                }
            }
        }

        ArrayList和LinkedList的关系

        • ArrayList 和 LinkedList 都是 List 接口的实现类,它们都可以用于存储一组元素。
        • ArrayList 底层使用数组来存储元素,而 LinkedList 底层使用双向链表来存储元素。
        • ArrayList 支持快速随机访问任意位置的元素,但是在添加和删除时需要移动大量元素,效率较低。
        • LinkedList 不支持快速随机访问任意位置的元素,但是在添加和删除时无需移动元素,效率较高。
        • 在大多数情况下,ArrayList 的性能优于 LinkedList。但是,如果需要经常添加或删除元素,或者构建复杂的数据结构,那么选择 LinkedList 可能更好。

          Set(集合):

          • Set 是一个不允许重复元素的集合,保持元素的唯一性。
          • 元素在 Set 中没有特定的顺序。
          • Set 通常用于判断元素是否存在,或者去重操作。
          • 常见的 Set 实现包括 HashSet 和 TreeSet。
          • 示例:{1, 2, 3, 4}

            HashSet

            • HashSet 是基于哈希表实现的集合,它使用哈希函数来确定元素在集合中的存储位置。
            • HashSet 不保证元素的顺序,元素的存储顺序是不确定的。
            • HashSet 允许存储空值(null)。
            • HashSet 的插入、删除和查找操作都具有常数时间复杂度 O(1) 的性能。
            • 由于元素的存储位置是根据哈希值计算得到的,因此 HashSet 并不能按照元素的顺序进行遍历。
            • 简单使用示例:
               // HashSet 示例
                      HashSet hashSet = new HashSet<>();
                      
                      // 添加元素
                      hashSet.add("Apple");
                      hashSet.add("Banana");
                      hashSet.add("Orange");
                      hashSet.add("Mango");
                      hashSet.add("Apple"); // 重复元素不会被添加
                      
                      // 输出 HashSet
                      System.out.println("HashSet: " + hashSet);
                      // 输出结果为:HashSet: [Orange, Banana, Apple, Mango]
                      // 元素的顺序是不确定的
                      // 判断元素是否存在
                      boolean containsApple = hashSet.contains("Apple");
                      System.out.println("HashSet contains \"Apple\": " + containsApple);
                      // 输出结果为:HashSet contains "Apple": true
                      // 删除元素
                      hashSet.remove("Banana");
                      System.out.println("HashSet after removing \"Banana\": " + hashSet);
                      // 输出结果为:HashSet after removing "Banana": [Orange, Apple, Mango]
                      // 判断 HashSet 是否为空
                      boolean isEmpty = hashSet.isEmpty();
                      System.out.println("Is HashSet empty? " + isEmpty);
                      // 输出结果为:Is HashSet empty? false
                      // 获取 HashSet 的大小
                      int size = hashSet.size();
                      System.out.println("HashSet size: " + size);
                      // 输出结果为:HashSet size: 3

              TreeSet

              • TreeSet 是基于红黑树(一种自平衡二叉搜索树)实现的集合,它可以对元素进行排序存储。
              • TreeSet 会对元素按照其自然顺序(或者根据指定的 Comparator 进行比较)进行排序。
              • TreeSet 不允许存储空值(null)。
              • TreeSet 的插入、删除和查找操作的时间复杂度取决于树的高度,通常为 O(logN),其中 N 为元素个数。
              • TreeSet 可以按照元素的顺序进行迭代遍历。
              • 简单的使用代码示例:
                 // TreeSet 示例
                        TreeSet treeSet = new TreeSet<>();
                        
                        // 添加元素
                        treeSet.add("Apple");
                        treeSet.add("Banana");
                        treeSet.add("Orange");
                        treeSet.add("Mango");
                        treeSet.add("Apple"); // 重复元素不会被添加
                        // 输出 TreeSet
                        System.out.println("TreeSet: " + treeSet);
                        // 输出结果为:TreeSet: [Apple, Banana, Mango, Orange]
                        // 元素按照字母顺序进行排序存储
                        // 获取第一个元素
                        String firstElement = treeSet.first();
                        System.out.println("First element in TreeSet: " + firstElement);
                        // 输出结果为:First element in TreeSet: Apple
                        // 获取最后一个元素
                        String lastElement = treeSet.last();
                        System.out.println("Last element in TreeSet: " + lastElement);
                        // 输出结果为:Last element in TreeSet: Orange
                        // 获取小于某个元素的最大元素
                        String lowerElement = treeSet.lower("Banana");
                        System.out.println("Element lower than \"Banana\": " + lowerElement);
                        // 输出结果为:Element lower than "Banana": Apple
                        // 获取大于某个元素的最小元素
                        String higherElement = treeSet.higher("Banana");
                        System.out.println("Element higher than \"Banana\": " + higherElement);
                        // 输出结果为:Element higher than "Banana": Mango
                        // 删除元素
                        treeSet.remove("Banana");
                        System.out.println("TreeSet after removing \"Banana\": " + treeSet);
                        // 输出结果为:TreeSet after removing "Banana": [Apple, Mango, Orange]
                        // 清空 TreeSet
                        treeSet.clear();
                        System.out.println("TreeSet after clearing: " + treeSet);
                        // 输出结果为:TreeSet after clearing: []

                HashSet和TreeSet的关系和区别

                • HashSet 和 TreeSet 都实现了 Set 接口,因此它们都不允许存储重复元素。
                • HashSet 是无序的,而 TreeSet 是有序的。
                • HashSet 的插入和查找操作性能更好,因为它使用哈希表进行元素存储;而 TreeSet 提供了有序的存储和检索操作,但相对来说性能更差。
                • 在需要快速插入、删除和查找元素,并不关心元素的顺序时,可以选择使用 HashSet。而在需要有序存储和遍历元素的场景中,可以选择使用 TreeSet。

                  Map(映射):

                  • Map 是一种键值对的集合,每个键都是唯一的。
                  • 可以通过键来访问、插入或删除对应的值。
                  • Map 中的键-值对没有特定的顺序。
                  • 常见的 Map 实现包括 HashMap 和 TreeMap。
                  • 示例:{ "key1" -> "value1", "key2" -> "value2", "key3" -> "value3" }

                    HashMap

                            HashMap 是基于哈希表实现的,它使用键的哈希值来进行存储和检索操作。它的特点是存储顺序不确定,不保证元素的顺序。HashMap 允许使用 null 作为键和值,并且允许存在重复的值,但不允许存在重复的键。

                    基本使用示例:

                    // HashMap 示例
                            HashMap hashMap = new HashMap<>();
                            
                            // 添加键值对
                            hashMap.put(3, "Apple");
                            hashMap.put(1, "Banana");
                            hashMap.put(2, "Orange");
                            hashMap.put(4, "Mango");
                            hashMap.put(1, "Grape"); // 重复的键会覆盖旧的值
                            
                            // 输出 HashMap
                            System.out.println("HashMap: " + hashMap);
                            // 输出结果为:HashMap: {1=Grape, 2=Orange, 3=Apple, 4=Mango}
                            // 元素的顺序是不确定的
                            // 获取值
                            String value = hashMap.get(3);
                            System.out.println("Value for key 3: " + value);
                            // 输出结果为:Value for key 3: Apple
                            // 判断是否包含键
                            boolean containsKey = hashMap.containsKey(2);
                            System.out.println("HashMap contains key 2: " + containsKey);
                            // 输出结果为:HashMap contains key 2: true
                            // 删除键值对
                            hashMap.remove(1);
                            System.out.println("HashMap after removing key 1: " + hashMap);
                            // 输出结果为:HashMap after removing key 1: {2=Orange, 3=Apple, 4=Mango}
                            // 判断 HashMap 是否为空
                            boolean isEmpty = hashMap.isEmpty();
                            System.out.println("Is HashMap empty? " + isEmpty);
                            // 输出结果为:Is HashMap empty? false
                            // 获取 HashMap 的大小
                            int size = hashMap.size();
                            System.out.println("HashMap size: " + size);
                            // 输出结果为:HashMap size: 3

                    TreeMap

                            TreeMap 是基于红黑树实现的,它会根据键的自然顺序或者自定义比较器的顺序来进行存储和检索操作。TreeMap 内部会对键进行排序,并且提供了按照键的自然顺序或者自定义比较器顺序的迭代器。TreeMap 不允许使用 null 作为键,但可以使用 null 作为值。TreeMap 中的键是有序的,因此迭代时会按照键的顺序进行遍历。

                    使用的简单示例:

                     // TreeMap 示例
                            TreeMap treeMap = new TreeMap<>();
                            
                            // 添加键值对
                            treeMap.put(3, "Apple");
                            treeMap.put(1, "Banana");
                            treeMap.put(2, "Orange");
                            treeMap.put(4, "Mango");
                            treeMap.put(1, "Grape"); // 重复的键会覆盖旧的值
                            // 输出 TreeMap
                            System.out.println("TreeMap: " + treeMap);
                            // 输出结果为:TreeMap: {1=Grape, 2=Orange, 3=Apple, 4=Mango}
                            // 元素按照键的自然顺序进行排序存储
                            // 获取第一个键值对
                            Map.Entry firstEntry = treeMap.firstEntry();
                            System.out.println("First entry in TreeMap: " + firstEntry);
                            // 输出结果为:First entry in TreeMap: 1=Grape
                            // 获取最后一个键值对
                            Map.Entry lastEntry = treeMap.lastEntry();
                            System.out.println("Last entry in TreeMap: " + lastEntry);
                            // 输出结果为:Last entry in TreeMap: 4=Mango
                            // 获取小于某个键的最大键值对
                            Map.Entry lowerEntry = treeMap.lowerEntry(3);
                            System.out.println("Entry with key lower than 3: " + lowerEntry);
                            // 输出结果为:Entry with key lower than 3: 2=Orange
                            // 获取大于某个键的最小键值对
                            Map.Entry higherEntry = treeMap.higherEntry(3);
                            System.out.println("Entry with key higher than 3: " + higherEntry);
                            // 输出结果为:Entry with key higher than 3: 4=Mango
                            // 删除键值对
                            treeMap.remove(1);
                            System.out.println("TreeMap after removing key 1: " + treeMap);
                            // 输出结果为:TreeMap after removing key 1: {2=Orange, 3=Apple, 4=Mango}
                            // 清空 TreeMap
                            treeMap.clear();
                            System.out.println("TreeMap after clearing: " + treeMap);
                            // 输出结果为:TreeMap after clearing: {} 

                    List、Set、Map这三个大类的关系和区别

                    • List 和 Set 都是集合,都用于存储一组元素。List 是有序的、允许重复元素的集合;Set 是无序的、不允许重复元素的集合。
                    • Map 是键值对的集合,通过键来唯一标识和访问值,键是唯一的。
                    • List 和 Set 可以使用迭代器遍历所有元素,而 Map 可以使用键来遍历所有键值对。
                    • List 可以通过索引获取元素,而 Set 和 Map 不能直接通过索引访问元素。
                    • List 的主要实现类有 ArrayList(基于动态数组)和 LinkedList(基于链表),而 Set 和 Map 的主要实现类有 HashSet(基于哈希表)和 TreeSet(基于红黑树)。