终于,我读懂了所有Java集合——set篇

HashSet

(底层是HashMap)

Set不允许元素重复。

基于HashMap实现,无容量限制。

是非线程安全的。

成员变量

private transient HashMap<E,Object> map;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

 

构造方法

/*** Constructs a new, empty set; the backing <tt>HashMap</tt> instance has* default initial capacity (16) and load factor (0.75).*/
public HashSet() {map = new HashMap<>();
}
public HashSet(int initialCapacity) {map = new HashMap<>(initialCapacity);
}
public HashSet(int initialCapacity, float loadFactor) {map = new HashMap<>(initialCapacity, loadFactor);
}

添加

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

删除

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

 

遍历

public Iterator<E> iterator() {return map.keySet().iterator();
}

 

包含

public boolean contains(Object o) {return map.containsKey(o);
}

 

TreeSet

(底层是TreeMap)

基于TreeMap实现,支持排序(自然排序 或者 根据创建TreeSet 时提供的 Comparator 进行排序)。

是非线程安全的。

 

成员变量

/**
 * The backing map.
 */

private transient NavigableMap<E,Object> m;

// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();

 

构造方法

public TreeSet() {this(new TreeMap<E,Object>());
}public TreeSet(Comparator<? super E> comparator) {this(new TreeMap<>(comparator));
}

 

添加

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

删除

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

遍历

public Iterator<E> iterator() {return m.navigableKeySet().iterator();
}

包含

public boolean contains(Object o) {return m.containsKey(o);
}

获取开头

public E first() {return m.firstKey();
}

获取结尾

public E last() {return m.lastKey();
}

子集

public NavigableSet<E> subSet(E fromElement, boolean fromInclusive,E toElement,   boolean toInclusive) {return new TreeSet<>(m.subMap(fromElement, fromInclusive,toElement,   toInclusive));
}

默认是含头不含尾

public SortedSet<E> subSet(E fromElement, E toElement) {return subSet(fromElement, true, toElement, false);
}

LinkedHashSet

(继承自HashSet,底层是LinkedHashMap)

LinkedHashSet继承自HashSet,源码更少、更简单,唯一的区别是LinkedHashSet内部使用的是LinkHashMap。这样做的意义或者好处就是LinkedHashSet中的元素顺序是可以保证的,也就是说遍历序和插入序是一致的

类声明

public class LinkedHashSet<E>
    extends HashSet<E>
    implements Set<E>, Cloneable, java.io.Serializable {}

构造方法

public LinkedHashSet(int initialCapacity, float loadFactor) {super(initialCapacity, loadFactor, true);
}/*** Constructs a new, empty linked hash set with the specified initial* capacity and the default load factor (0.75).** @param   initialCapacity   the initial capacity of the LinkedHashSet* @throws  IllegalArgumentException if the initial capacity is less*              than zero*/
public LinkedHashSet(int initialCapacity) {super(initialCapacity, .75f, true);
}/*** Constructs a new, empty linked hash set with the default initial* capacity (16) and load factor (0.75).*/
public LinkedHashSet() {super(16, .75f, true);
}

 

super指的是HashSet的default访问级别的构造方法

