java泛型和集合_泛型和集合

本文探讨了Java泛型在集合操作中的应用,包括组合、分区等递归算法的实现,以及自定义集合类的创建,展示了如何通过泛型处理各种类型的集合。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java泛型和集合

问候,

介绍

这周,我将写一些关于泛型的东西(那些有趣的尖括号)。 我需要

一个示例,并决定使用集合及其一些操作。 这周

本文讨论了一个集合类和对该集合的两个有趣的操作:

组合和集合分区。 首先对算法进行描述

给定,然后我们将对它们的通用实现有一些乐趣。

组合方式

对于给定的集合S = [x,y,z],有八组代表所有可能

这三个不同元素的组合:

  • []
  • [X]
  • [y]
  • [z]
  • [x,y]
  • [x,z]
  • [y,z]
  • [x,y,z]

给定集合S,我们如何找到所有这些组合? 方法如下:假设

我们可以找到集合S'= [y,z]的所有组合,它们是:[],[y],[z]和[y,z]

当然,这些子集也是原始集合S的组合,但是

在它们中没有找到“ x”(当然不是,因为我省略了它)。

只需将元素“ x”添加到组成组合的所有子集中

集合[y,z]; 结果如下:

[x],[x,y],[x,z]和[x,y,z]

连同其他四个子集,我们构建了所有八个组合

的集合S = [x,y,z]

但是我们如何找到集合S'= [y,z]的所有组合? 我们应用类似的

在这里进行递归推理:假设我们可以找到集合S''= [z]的所有组合;

他们是[]和[c]; 它们是集合S'= [y,z]的所有组合的一部分,并且

我们在其中添加元素“ y”:[y],[y,z]。

这似乎是徒劳的,但这是我们找到集合S''= [z]的所有组合的方式:

我们找到空集的所有组合,即空集本身:[],

然后将元素[z]添加到所有组合(仅一个),即[z]。

对于具有n个元素的集合,有2 ^ n个组合。 这很容易看出:

空集(零元素)具有一种组合:空集本身。 如果

我们在集合中添加一个元素,最终得到的组合数量是原来的两倍:

原始组合加上具有该新元素的原始组合

添加到每个组合。 一组元素具有两个组合,一组

两个元素具有四个组合,等等。

上述的递归算法将全部生成。

隔断

集S的分区是一个或多个分离的非空子集,并且并集

这些集合中的一个再次形成集合S。 对于集合S = [x,y,z],分区为:

  • [x,y,z]
  • [x],[y,z]
  • [x,y],[z]
  • [x,z],[y]
  • [x],[y],[z]

我们如何找到集合的所有分区? 我们应用类似的递归推理:

假设我们可以找到集合S'= [y,z]的所有分区,即:

  • [y,z]
  • [y],[z]

首先,我们将集合[x]添加到集合S'的每个分区中:

  • [x],[y,z]
  • [x],[y],[z]

接下来,我们将元素“ x”一一添加到S的分区中的每个集合中:

  • [x,y,z]
  • [x,y],[z]
  • [y],[x,z]

我们再次以相同的五个分区结束。 尝试查找的所有分区

给定集合S''= [z]的分区,集合S'= [y,z]。 一个分区

元素集本身就是单个元素集,因此集S''的所有分区为

集S''= [z]本身。

根据定义,空集的所有分区都是空集本身。

套装

您可能已经注意到,本文是关于集合的。 Java编程

语言具有可用的Set实现。 我将使用HashSet

本文示例的实现。 我将改变行为

实现的一点点:我想要“ COW”集。 “ COW”是的首字母缩写

“写时复制”。 COW表示该集合在需要时会复制自身

改变 副本将被更改。 让我们弄脏双手。

这是我们(通用)集合的构造函数:


public class S<T> extends HashSet<T> { 
    private static final long serialVersionUID = -8875179328198507416L; 
    public S(Collection<T> collection) { super(collection); } 
    public S(T arg) { this.add(arg); } 
    public S(T ... args) { super(Arrays.asList(args)); } 
    ... 
我添加了serialVerionUID以保持Eclipse的状态。 这个班有三个

构造函数:采用Collection <T>作为其副本构造函数的一种形式

论据; 以单个元素T作为参数的构造函数,

一个接受(可能为空)T个论点列表的构造函数。

最后一个构造函数允许我们编写新的S <T>(),即根本没有任何元素

这导致空集。

我再次包括第二个构造函数,以保持Eclipse的正常运行。 我需要

套集如下:


S<S<T>> set= new S<S<T>>(new S<T>()); 
假设我没有包括第二个构造函数,那么Java编译器必须

推论给定最后一个构造函数,需要将类型为S <T>的通用数组

构造为将单个参数放入。类型S <T>不是类型T,因此

Eclipse警告自己的创造力。 如果我没有包括那一秒

构造函数,一切仍然会很好,但是我只是不喜欢警告。

最后一个构造函数只是将varargs数组转换为一个List(这是一个

集合),因此超类构造函数可以处理所有这些。

Set接口定义返回“ true”或“ false”的“ add()”和“ addAll()”方法

指示是否可以添加元素。 这同样适用于

'remove'和'removeAll'方法。 我不想要这种行为,我想要方法

这样做相同,但返回新集。 开始:


