集合

集合:

队列(queue)接口:可以在队尾添加元素,在队头删除元素,并可以查找队列中元素的个数。收集对象时,按照“先进先出”的规则检索对象。

interface Queue<E>{ ... }

 

队列的两种实现方式:一种是使用循环数组;另一种是使用链表。

 

集合类的基本接口是Collection接口,这个接口有两个基本方法:

public interface Collection<E> {

boolean add(E element); //向集合中添加元素

Iterator<E> iterator(); //返回一个实现了Iterator接口的对象,可以使用这个迭 ... //代器对象依次访问集合中的元素。

}

 

一些Collection允许相同的元素而另一些不行。一些能排序而另一些不行。

 

迭代器Iterator接口包含3个方法:

public interface Iterator<E>{

E next();

boolean hasNext();

void remove();

}

通过反复调用next()方法,可以逐个访问集合中的每个元素,但如果到了集合的末尾,next()方法将抛出NoSuchElementException,因此在调用next之前调用hasNext方法。

如果想要查看集合中的所有元素,就请求一个迭代器,并在hasNext返回true时反复地调用next方法。

迭代器查找一个元素唯一的方法是调用next方法。

 

for each循环可以与任何实现了Iterable接口的对象一起工作,这个接口只包含一个方法:

public interface Iterable<E>{

Iterator<E> iterator();

}

 

Collection接口扩展了Iterable接口,因此,对于标准类库中的任何集合都可以使用for each循环。

 

元素被访问的顺序取决于集合类型。如果对ArrayList进行迭代,迭代器将从索引0开始,每迭代一次,索引值加1。然而,如果访问HashSet中的元素,每个元素将会按照某种随机的次序出现。虽然可以确定在迭代中能够遍历到集合中的所有元素,但却无法预知元素被访问的次序。

 

删除元素:Iterator接口的remove方法将会删除上次调用next方法时返回的元素。如果想要删除指定位置上的元素,仍然需要越过这个元素。删除字符串集合中第一个元素的方法:

Iterator<String> it = c.iterator();

it.next();

it.remove();

next方法和remove方法的调用具有互相依赖性,如果调用remove之前没有调用next将是不合法的,会抛出IllegalStateException异常。如果想要删除两个相邻的元素,不能直接这样调用:

it.remove();

it.remove();

必须:

it.remove();

it.next();

it.remove();

 

检测任意集合是否包含指定元素的泛型方法:contains.

还有其他方法:sizeisEmptycontainsAllequalsaddAllremoveremoveAllclearretainAlltoArray.

 

Java类库提供了类AbstractCollection,将sizeiterator抽象化了,但其他方法均提供了实现。

 

具体的集合:


处理以Map结尾的类之外,其它类都实现了Collection接口,而以Map结尾的类实现了Map接口。

 

链表Java中的所有链表都是双向链接的。链表是有序集合,并且集合中每个元素的位置十分重要。 Set不同,List允许有相同的元素。

接口List、类LinkedList

只有在自然有序的集合中使用迭代器添加元素才有意义,因此Iterator接口中就没有add方法,而在子接口ListIterator中包含add方法。ListIterator接口有两个方法可以用来反向遍历链表:

E prevoius()

boolean hasPrevious()

LinkedList类的listIterator方法返回一个实现了ListIterator接口的迭代器对象。

add方法在迭代器位置之前添加一个新对象。如越过链表中的第一个元素,并在第二个元素之前添加新对象。

如果调用previous就会将右侧的元素删除掉,并且不能在同一行中调用两次remove

add方法只依赖于迭代器的位置,而remove方法依赖于迭代器的状态。

set方法用一个新元素取代调用nextprevious方法返回的上一个元素:

用一个新值取代链表的第一个元素:

ListIterator<String> iter = list.listIterator();

String oldValue = iter.next();   //returns first element

iter.set(new Value);   //sets first element to newValue

 

如果需要对集合进行随机访问,就使用数组或ArrayList,而不要使用链表。

 

有两种访问元素的协议:一种是用迭代器,另一种是用getset方法随机的访问每个元素。后者不适合链表,但对数组却很有用。

 

数组列表:

ArrayList:实现了List接口。ArrayList封装了一个动态再分配的对象数组。

Vector类:其所有方法都是同步的,可以由两个线程安全地访问一个Vector对象。

ArrayList方法不是同步的。

 

为了 避免执行成本较高的随机访问操作,引入了一个标记接口RandomAccess。这个接口没有任何方法,但可以用来检测一个特定的集合是否支持高效的的随机访问。


散列集(hash table):

如果不在意元素的顺序,可以有几种能够快速查找元素的数据结构,其缺点是无法控制 元素出现的次序,它们将按照有利于其操作目的的原则组织数据。

散列表为每个对象计算一个整数,称为散列码(hash code)。

a.equals(b)true,则ab必须具有相同的hash code

 

set是没有重复元素的元素集合setadd方法首先在集中查找要添加的对象,如果不存在,就将这个对象添加进去。

 