/*** Constructs a new, empty linked hash set.  (This package private* constructor is only used by LinkedHashSet.) The backing* HashMap instance is a LinkedHashMap with the specified initial* capacity and the specified load factor.** @param      initialCapacity   the initial capacity of the hash map* @param      loadFactor        the load factor of the hash map* @param      dummy             ignored (distinguishes this*             constructor from other int, float constructor.)* @throws     IllegalArgumentException if the initial capacity is less*             than zero, or if the load factor is nonpositive*/
HashSet(int initialCapacity, float loadFactor, boolean dummy) {map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

BitSet

(位集,底层是long数组,用于替代List<Boolean>)

BitSet是位操作的对象,值只有0或1即false和true,内部维护了一个long数组,初始只有一个long,所以BitSet最小的size是64(8个字节64个位,可以存储64个数字),当随着存储的元素越来越多,BitSet内部会动态扩充,最终内部是由N个long来存储,这些针对操作都是透明的。

默认情况下,BitSet的所有位都是false即0。

不是线程安全的。

用1位来表示一个数据是否出现过,0为没有出现过,1表示出现过。使用的时候既可根据某一个是否为0表示,此数是否出现过。

一个1GB的空间,有8*1024*1024*1024 = 8.58*10^9bit,也就是1GB的空间可以表示85亿多个数。

常见的应用是那些需要对海量数据进行一些统计工作的时候,比如日志分析、用户数统计等等,如统计40亿个数据中没有出现的数据,将40亿个不同数据进行排序,海量数据去重等等。

JDK选择long数组作为BitSet的内部存储结构是出于性能的考虑,因为BitSet提供and和or这种操作,需要对两个BitSet中的所有bit位做and或者or,实现的时候需要遍历所有的数组元素。使用long能够使得循环的次数降到最低,所以Java选择使用long数组作为BitSet的内部存储结构。

去重示例

public static void containChars(String str) {BitSet used = new BitSet();for (int i = 0; i < str.length(); i++)used.set(str.charAt(i)); // set bit for char StringBuilder sb = new StringBuilder();sb.append("[");int size = used.size();for (int i = 0; i < size; i++) {if (used.get(i)) {sb.append((char) i);}}sb.append("]");System.out.println(sb.toString());
}public static void main(String[] args) {containChars("abcdfab");
}

 [abcdf]

排序示例

public static void sortArray(int[] array) {BitSet bitSet = new BitSet(2 << 13);// 虽然可以自动扩容,但尽量在构造时指定估算大小,默认为64 System.out.println("BitSet size: " + bitSet.size());for (int i = 0; i < array.length; i++) {bitSet.set(array[i]);}//剔除重复数字后的元素个数 int bitLen = bitSet.cardinality();//进行排序,即把bit为true的元素复制到另一个数组 int[] orderedArray = new int[bitLen];int k = 0;for (int i = bitSet.nextSetBit(0); i >= 0; i = bitSet.nextSetBit(i + 1)) {orderedArray[k++] = i;}System.out.println("After ordering: ");for (int i = 0; i < bitLen; i++) {System.out.print(orderedArray[i] + "\t");}
}public static void main(String[] args) {int[] array = new int[]{423, 700, 9999, 2323, 356, 6400, 1, 2, 3, 2, 2, 2, 2};sortArray(array);
}

BitSet size: 16384

After ordering:

1     2     3     356 423 700 2323      6400      9999

CopyOnWriteArraySet

(底层是CopyOnWriteArrayList)

基于CopyOnWriteArrayList实现,其唯一的不同是在add时调用的是CopyOnWriteArrayList的addIfAbsent方法。

在每次add的时候都要进行数组的遍历,因此其性能会略低于CopyOnWriteArrayList。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/444811.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

加速scp传输速度

当需要在机器之间传输400GB文件的时候&#xff0c;你就会非常在意传输的速度了。默认情况下(约125MB带宽&#xff0c;网络延迟17ms&#xff0c;Intel E5-2430&#xff0c;本文后续讨论默认是指该环境)&#xff0c;scp的速度约为40MB&#xff0c;传输400GB则需要170分钟&#xf…

tcpcopy使用方法

1、下载tcpcopy http://code.google.com/p/tcpcopy/downloads/list 2、配置、编译、安装 依此使用如下命令&#xff1a; 配置&#xff1a; ./configure 编译&#xff1a; make 安装&#xff1a; make install 3、使用方法 下面以mosquitto为例&#xff0c;说明tcpcopy的用法&a…

C++(14)--面向对象

面向对象1.面向对象编程(难点)2.类和对象demo1:地主类的实现版本1demo2:地主类的实现版本23.访问修饰符demo3:外部修改成员变量不安全(版本3)demo4: 使用封装防止直接修改成员变量&#xff08;版本3&#xff09;demo5:进一步封装&#xff1a;设置/获取名字&#xff0c;修改积分…

终于,我读懂了所有Java集合——map篇(多线程)

多线程环境下的问题 1.8中hashmap的确不会因为多线程put导致死循环&#xff08;1.7代码中会这样子&#xff09;&#xff0c;但是依然有其他的弊端&#xff0c;比如数据丢失等等。因此多线程情况下还是建议使用ConcurrentHashMap。 数据丢失&#xff1a;当多线程put的时候&…

system函数的返回值和执行脚本的返回值

1、先统一两个说法&#xff1a;&#xff08;1&#xff09;system返回值&#xff1a;指调用system函数后的返回值&#xff0c;比如上例中status为system返回值&#xff08;2&#xff09;shell返回值&#xff1a;指system所调用的shell命令的返回值&#xff0c;比如上例中&#x…

OJ汇总

国内&#xff1a;&#xff08;一下排名不分先后&#xff09; 浙江大学&#xff08;ZJU&#xff09;&#xff1a;http://acm.zju.edu.cn/ 北京大学&#xff08;PKU&#xff09;&#xff1a;http://acm.pku.edu.cn/JudgeOnline/ 同济大学&#xff08;TJU&#xff09;&#xff1a;…

C++(15)--面向对象编程实践-欢乐斗地主(vector的花式输出)

面向对象编程实践-欢乐斗地主《老九学堂C课程》《C primer》学习笔记。《老九学堂C课程》详情请到B站搜索《老九零基础学编程C入门》-------------简单的事情重复做&#xff0c;重复的事情用心做&#xff0c;用心的事情坚持做(老九君)---------------要求&#xff1a;实现录入及…

Google Protobuf 使用介绍

直接在 www.google.com.hk 上搜索google protobuf 后下载官方版本。 官方版本支持C\Java\Python三门语言。 还有很多非官方的语言版本支持&#xff0c;如C\NET(C#/Vb.net)\Flex(AS3)等. 要通信&#xff0c;必须有协议&#xff0c;否则双方无法理解对方的码流。在protobuf中&…

epoll的再次认识

使用mmap加速内核与用户空间的消息传递。 这 点实际上涉及到epoll的具体实现了。无论是select,poll还是epoll都需要内核把FD消息通知给用户空间,如何避免不必要的内存拷贝就很 重要,在这点上,epoll是通过内核于用户空间mmap同一块内存实现的。而如果你想我一样从2.5内核就关…

leetcode82. 删除排序链表中的重复元素 II

给定一个排序链表&#xff0c;删除所有含有重复数字的节点&#xff0c;只保留原始链表中 没有重复出现 的数字。 示例 1: 输入: 1->2->3->3->4->4->5 输出: 1->2->5 示例 2: 输入: 1->1->1->2->3 输出: 2->3 思路&#xff1a;判断n…

C++(16)--运算符重载(自定义Integer类)

运算符重载1.运算符重载--重点2.友元函数--难点(流运算符重载)《老九学堂C课程》《C primer》学习笔记。《老九学堂C课程》详情请到B站搜索《老九零基础学编程C入门》 -------------简单的事情重复做&#xff0c;重复的事情用心做&#xff0c;用心的事情坚持做(老九君)--------…

反应器组件 ACE_Reactor

6.1 反应器组件 ACE_Reactor反应器的基本原理是: 针对关心的某个事件写一个事件处理器(event_handler). 将该事件处理器登记到反应器中(同时指明关心的事件). 然后反应器会自动检测事件的发生. 并调用预先登记的事件处理器中的回调函数. 所以ACE Reactor 框架的责任&#x…

C++(17)--详解const

详解const《老九学堂C课程》《C primer》学习笔记。《老九学堂C课程》详情请到B站搜索《老九零基础学编程C入门》-------------简单的事情重复做&#xff0c;重复的事情用心做&#xff0c;用心的事情坚持做(老九君)---------------1.const修饰成员变量 2.const修饰函数参数 3.c…

cppcheck的安装和使用

首先从这里下载linux版本的:http://sourceforge.net/projects/cppcheck/files/cppcheck/ 然后下载对应的版本,解压,之后安装: 编译: g++ -o cppcheck -Ilib cli/*.cpp lib/*.cpp 安装: make install

leetcode24 两两交换链表中的节点

给定一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后的链表。 你不能只是单纯的改变节点内部的值&#xff0c;而是需要实际的进行节点交换。 示例: 给定 1->2->3->4, 你应该返回 2->1->4->3. 思路&#xff1a;这一看就是个递归定义&…

再议指针和引用的一些事情吧

关于指针和引用一直是学习C++的同学们争论的焦点,什么时候用指针,什么时候用引用,还有怎么引用数组,这么用指针访问数组,以及初始化的问题。 不过有一些文章我在很早就已经写过,但是由于当时时间不充分,自己也都是随性写的,可以参看以前我的一个文章:http://blog.csd…

C++(18)--复制构造函数

复制构造函数《老九学堂C课程》《C primer》学习笔记。《老九学堂C课程》详情请到B站搜索《老九零基础学编程C入门》-------------简单的事情重复做&#xff0c;重复的事情用心做&#xff0c;用心的事情坚持做(老九君)---------------包装基本类&#xff0c;封装一些算法。 需求…

lua与C++粘合层框架

一. lua调用C 在lua中是以函数指针的形式调用函数, 并且所有的函数指针都必须满足如下此种类型: typedef int (*lua_CFunction) (lua_State *L);   也就是说, 偶们在C中定义函数时必须以lua_State为参数, 以int为返回值才能被Lua所调用. 但是不要忘记了, 偶们的lua_State是…

leetcode147 对链表进行插入排序

丢人&#xff0c;我就是按插入排序老老实实写的啊。。。。 别人肯定map了hhh。 对链表进行插入排序。 插入排序的动画演示如上。从第一个元素开始&#xff0c;该链表可以被认为已经部分排序&#xff08;用黑色表示&#xff09;。 每次迭代时&#xff0c;从输入数据中移除一个…

PaperNotes(13)-Conditional Image Generation with PixelCNN Decoders

conditional Image generation with PixelCNN DecodersICML的best paperpixel cnn 属于完全可见的信念网络&#xff0c;需要对 概率密度 建模。给定图像数据x&#xff0c;想要对概率分布p(x)建模。概率分布p(x)可以看做&#xff0c;每一像素分布同时作用结果的一个联合分布。一…