Java核心技术知识点笔记—集合(一)

前言:数组和数组列表(ArrayList)有一个重大的缺陷:从数组中间位置删除一个元素要付出很大的代价。原因是数组中处于被删除元素之后的所有元素都要向数组的前端移动。在数组的中间位置插入元素也是如此。

1、链表:

1.1、可以解决在数组和数组列表中插入或删除中间位置元素代价大的问题。

(1)每个对象存放在独立的结点中;

(2)每个结点兼职存放着序列中下一个结点的引用;

(3)Java程序设计中,所有链表实际上都是双向链接的(doubly linked)。即每个结点还存放着指向前驱结点的引用。

1.2、是一个有序集合(ordered collection),每个对象的位置十分重要。

(1)add方法将对象添加到链接尾部,但常常需要将元素添加到链表中间;

(2)由于迭代器是描述集合中位置的,这种依赖于位置的add方法将由迭代器负责;

(3)只有对自然有序的集合使用迭代器添加元素才有实际意义。

(4)当用一个新获得(由Iterator返回)且指向链表表头的迭代器调用add操作时,新添加的元素将变成列表的新表头。当迭代器越过链表的最后一个元素(即hasNext返回false),新添加的元素将变成链表的表尾。

(5)set方法用一个新元素取代调用next或previous方法返回的上一个元素。

(6)如果链表的迭代器检测到它的集合被另一个迭代器修改了,或者被集合自身的方法修改了,将抛出一个ConcurrentModificationException。

1.3、遵循规则:

(1)可以根据需要给容器附加多个迭代器,但这些迭代器只能读取列表;

(2)另外再单独附加一个既能读又能写的迭代器。

(3)特例:链表只负责跟踪对列表的结构性修改,如添加、删除,而set方法不被视为结构性修改。可以将附加到链表的多个迭代器都调用set方法对现有结点的内容进行修改。

1.4、不支持快速随机访问:如要查看第n个元素,必须从头依次越过n-1个元素。鉴于这种方法效率并不高,在需要采用整数索引访问元素时,通常不选用链表。还有,绝对不要使用下面的方式遍历链表,效率极低:

        LinkedList linkedList = new LinkedList<>();
        linkedList.add("..");
        ...//添加n个元素
        for (int i = 0; i < linkedList.size(); i++) {
            //TODO ....
        }

1.5、使用链表的唯一理由是尽可能地减少在列表中间插入或删除元素所付出的代价。

2、数组列表:

2.1、ArrayList:封装了一个动态再分配的对象数组。

2.2、Vector:某些有经验的程序员可能会在需要动态数组时选用Vector。Vector和ArrayList区别在于:Vector是同步的,可以由两个线程安全地访问,但如果由一个线程访问,代码要在同步操作上耗费大量时间。而ArrayList不是同步的。

3、散列集:不在意元素的顺序,利于快速查找位置未知的对象。

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

(1)散列码:由对象的实例域产生的一个整数。具有不同数据域的对象产生不同的散列码。

(2)重要的是散列码要能够快速地计算出来,且这个计算只与要散列的对象状态有关,与散列表中的其他对象无关。

(3)散列表用链表数组实现,每个列表称为桶(bucket)。要查找表中对象的位置,先计算它的散列码,然后与桶的总数取余,所得结果就是保存这个元素的索引。

(4)散列冲突(hash collision):桶被占满,这是有可能发生的。此时,需要用新对象与桶中所有对象比较,看这个对象是否已存在。如果散列码是合理且随机的,桶的数目也足够大,需要比较的次数就会很少。(注:Java SE 8中,桶满时会从链表变为平衡二叉树。)

3.2、桶数:用于收集具有相同散列值的桶的数目。

(1)想要更多控制散列表的运行性能,就要指定一个初始的桶数;

(2)如果大致知道元素最终个数,可以设置桶数。通常设置为预计元素个数的75%~150%。有研究人员认为最好将桶数设置为一个素数,以防键的集聚。标准类库使用的桶数是2的幂,默认为16(为表大小提供的任何值都将被自动转换为2的下一个幂)。

3.3、再散列(rehashed):如果散列表太满,就需要再散列。创建一个桶数更多的表,并将所有元素插入到这个新表中,然后丢弃原来的表。

(1)装填因子(load factor):决定何时对散列表进行再散列。如果表中超过装填因子比例的位置已经填入元素,这个表就会用双倍的桶数自动地进行再散列。对大多数程序而言,0.75的装填因子是比较合理的。

(2)实现几个重要的数据结构:set是没有重复元素的元素集合。set的add方法首先在集中查找要添加的对象,如果不存在,就将这个对象添加进去。Java中提供了一个HashSet类实现了基于散列表的集。

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

你可能感兴趣的:(Java,java,集合,链表,散列集)