使用Java PriorityQueue和TreeSet排序的踩坑小记录

背景是

需要一种数据结构:

  1. 支持添加元素进入该结构、或根据元素内容从结构中移除该元素;
  2. 该结构支持按给定的排序规则遍历。

于是就想到了 priorityQueue!!!

给它定义一个按字符串的长度倒序排序:

priorityQueue = new PriorityQueue<>(Comparator.comparingInt(String::length).reversed());

一顿添加之后:
在这里插入图片描述
发现:顺序竟然不对?! 丝毫没有向想象中的结果发展。。。即使用内置的迭代器遍历结果也是一样的: ) 难道java有bug??

于是赶紧面向百度编程,并没有反转:
priorityQueue内部是一个小根堆结构!!然而而堆是一种不完全有序的结构,而这个堆的根节点就是队列的队头
在这里插入图片描述

如果要获得有序的特性, 逐个出队(poll) :行! 用迭代器:不行!

而实际上每次做出队操作,都是在删除根节点,假定现在我们需要删除头部元素3,我们主要还是两个步骤:

  1. 用尾元素替换头元素
  2. 用头元素和两个孩子中值较小的相比较,如果小于该节点的值则不做任何调整,否则交换,再作为子树根节点做同样的逻辑。

这个过程是 O(logn) 的时间复杂度,实在不能接受!

而该结构的 插入元素(offer)的过程,也伴随着调整结构

  1. 将新元素添加到堆结构的末尾
  2. 比较该元素和父节点的大小,如果小于父节点就进行调整,直至满足堆结构,最差会直接到根节点比较
    显然插入过程的时间复杂度也取决于树的高度,同样是 O(logn)

Q:如果我要把n个数放进去priorityQueue,并且按序遍历m次,遍历和插入的先后顺序不确定,总的时间复杂度是多少?

A: n * logn + m * n * logn

麻了麻了 简直太慢了: )

于是又想到了TreeSet

赶紧new了个压压惊
keywordsTreeSet = new TreeSet<>(Comparator.comparingInt(String::length).reversed());
我直接add了几个,很快啊
在这里插入图片描述
然后remove了一个其中不存在的元素
filterSystem.remove("he");

它 变了!!
在这里插入图片描述
我直接好家伙,remove的是"he" "hi"怎么没了?难道jdk有bug??
这次面向百度编程也没找到大佬解读,只能自己看看代码,看到TreeMap.java中有这样一段逻辑:
在这里插入图片描述

然后它的返回值变成了"hi" !
在这里插入图片描述

竟然remove的时候用了实例化TreeSet时的Comparator来区分元素???意思我定义的是按长度比较,add一个两个字符长度的进去,随便remove一个两个字符长度的就能删。
然而java注释也没说明清楚有这么回事
在这里插入图片描述
看来jdk官方的代码注释也不太靠谱的样子。

最终自己手写了一个。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值