当前位置: 首页 > news >正文

JAVA数据结构篇--12理解LinkedHashSetTreeSet

前言:在java 中使用HashSet 结构来存放不重复的元素,但是HashSet 内部的元素时乱序的,存入和取出元素的顺序不能保证,那么有没有一种结构可以保证其顺序性,或者使用者可以自行决定顺序;LinkedHashSet 即实现了存取顺序的一致性;TreeSet可以让开发者自己定义元素的比较器,自行决定顺序;

1 使用:

// LinkedHashSet
Set<User> set = new LinkedHashSet<>(10, 0.75f);
 User userOne = new User();
 userOne.setId(1).setName("lisi").setAge(20);
 set.add(userOne);
 User userTwo = new User();
 userTwo.setId(2).setName("wangwu").setAge(20);
 set.add(userTwo);
 set.remove(userTwo);

 Iterator iterator1 = set.iterator();
 while (iterator1.hasNext()) {
     User user = (User) iterator1.next();
     System.out.println("user = " + user);
 }
//  TreeSet
 Set<User> set1 = new TreeSet<>(Comparator.comparingInt(User::getId));
 User user1 = new User();
 user1.setId(1).setName("lisi").setAge(20);

 set1.add(userOne);
 set1.add(userTwo);
 set1.remove(userTwo);
 Iterator iterator2 = set1.iterator();
 while (iterator2.hasNext()) {
     User user = (User) iterator2.next();
     System.out.println("user = " + user);
 }

2 过程:
2.1 构建:
LinkedHashSet:可以看到内部实际使用了LinkedHashMap进行数据存放

    public LinkedHashSet(int initialCapacity, float loadFactor) {
        super(initialCapacity, loadFactor, true);
    }
    public LinkedHashSet(int initialCapacity) {
        super(initialCapacity, .75f, true);
    }
    public LinkedHashSet() {
        super(16, .75f, true);
    }
    public LinkedHashSet(Collection<? extends E> c) {
        super(Math.max(2*c.size(), 11), .75f, true);
        addAll(c);
    }
    // 使用HashSet 中 LinkedHashMap 作为数据结构进行存放
   HashSet(int initialCapacity, float loadFactor, boolean dummy) {
       map = new LinkedHashMap<>(initialCapacity, loadFactor);
   }

TreeSet:可以看到内部实际上使用TreeMap 进行数据存放

private transient NavigableMap<E,Object> m;

    // Dummy value to associate with an Object in the backing Map
    private static final Object PRESENT = new Object();
    TreeSet(NavigableMap<E,Object> m) {
        this.m = m;
    }
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }
    public TreeSet(Collection<? extends E> c) {
        this();
        addAll(c);
    }
    public TreeSet(SortedSet<E> s) {
        this(s.comparator());
        addAll(s);
    }

2.2 存入元素:
2.2.1 LinkedHashSet: 使用 LinkedHashMap 将元素e作为key ,new object() 作为value 进行数据存入

public boolean add(E e) {
    return map.put(e, PRESENT)==null;
}

2.2.2 treeSet:使用 TreeMap 将元素e作为key ,new object() 作为value 进行数据存入

public boolean add(E e) {
    return m.put(e, PRESENT)==null;
}

2.3 移除元素:
2.3.1 LinkedHashSet: 将元素从 LinkedHashMap 移除

public boolean remove(Object o) {
      return map.remove(o)==PRESENT;
  }

2.3.2 treeSet: 将元素从 TreeMap 移除

public boolean remove(Object o) {
       return m.remove(o)==PRESENT;
   }

2.4 遍历元素:
2.4.1 LinkedHashSet:获取LinkedHashMap的keySet进行遍历:

public Iterator<E> iterator() {
     return map.keySet().iterator();
 }
final class LinkedKeySet extends AbstractSet<K> {
    public final int size()                 { return size; }
    public final void clear()               { LinkedHashMap.this.clear(); }
    public final Iterator<K> iterator() {
        return new LinkedKeyIterator();
    }
    public final boolean contains(Object o) { return containsKey(o); }
    public final boolean remove(Object key) {
        return removeNode(hash(key), key, null, false, true) != null;
    }
    public final Spliterator<K> spliterator()  {
        return Spliterators.spliterator(this, Spliterator.SIZED |
                                        Spliterator.ORDERED |
                                        Spliterator.DISTINCT);
    }
    public final void forEach(Consumer<? super K> action) {
        if (action == null)
            throw new NullPointerException();
        int mc = modCount;
        for (LinkedHashMap.Entry<K,V> e = head; e != null; e = e.after)
            action.accept(e.key);
        if (modCount != mc)
            throw new ConcurrentModificationException();
    }
}
final class LinkedKeyIterator extends LinkedHashIterator
    implements Iterator<K> {
    public final K next() { return nextNode().getKey(); }
}
final LinkedHashMap.Entry<K,V> nextNode() {
   LinkedHashMap.Entry<K,V> e = next;
   if (modCount != expectedModCount)
       throw new ConcurrentModificationException();
   if (e == null)
       throw new NoSuchElementException();
   current = e;
   next = e.after;
   return e;
}