HashSet类是实现了基于散列表的集,其contains方法以及被重新定义,用来快速查看是否已经出现在集中,它只在某个桶中查找元素,而不必查看集合中的所有元素。

散列表迭代器将依次访问所有的桶,由于散列将元素分散在表的各个位置上,所以访问他们的顺序几乎是随机的。只有不关心集合中元素的顺序时才应该使用HashSet

 

树集(TreeSet是一个有序集合,可以以任意顺序将元素插入到集合中。在对集合进行遍历时,每个值将自动地按照排序后的顺序呈现。

排序使用树结构完成的,每次将一个元素添加到树中时,都被放置在正确的排序位置上。因此,迭代器总是以排好序的顺序访问每个元素。

 

将一个元素添加到TreeSet中要比添加到HashSet中慢。但与将元素添加到数组或链表的正确位置上相比还是快很多。

在默认情况下,树集假定插入的元素实现了Comparable接口,其中定义了一个方法:compareTo

 

双端队列:可在首尾同时添加或删除元素。不支持在队列中间添加元素。

Deque接口,并由ArrayDequeLinkedList类实现

 

优先级队列(PriorityQueue中的元素可以按照任意的顺序插入,却总是按照排序的顺序进行检索。即,无论何时调用remove方法,总会获得当前优先级队列中最小的元素。然而,优先级队列并没有对所有的元素进行排序。若果用迭代的方式处理这些元素,并不需要对他们进行排序。优先级队列使用了堆。堆是一个可以自我调整的二叉树,对树执行添加和删除操作,可以让最小的元素移动到根,而不必花时间对元素进行排序。

使用优先级队列的典型示例是任务调度。

 

映射表(Map:用来存放键/值对,如果提供了键,就能查找到值。

提供两个实现:HashMapTreeMap,都实现了Map接口。

HashMap对键进行散列,TreeMap用键的整体顺序对元素进行排列,并将其组织成搜索树。散列或比较函数只能作用于键,与键关联的值不能进行散列或比较。

与集一样,散列稍微快一点,如果不需要按照排列顺序访问键,就最好选择散列。

 

如果对同一个键两次调用put方法,第二个值就会取代第一个值。实际上,put将返回用这个键参数存储的上一个值。

如果想要同时查看键与值,就可以通过枚举各个条目(entries)查看,就避免对值进行查找。可以使用下面这段代码框架:

for(Map.Entry<String,Employee>  entry:staff.entrySet()){

String key = entry.getKey();

Employee value = entry.getValue();

...

}

 

 

专用集与散列表集:

1、弱散列映射表(WeakHashMap

2、链接散列集(LinekedHashSet)和链接映射表(LinkedHashMap):用来记住插入元素项的顺序。避免在散列表中的项从表面上看是随机排列的。

3、枚举集(EnumSet)与映射表(EnumMap

4、标识散列映射表(IdentityHashMap

 

视图与包装器

 

批操作:避免频繁使用迭代器

假设找出两个集合的交集:

Set<String> result = new HashSet<>(a);

result.retainAll(b);

 

假设希望将一个列表的前10个元素添加到另一个容器中,可以建立一个子列表用于选择前10个元素:

relocated.addAll(staff.subList(0,10));

这个子范围也可以成为更改操作的对象。

staff.subList(0,10).clear();

 

集合与数组之间的转换:

将数组转换为集合,Arrays.asList的包装器就可以实现:

String[] values = ...;

HashSet<String> staff = new HashSet<>(Arrays.asList(values));

 

集合转换为数组:设计为所希望的元素类型且长度为0的数组

String[] values = staff.toArray(new String[0]);

可以构造一个指定大小的数组:

staff.toArray(new String[staff.size()]);  //在这种情况下, 没有创建任何新数组。

 

Collections.sort(staff);

实现对List接口的集合进行排序。

若谷想采用其他方式对列表进行排序,可以将Comparator对象作为第二个参数传递给sort方法。

如果想按照降序对列表进行排序,可以使用:

Collections.sort(staff,Collections.reverseOrder());

 

Collections类有一个算法Shuffle,其功能与排序刚好相反,即随机的混排列表中元素的顺序。

如果提供的列表没有实现RandomAccess接口,shuffle方法将元素复制到数组中,然后打乱数组元素的顺序,最后再将打乱顺序后的元素复制回列表。

 

二分查找:Collections类的binarySearch方法实现了这个算法,注意:集合必须是排好序的,要想查找某个元素,必须提供集合(这个集合要实现List接口)以及要查找的元素。如果集合没有采用Comparable接口的compareTo方法进行排序,就还要提供一个比较器对象。

 

遗留的集合:

Hashtable类:与HashMap类的作用一样,实际上它们拥有相同的接口。

Vector类的方法一样。Hashtable的方法也是同步的。如果对同步性或与遗留代码的兼容性没有任何要求,就应该使用HashMap

 

枚举

属性映射表

栈(Stack类)

位集(BitSet类):用于存放一个位序列



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值