【JavaSE】十一、Stack && Queue && Deque && PriorityQueue && Map && Set

文章目录

  • [Ⅰ. Stack(不推荐使用了☠)](#Ⅰ. Stack(不推荐使用了☠))
  • [Ⅱ. Queue](#Ⅱ. Queue)
  • [Ⅲ. Deque](#Ⅲ. Deque)
  • [Ⅳ. PriorityQueue](#Ⅳ. PriorityQueue)
  • [Ⅴ. Map](#Ⅴ. Map)
  • [Ⅵ. Set](#Ⅵ. Set)

Ⅰ. Stack(不推荐使用了☠)

常见方法如下所示:

其中 peek() 就相当于是 std::stack 中的 top()

注意事项:

  1. 在比较元素相同的时候,要使用 equals(),因为就算存储的是整数 Stack<Integer> 类型,里面仍然是引用类型,不能直接通过 == 来比较

  2. 因为 Stack 继承于 Vector,而 Vector 中还有很多实用的方法比如 size() 方法等,都是可以使用的,但由于 Vector 比较老,并且这种设计违反了最小接口原则 ,所以现在不推荐使用 Stack,而是 Deque 来替代!(如下面代码所示)

    1. Java 推荐使用 Deque 接口的实现类,比如:

      1. ArrayDeque
      2. LinkedList
      java 复制代码
         Deque<Integer> stack = new ArrayDeque<>(); // 使用Deque代替Stack
         
         stack.push(1);    // 入栈
         stack.pop();      // 出栈
         stack.peek();     // 查看栈顶
         stack.isEmpty();  // 是否为空

Ⅱ. Queue

注意事项:

  • Queue 是一个接口,要使用实现类来实现,常用 LinkedListArrayDequePriorityQueue 来实现!
  • 一个队列可以实现 栈,但是一个栈实现不了 队列!225. 用队列实现栈232. 用栈实现队列

Ⅲ. Deque

Deque 是一个接口,使用时必须创建 LinkedList 或者 ArrayDeque 类型的对象 。在实际工程中,使用 Deque 接口是比较多的,栈和队列均可以使用该接口。

java 复制代码
Deque<Integer> stack = new ArrayDeque<>(); // 双端队列的线性实现 
Deque<Integer> queue = new LinkedList<>(); // 双端队列的链式实现
操作类型 方法名 描述 抛出异常版本 返回特殊值版本
插入 addFirst(e) 在队首插入元素 如果容量受限会抛出IllegalStateException offerFirst(e) - 失败返回false
addLast(e) 在队尾插入元素 同上 offerLast(e) - 失败返回false
移除 removeFirst() 移除并返回队首元素 队列为空时抛出NoSuchElementException pollFirst() - 队列为空返回null
removeLast() 移除并返回队尾元素 同上 pollLast() - 队列为空返回null
查看 getFirst() 查看队首元素(不移除) 队列为空时抛出NoSuchElementException peekFirst() - 队列为空返回null
getLast() 查看队尾元素(不移除) 同上 peekLast() - 队列为空返回null
栈操作 push(e) 将元素压入栈 可能抛出IllegalStateException
pop() 弹出栈顶元素 栈为空时抛出NoSuchElementException
其他 size() 返回队列中元素数量 - -
isEmpty() 判断队列是否为空 - -
contains(o) 判断是否包含指定元素 - -
remove(o) 移除第一个匹配的元素 元素不存在时抛出NoSuchElementException

Ⅳ. PriorityQueue

Java 集合框架中提供了 PriorityQueuePriorityBlockingQueue 两种类型的优先级队列,PriorityQueue 是线程不安全的,PriorityBlockingQueue 是线程安全的,下面主要介绍 PriorityQueue

使用注意事项:

  1. 使用时必须导入包:import java.util.PriorityQueue;
  2. PriorityQueue放置的元素必须要能够比较大小 ,不能插入无法比较大小的对象,否则会抛出 ClassCastException 异常。
  3. 不能插入 null 对象 ,否则会抛出 NullPointerException
  4. PriorityQueue 默认情况下是小堆
  5. 创建自定义大小堆的比较器写法如下所示:(以 Integer 为例)
java 复制代码
// 推荐使用 Comparator 而不是 Comparable,因为前者比较灵活、侵入性小
// 创建小堆
class lesscmp implements Comparator<Integer> {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1.compareTo(o2);
    }
}

// 创建大堆
class greatercmp implements Comparator<Integer> {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2.compareTo(o1);
    }
}

public static void main(String[] args) {
    PriorityQueue<Integer> pq = new PriorityQueue<>(); // 默认为小堆
    pq.add(10);
    pq.add(20);
    pq.add(15);
    while(!pq.isEmpty()) {
        System.out.println(pq.poll());
    };

    PriorityQueue<Integer> pq1 = new PriorityQueue<>(new greatercmp());
    pq1.add(10);
    pq1.add(20);
    pq1.add(15);
    while(!pq1.isEmpty()) {
        System.out.println(pq1.poll());
    }
    
    // 使用lambda表达式创建大堆
    PriorityQueue<Integer> pq2 = new PriorityQueue<>((o1, o2) -> {return o1.compareTo(o2)});
    pq2.add(10);
    pq2.add(20);
    pq2.add(15);
    while(!pq2.isEmpty()) {
        System.out.println(pq2.poll());
    }
}

// 运行结果
10
15
20

20
15
10

20
15
10

堆排序

  • 升序:建大堆
  • 降序:建小堆
  • 时间复杂度:O(nlogn)

Ⅴ. Map

Map 是一个接口类 ,该类没有继承自 Collection,该类中存储的是 <K,V> 结构的键值对,并且 K 一定是唯一的,不能重复

https://docs.oracle.com/javase/8/docs/api/index.html

☠注意事项

  1. 内置类型不能直接来实例化 HashMap,必须要找其对应的包装类型
  2. TreeMap 中的 key 不能为空 ,否则就会抛 NullPointerException 异常,value 可以为空;而 HashMap key value 都可以为空
  3. Map 中键值对的 Key 不能直接修改,value 可以修改,如果要修改 key,只能先将该 key 删除掉,然后再来进行重新插入。
  4. HashMap 的底层实现中,当某个桶中链表元素超过 8 个,并且桶的个数超过 64 个,此时会将该桶中的链表转化为红黑树维护,降低高度!
  5. 采用方法如下所示:
  1. 其中 getOrDefalut() 方法通常用于统计次数的时候简化代码,如下所示:

    java 复制代码
    public List<String> topKFrequent(String[] words, int k) {
        // 统计字符串出现个数
        Map<String, Integer> hash = new HashMap<>();
        for(int i = 0; i < words.length; ++i) {
            hash.put(words[i], hash.getOrDefault(words[i], 0) + 1); // 这样子来简化代码
        } 
        ...
    }
  2. Map (如 HashMapTreeMap 等) 自身没有迭代器 ,即没有实现 Iterator 接口,但它的视图对象(keySetentrySetvalues)都可以迭代,如下所示:

    java 复制代码
    // 遍历 keySet()(只要 key)
    for (K key : map.keySet()) {
        System.out.println(key);
    }
    
    // 遍历 values()(只要 value)
    for (V value : map.values()) {
        System.out.println(value);
    }
    
    // 遍历 entrySet()(需要 key 和 value)⭐⭐⭐⭐⭐⭐⭐(推荐)
    for (Map.Entry<K, V> entry : map.entrySet()) {
        System.out.println(entry.getKey() + " = " + entry.getValue());
    }
  3. 上述的 entrySet()Map 接口中的一个方法,返回一个包含了所有 键值对 的 Set 集合 ,这些键值对就是 Map.Entry<K, V> 对象,它们每一个都包含两个元素:keyvalue

    java 复制代码
    // 也就是说上面的for-each可以转化为迭代器来处理,如下所示:(这里只举例entrySet)
    Iterator<Map.Entry<String, Integer>> it = map.entrySet().iterator();
    while(it.hasNext()) {
        System.out.println(it.next().getKey() + " " + it.next().getValue());
    }
  4. TreeMapHashMap 的区别如下图所示。其中因为 HashMap 在比较内容的时候是根据 hashCode() 来确定 key 是在哪个桶中的,而根据 equals() 来确定是桶中的哪个元素,所以 HashMap 中存放自定义类型的时候,需要重写该自定义类型的 equals() hashCode() 方法

Ⅵ. Set

SetMap 主要的区别:

  1. Set 是继承自 Collection 的接口类
  2. Set 中只存储了 Key

但实际上底层源码实现是让 Set 去调用 Map 的接口 ,只不过传入的 value 是一个默认的 Object 对象,而只需要关心 key 即可。

常用方法如下所示:

注意事项:

  1. Set 最大的功能就是对集合中的元素进行去重
  2. 实现 Set 接口的常用类有 TreeSetHashSet,还有一个 LinkedHashSetLinkedHashSet 是在 HashSet 的基础上维护了一个双向链表来记录元素的插入次序
  3. TreeSet 中不能插入 nullkey,而 HashSet 可以。
相关推荐
躺平大鹅1 小时前
Java面向对象入门(类与对象,新手秒懂)
java
初次攀爬者2 小时前
RocketMQ在Spring Boot上的基础使用
java·spring boot·rocketmq
花花无缺2 小时前
搞懂@Autowired 与@Resuorce
java·spring boot·后端
Derek_Smart3 小时前
从一次 OOM 事故说起:打造生产级的 JVM 健康检查组件
java·jvm·spring boot
NE_STOP4 小时前
MyBatis-mybatis入门与增删改查
java
孟陬8 小时前
国外技术周刊 #1:Paul Graham 重新分享最受欢迎的文章《创作者的品味》、本周被划线最多 YouTube《如何在 19 分钟内学会 AI》、为何我不
java·前端·后端
想用offer打牌8 小时前
一站式了解四种限流算法
java·后端·go
华仔啊8 小时前
Java 开发千万别给布尔变量加 is 前缀!很容易背锅
java
也些宝9 小时前
Java单例模式:饿汉、懒汉、DCL三种实现及最佳实践
java