【达内课程】集合之 Set、Collection

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采用自然排序,则返回nullObject 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 的区别

  1. Set 接口实例存储的是无序的,不重复的数据。List 接口实例存储的是有序的,可以重复的元素。

  2. Set 检索效率低下,删除和插入效率高,插入和删除不会引起元素位置改变。 <实现类有 HashSet,TreeSet >。

  3. 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>(){
            @Override
            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工具类

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值