文章目录
- Set
Set
介绍
Set 继承于 Collection 接口,是一个不允许出现重复元素,并且无序的集合,主要有 HashSet 和 TreeSet 两大实现类。
Set 常用方法
与 List 接口一样,Set 接口也提供了集合操作的基本方法。
但与 List 不同的是, Set 还提供了 equals(Object o)
和 hashCode()
,供其子类重写,以实现对集合中插入重复元素的处理。
public interface Set<E> extends Collection<E> {
A:添加功能
boolean add(E e);
boolean addAll(Collection<? extends E> c);
B:删除功能
boolean remove(Object o);
boolean removeAll(Collection<?> c);
void clear();
C:长度功能
int size();
D:判断功能
boolean isEmpty();
boolean contains(Object o);
boolean containsAll(Collection<?> c);
boolean retainAll(Collection<?> c);
E:获取Set集合的迭代器:
Iterator<E> iterator();
F:把集合转换成数组
Object[] toArray();
<T> T[] toArray(T[] a);
//判断元素是否重复,为子类提高重写方法
boolean equals(Object o);
int hashCode();
}
HashSet
HashSet 内部封装 HashMap 对象,使用 HashMap 的键这一列来存放对象,里边的数据不重复且无序。
当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的hashCode
方法来得到该对象的hashCode
值,然后根据该hashCode
值决定该对象在HashSet
中的存储位置。如果有两个元素通过equals
方法比较 true,但它们的hashCode
方法返回的值不相等,HashSet 将会把它们存储在不同位置,依然可以添加成功。也就是说。 HashSet 集合判断两个元素的标准是两个对象通过 equals
方法比较相等,并且两个对象的 hashCode
方法返回值也相等。
靠元素重写 hashCode
方法和 equals
方法来判断两个元素是否相等,如果相等则覆盖原来的元素,依此来确保元素的唯一性。
创建对象
HashSet set = new HashSet();
hashset 特点
1、不允许出现重复因素;
2、允许插入Null值;
3、元素无序(添加顺序和遍历顺序不一致);
4、线程不安全,若2个线程同时操作HashSet,必须通过代码实现同步;
举例:HashSet 练习
public class Main {
public static void main(String[] args) {
Set<Integer> set = new HashSet<>();
set.add(99);
set.add(55);
set.add(77);
set.add(44);
set.add(88);
set.add(11);
set.add(33);
System.out.println(set.size());//7
System.out.println(set);//[33, 99, 55, 88, 11, 44, 77]
System.out.println(set.contains(99));//true
System.out.println(set.remove(44));//true
System.out.println(set);//[33, 99, 55, 88, 11, 77]
//迭代器遍历
Iterator<Integer> it = set.iterator();
while (it.hasNext()) {
System.out.println(it.next());
}
//遍历结果:
/*33
99
55
88
11
77*/
//迭代器的另一种写法
for (Iterator<Integer> it2 = set.iterator(); it2.hasNext(); ) {
System.out.println(it2.next());
}
}
}
由于Set集合中并没有角标的概念,所以并没有像 List 一样提供
get()
方法。当获取 HashSet 中某个元素时,只能通过遍历集合的方式进行 equals()
比较来实现;
TreeSet
介绍
内部封装 TreeMap 对象,使用 TreeMap 的键这一列来存放对象,数据不重复有序。
与 HashSet 不同的是,TreeSet 具有排序功能,分为自然排序(123456)和自定义排序两类,默认是自然排序;在程序中,我们可以按照任意顺序将元素插入到集合中,等到遍历时 TreeSet 会按照一定顺序输出–倒序或者升序。
TreeSet 特点
1、对插入的元素进行排序,是一个有序的集合(主要与HashSet的区别);
2、底层使用红黑树结构,而不是哈希表结构;
3、允许插入Null值;
4、不允许插入重复元素;
5、线程不安全;
创建对象
TreeSet set = new TreeSet();
TreeSet set = new TreeSet(比较器);
举例:关键词去重
例如输入关键词:
aaa,aaa,bbb,ccc,ccc
返回去除重复的关键词后:
aaa,bbb,ccc
public class Main {
public static void main(String[] args) {
System.out.println("输入关键词列表,用逗号隔开");
String s = new Scanner(System.in).nextLine();
//aa,aa,bb,cc,cc
String[] a = s.split(",");
Set<String> set = new TreeSet<>();
for (int i = 0; i < a.length; i++) {
set.add(a[i]);
}
for (Iterator<String> it = set.iterator(); it.hasNext(); ) {
System.out.println(it.next());
}
}
}
运行结果:
与HashSet集合相比,TreeSet还提供了几个额外方法:
Comparator comparator():如果TreeSet采用了定制顺序,则该方法返回定制排序所使用的Comparator,如果TreeSet采用自然排序,则返回null;
Object first():返回集合中的第一个元素;
Object last():返回集合中的最后一个元素;
Object lower(Object e):返回指定元素之前的元素。
Object higher(Object e):返回指定元素之后的元素。
SortedSet subSet(Object fromElement,Object toElement):返回此Set的子集合,含头不含尾;
SortedSet headSet(Object toElement):返回此Set的子集,由小于toElement的元素组成;
SortedSet tailSet(Object fromElement):返回此Set的子集,由大于fromElement的元素组成
举例:TreeSet 使用练习
TreeSet<String> treeSet = new TreeSet<>();
System.out.println("TreeSet初始化容量大小:" + treeSet.size());//0
//元素添加:
treeSet.add("my");
treeSet.add("name");
treeSet.add("is");
treeSet.add("Errol");
treeSet.add("1");
treeSet.add("2");
treeSet.add("3");
System.out.println("TreeSet容量大小:" + treeSet.size());//7
System.out.println("TreeSet元素顺序为:" + treeSet);//[1, 2, 3, Errol, is, my, name]
//增加for循环遍历:
for (String str : treeSet) {
System.out.println("遍历元素:" + str);
}
//迭代器遍历:升序
Iterator<String> iteratorAesc = treeSet.iterator();
while (iteratorAesc.hasNext()) {
String str = iteratorAesc.next();
System.out.println("遍历元素升序:" + str);
}
//迭代器遍历:降序
Iterator<String> iteratorDesc = treeSet.descendingIterator();
while (iteratorDesc.hasNext()) {
String str = iteratorDesc.next();
System.out.println("遍历元素降序:" + str);
}
System.out.println("TreeSet头节点为:" + treeSet.first());//1
// 获取指定元素之前的所有元素集合:(不包含指定元素)
SortedSet<String> headSet = treeSet.headSet("is");
System.out.println("is节点之前的元素为:" + headSet.toString());//[1, 2, 3, Errol]
//获取给定元素之间的集合:(包含头,不包含尾)
SortedSet subSet = treeSet.subSet("3", "my");
System.out.println("3-my之间节点元素为:" + subSet.toString());//[3, Errol, is]
//集合判断:
System.out.println("TreeSet是否为空:" + treeSet.isEmpty());//false
System.out.println("TreeSet是否包含name元素:" + treeSet.contains("name"));//true
//元素删除:
System.out.println("3元素是否被删除" + treeSet.remove("3"));//true
//集合中不存在的元素,删除返回false
System.out.println("who元素是否被删除" + treeSet.remove("who"));//false
//删除并返回第一个元素:如果set集合不存在元素,则返回null
System.out.println("删除的第一个元素:" + treeSet.pollFirst());//1
//删除并返回最后一个元素:如果set集合不存在元素,则返回null
System.out.println("删除的最后一个元素:" + treeSet.pollLast());//name
//清空集合
treeSet.clear();
其余打印都写在注释中了,循环遍历的结果如下:
遍历元素:1
遍历元素:2
遍历元素:3
遍历元素:Errol
遍历元素:is
遍历元素:my
遍历元素:name
Set 和 List 的区别
- Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。
- Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 <实现类有 HashSet,TreeSet >。
- List 和数组类似,可以动态增长,根据实际存储的数据的长度自动增长 List 的长度。查找元素效率高,插入删除效率低,因为会引起其他元素位置改变。<实现类有ArrayList,LinkedList,Vector> 。
Iterator接口
Java Iterator(迭代器)不是一个集合,它是一种用于访问集合的方法。一般遍历数组都是采用 for 循环或者增强 for,这两个方法也可以用在集合框架,但我们也可以采用迭代器遍历集合框架,实现了 Iterator 接口或 ListIterator 接口。可用于迭代 ArrayList 和 HashSet 等集合。
方法
hasNext()
//用于检测集合中是否还有元素
next()
//返回迭代器的下一个元素,并且更新迭代器的状态。
remove()
//将迭代器返回的元素删除。
我们之前的代码中也用到了,现在再举个例子看一下
List<String> list=new ArrayList<String>();
list.add("Hello");
list.add("World");
list.add("!");
Iterator<String> it = list.iterator();
//判断下一个元素之后是否有值
while(it.hasNext()){
System.out.println(it.next());
}
运行结果如下:
Hello
World
!
iterator 和 for 循环的区别
从数据结构角度分析,for 循环适合访问顺序结构,可以根据下标快速获取指定元素。而 Iterator 适合访问链式结构,因为迭代器是通过 next() 来定位的,可以访问没有顺序的集合。
Collections 工具类
集合之 LinkedList中我们提到了 Collection。
排序操作
Collections 提供以下方法对 List 进行排序操作
void reverse(List list)
:反转
void shuffle(List list)
:随机排序
void sort(List list)
:按自然排序的升序排序
void sort(List list, Comparator c)
:定制排序,由 Comparator 控制排序逻辑
void swap(List list, int i , int j)
:交换两个索引位置的元素
void rotate(List list, int distance)
:旋转。当 distance 为正数时,将 list 后 distance 个元素整体移到前面。当 distance 为负数时,将 list 的前 distance 个元素整体移到后面。
查找,替换操作
int binarySearch(List list, Object key)
:对 List 进行二分查找,返回索引,注意 List 必须是有序的
int max(Collection coll)
:根据元素的自然顺序,返回最大的元素。 类比 int min(Collection coll)
int max(Collection coll, Comparator c)
:根据定制排序,返回最大元素,排序规则由 Comparatator 类控制。类比 int min(Collection coll, Comparator c)
void fill(List list, Object obj)
:用元素 obj 填充 list 中所有元素
int frequency(Collection c, Object o)
:统计元素出现次数
int indexOfSubList(List list, List target)
:统计 targe 在 list 中第一次出现的索引,找不到则返回 -1,类比 int lastIndexOfSubList(List source, list target).
boolean replaceAll(List list, Object oldVal, Object newVal)
:用新元素替换旧元素
addAll(Collection,值1,值2,值3...)
:向指定集合,加入多个数据
栗子
public static void main(String[] args) {
List<String> list = new ArrayList<>();
Collections.addAll(
list,
"8",
"11",
"5",
"4364",
"8",
"215",
"21",
"41029",
"20",
"6",
"1162");
System.out.println(list);
System.out.println("-----------");
Collections.sort(list);
System.out.println(list);
}
输出结果
[8, 11, 5, 4364, 8, 215, 21, 41029, 20, 6, 1162]
[11, 1162, 20, 21, 215, 41029, 4364, 5, 6, 8, 8]
虽然已经排序了,但是排序是根据字符串排序的,并不是按照数字从小到大排序的,如果需要按照数字从小到大排序,可以外接一个比较器
//外接比较器
Collections.sort(list,new Comparator<String>(){
public int compare(String arg0, String arg1) {
int a = Integer.parseInt(arg0);
int b = Integer.parseInt(arg1);
//为了防止溢出,直接用大小比较
if(a>b){
return 1;
}else if(a<b){
return -1;
}else{
return 0;
}
}
});
System.out.println(list);
输出结果
[5, 6, 8, 8, 11, 20, 21, 215, 1162, 4364, 41029]
参考
Java中的Set总结java中的Set集合JAVA基础知识之Collections工具类