题目来自若博豆支持优先级队列
是实现输入一群数据对象,对象里包含id(优先度),date数据
按照优先度排序,
优先度相同数据不同、按照插入顺序排序,
优先度和数据都相同,去重。
开始无脑使用的TreeSet进行排序
发现我打断了date的排序规则
输入
String s = "(10,1),(30,1),(20,1),(20,2),(40,3),(50,3),(10,1),(20,1)";
导致
[Ele{date=40, id=3}, Ele{date=50, id=3}, Ele{date=20, id=2}, Ele{date=10, id=1}, Ele{date=30, id=1}, Ele{date=20, id=1}, Ele{date=10, id=1}]
可以发现 最后的20,1去重了,10,1却没有
查阅资料TreeSet底层是树的结构,按照排序规则维持左右节点,而查询是否重复,也是依托树形的结构去查相邻的节点,我人为修改了第二个排序规则,就把树形的结构没有按照
条件1排序?满足:不满足条件2排序 这个规则
导致去重失败,树的结构在第二个条件下被锁死了,无法正常去重,没法按照条件二的大小情况正常排序。如果正常排序,又不满足按照 输入顺序的排序。
所以针对条件1是否满足,不满足按输入顺序进行去重输出这类问题时,可以使用TreeMap,键存放条件1,进行排序,值使用LinkedHashSet 存储对应id的date值 进行去重和保持输入顺序。
排序可以使用比较器
比较器返回值 0 正数,负数,
负数,证明前者小于后者,升序
正数,证明前者大于后者,降序
0,证明前者等于后者,不改变顺序
比较器只比较大小决定顺序,不去重。
TreeSet可以对基本数据类型进行排序,按照从小到大的规则,而自定义比较器也可以实现对对象进行排序。
TreeSet也根据比较值进行去重,但如果你手动的更改了比较为0但返回值不为0的情况,会导致不去重。即排序成功,去重失败。
再但,即使你更改了比较值为0,返回值也为0,但更改了某一比较值非0情况的返回值,把它从返回正或者负 统一为 正或者统一为负,这打断了TreeSet的红黑树结构,会导致希望的数据按照了你的想法排列了,但没能去重。即排序成功,去重失败。
public V put(K key, V value) {
//获取根结点赋值给变量t
Entry<K,V> t = root;
//判断根结点是否为null
if (t == null) {
//对key进行非空和类型校验
compare(key, key);
//新建一个结点
root = new Entry<>(key, value, null);
//设置集合长度为1
size = 1;
//记录集合被修改的次数
modCount++;
//添加成功返回null
return null;
}
//如果根结点不是null则执行下面代码
int cmp;
Entry<K,V> parent;
//把比较器对象赋值给变量cpr
Comparator<? super K> cpr = comparator;
//判断比较器对象如果是空则执行下面代码
if (cpr != null) {
do {
//把当前结点赋值给变量parent
parent = t;
//比较当前结点的键和要存储的键的大小
cmp = cpr.compare(key, t.key);
//如果要存储的键小于当前结点,则继续和左边的结点进行比较
if (cmp < 0)
t = t.left;
//如果要存储的键大于当前结点,则继续和右边的结点进行比较
else if (cmp > 0)
t = t.right;
else
//如果要存储的键等于当前结点的键,则调用setValue()方法设置新的值
//并结束循环
return t.setValue(value);
//循环直到遍历到叶子结点结束为止
} while (t != null);
}
//如果比较器对象不是空则执行下面代码
else {
//如果要保存的键为空,抛出空指针异常
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
//把键转型为Comparable类型
Comparable<? super K> k = (Comparable<? super K>) key;
do {
//把当前结点赋值给变量parent
parent = t;
//比较要存储的键和当前结点的键
cmp = k.compareTo(t.key);
//如果要存储的键小于当前结点,则继续和左边的结点比较
if (cmp < 0)
t = t.left;
//如果要存储的键大于当前结点,则继续和右边的结点比较
else if (cmp > 0)
t = t.right;
else
//如果要存储的键等于当前结点的键,则调用setValue()方法设置新的值
//并结束循环
return t.setValue(value);
//循环直到遍历到叶子结点结束为止
} while (t != null);
}
//遍历结束如果没有找到相同的键,则执行下面代码
//创建新的结点对象,保存键值对,设置父结点
Entry<K,V> e = new Entry<>(key, value, parent);
//如果新的键小于父结点的键,则保存在左边
if (cmp < 0)
parent.left = e;
else
//如果新的键大于父结点的键,则保存在右边
parent.right = e;
//维持红黑树的平衡
fixAfterInsertion(e);
//集合长度加一
size++;
//集合修改次数加一
modCount++;
//返回被覆盖的值是null
return null;
}