2.4.2:treeSet

 public Iterator<E> iterator() {
  return m.navigableKeySet().iterator();
}
// TreeMap KeySet
 public Iterator<E> iterator() {
    if (m instanceof TreeMap)
        return ((TreeMap<E,?>)m).keyIterator();
    else
        return ((TreeMap.NavigableSubMap<E,?>)m).keyIterator();
}
Iterator<K> keyIterator() {
	return new KeyIterator(getFirstEntry());
}
final class KeyIterator extends PrivateEntryIterator<K> {
    KeyIterator(Entry<K,V> first) {
        super(first);
    }
    public K next() {
        return nextEntry().key;
    }
}
Entry<K,V> next;
Entry<K,V> lastReturned;
int expectedModCount;

PrivateEntryIterator(Entry<K,V> first) {
    expectedModCount = modCount;
    lastReturned = null;
    next = first;
}
// first 节点获取
final Entry<K,V> getFirstEntry() {
    Entry<K,V> p = root;
    if (p != null)
        while (p.left != null)
            p = p.left;
    return p;
}
// 下一节点获取
final Entry<K,V> nextEntry() {
    Entry<K,V> e = next;
    if (e == null)
        throw new NoSuchElementException();
    if (modCount != expectedModCount)
        throw new ConcurrentModificationException();
    next = successor(e);
    lastReturned = e;
    return e;
}
static <K,V> TreeMap.Entry<K,V> successor(Entry<K,V> t) {
    if (t == null)
        return null;
    else if (t.right != null) {
        Entry<K,V> p = t.right;
        while (p.left != null)
            p = p.left;
        return p;
    } else {
        Entry<K,V> p = t.parent;
        Entry<K,V> ch = t;
        while (p != null && ch == p.right) {
            ch = p;
            p = p.parent;
        }
        return p;
    }
}

3 总结
3.1 LinkedHashSet 内部使用LinkedHashMap 将元素e 作为key 进行数据存放;TreeSet 内部使用TreeMap 将元素e 作为key 进行数据存放;
3.2 因为LinkedHashMap 内部元素通过prev 和next 指针维护了元素的有些性,进而保证了LinkedHashSet 存取元素的有序性;TreeSet 通过TreeMap 使用红黑树形结构,通过自定义元素的比较器 来保证元素存取元素的有序性;
3.3 LinkedHashSet&TreeSet 都不是线程安全的;

相关文章:

  • DR_CAN基尔霍夫电路题解法【自留用】
  • 21级数据结构考前模拟题
  • 剑指offer----C语言版----第六天
  • Qt音视频开发08-ffmpeg内核优化(极速打开/超时回调/实时响应)
  • 网络安全一哥的奇安信发布了全球高级可持续威胁年度报告 值得学习
  • 13---SpringBoot整合JWT,实现登录和拦截
  • 4366. 上课睡觉
  • vue后台系统管理项目-echarts柱状图实现订单统计
  • 2022年博客之星排行榜 日榜 2023-01-01 博客之星总榜
  • 一名普通Java程序员的2022的总结和2023的展望
  • 【寒假每日一题】洛谷 P1079 [NOIP2012 提高组] Vigenère 密码
  • 【概率论】期末复习笔记:参数估计
  • k-means算法进行数据分析应用
  • 【数据结构】单链表(线性表)的实现
  • JavaScript 入门基础 - 流程控制(四)
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • 【翻译】babel对TC39装饰器草案的实现
  • Android路由框架AnnoRouter:使用Java接口来定义路由跳转
  • Angular 响应式表单之下拉框
  • Apache Zeppelin在Apache Trafodion上的可视化
  • Codepen 每日精选(2018-3-25)
  • iOS 颜色设置看我就够了
  • IOS评论框不贴底(ios12新bug)
  • JavaScript的使用你知道几种?(上)
  • leetcode378. Kth Smallest Element in a Sorted Matrix
  • mockjs让前端开发独立于后端
  • Python_OOP
  • Spark学习笔记之相关记录
  • 阿里云ubuntu14.04 Nginx反向代理Nodejs
  • 成为一名优秀的Developer的书单
  • 代理模式
  • 离散点最小(凸)包围边界查找
  • 前言-如何学习区块链
  • 全栈开发——Linux
  • 关于Kubernetes Dashboard漏洞CVE-2018-18264的修复公告
  • 正则表达式-基础知识Review
  • # 计算机视觉入门
  • #162 (Div. 2)
  • $L^p$ 调和函数恒为零
  • ()、[]、{}、(())、[[]]等各种括号的使用
  • (2)Java 简介
  • (4)(4.6) Triducer
  • (JS基础)String 类型
  • (Python第六天)文件处理
  • (编译到47%失败)to be deleted
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (六)软件测试分工
  • (七)c52学习之旅-中断
  • (四)库存超卖案例实战——优化redis分布式锁
  • (五)MySQL的备份及恢复
  • (原創) 如何讓IE7按第二次Ctrl + Tab時,回到原來的索引標籤? (Web) (IE) (OS) (Windows)...
  • (原創) 未来三学期想要修的课 (日記)
  • ***检测工具之RKHunter AIDE
  • *p=a是把a的值赋给p,p=a是把a的地址赋给p。
  • .desktop 桌面快捷_Linux桌面环境那么多,这几款优秀的任你选