算法基础之排序遇到的坑

​​​​​​​1根据id和date排序

题目来自若博豆支持优先级队列

是实现输入一群数据对象,对象里包含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;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值