    private S<T> unionHere(T arg) { 
        add(arg); 
        return this;
    } 
    public S<T> union(T arg) {  
        return new S<T>(this).unionHere(arg);
    } 
    public S<T> union(Collection<T> collection) { 
        S<T> copy= new S<T>(this); 
        copy.addAll(collection); 
        return copy;
    } 
    public S<T> difference(T arg) { 
        S<T> copy= new S<T>(this); 
        copy.remove(arg); 
        return copy;
    } 
    public S<T> difference(Collection<T> collection) { 
        S<T> copy= new S<T>(this); 
        copy.removeAll(collection); 
        return copy;
    } 
请注意,我将第一个方法设为私有:我不希望用户摆弄

设置本身; 如果他们想这样做,他们可以摆弄超类

更改集合本身的方法。

上面的公共方法仅复制该集合并将所需的操作应用于

而是复制并返回复制的集,而不返回布尔值。

请注意,所有方法都是通用的:它们并不关心T实际是什么类型。

到目前为止还不错,但是我还没有做很多事情。 以下是其他设置操作:

相交,差和对称差。 前几个例子

操作; A = [x,y,z],B = [y,z,t]

  • 交集:[y,z]
  • 差异:[x]
  • 对称差:[x,t]

A和B的交集是在A和B中都出现的元素。

A和B的差异是在A中发生但不在B中发生的那些元素。

A和B的对称性差异是A或B bot中的元素不在两者中。

对称差加上两个集合的交集是那些集合的并集

两套。 集A和B的对称差是差的并集

和B的差和B和A的差。

这是源代码:


    public S<T> difference(Collection<T> collection) { 
        S<T> copy= new S<T>(this); 
        copy.removeAll(collection); 
        return copy;
    } 
    public S<T> symDifference(Collection<T> collection) { 
        return difference(collection).union(new S<T>(collection).difference(this));
    } 
    public S<T> intersection(Collection<T> collection) { 
        S<T> copy= new S<T>(this); 
        copy.retainAll(collection); 
        return copy;
    } 
关于这些方法,除了它们首先使

集的副本,并将操作应用于集的副本。

组合方式

“组合”方法的实现紧随描述

在以上段落中。 该方法返回一组集合。 集合是

原始组合的各个组合。

首先,该方法构造一个包含空集的集。 如果原来

set不为空,它将遍历每个元素,将其删除并生成所有

化简集的组合。 它将组合复制到“结果”集中

并在将当前元素再次添加到集合后再次复制它们。

这是代码:


    public S<S<T>> combinations() { 
        S<S<T>> result= new S<S<T>>(new S<T>()); 
        for (T current : this) {
            S<S<T>> comb= difference(current).combinations();
            result.addAll(comb);
            for (S<T> set : comb)
                result.unionHere(set.union(current));
        } 
        return result;
    } 
我的方法本身返回修改后的集合,这非常方便

正确/错误值。 不是通用类型S <S <T >>,即类型T的一个或多个集合。

方法本身是在类S的泛型定义中定义的。

类型是T,所以S <S <T >>的(部分)专业化也是有效的。 其他

文字:例如,如果类型T的并集方法的定义有效,则

自动对通用类型S <T>有效。 上面的代码利用了

Java的通用行为。

我将在下一算法实现中更多地使用该功能:

隔断

此方法使用相同的实现策略:递归调用自身

具有较小的集合,并使用返回值来收集

当前设置在一组分区中。 这里是:


    public S<S<S<T>>> partitions() { 
        S<S<S<T>>> result= new S<S<S<T>>>(); 
        if (size() < 2)
            return result.unionHere(new S<S<T>>(this)); 
        T current= iterator().next();
        S<S<S<T>>> part= difference(current).partitions(); 
        for (S<S<T>> set : part) {
            result.unionHere(set.union(new S<T>(current))); 
            for (S<T> elem : set) {
                S<S<T>> copy= set.difference(elem);
                result.unionHere(copy.unionHere(elem.union(current)));
            }
        } 
        return result;
    } 
分区是一组集合,因此所有分区一起是一组集合

套 最后一组包含类型T的元素。

对于包含最多一个元素的集合,包含包含以下内容的集合的集合

返回(几乎)空集。 否则,如

应用上面的段落,并返回已填充的“结果”集。

如您所见,在类型为<T>的方法的通用定义中,类型为S <T>,

S <S <T >>甚至S <S <S <T >>>是自动定义的,因为S <T>,S <S <T >>

和S <S <S <T >>>本身也是纯泛型类型。

这样就可以找到相交,组合或其他任何东西

对于字符串集(例如S <String>),也对于字符串集集,

即S <S <String >>或您想要的集合中的任何元素。

例子

完成所有这些编程后,我希望看到一些结果; 我测试了上面

像这样的方法:


    public static void main(String[] args) { 
        S<String> s= new S<String>("x", "y", "z");
        S<String> t= new S<String>("y", "z", "t"); 
        System.out.println("union        : "+s.union(t));
        System.out.println("intersection : "+s.intersection(t));
        System.out.println("difference   : "+s.difference(t));
        System.out.println("symDifference: "+s.symDifference(t));
        System.out.println("combinations : "+s.combinations());
        System.out.println("partitions   : "+s.partitions());
    } 
这是(正确的)输出:

union        : [t, z, y, x]
intersection : [z, y]
difference   : [x]
symDifference: [t, x]
combinations : [[], [z, x], [z, y], [z], [y], [z, y, x], [x], [y, x]]
partitions   : [[[z, x], [y]], [[z, y], [x]], [[z], [y], [x]], [[z, y, x]], [[z], [y, x]]] 
结束语

本章介绍了一些泛型的设置杂耍和摆弄

Java的功能。 我确定您必须阅读这篇小文章,

充分了解通用功能和递归实现的时间

两种操作。

我希望下周见,

亲切的问候,

乔斯

翻译自: https://bytes.com/topic/java/insights/709126-generics-sets

java泛型和集合

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值