Java06集合

13 集合

实现方法时,不同的数据结构会导致性能有很大差异。

 

13.1 集合接口

Java集合类库将接口(interface)与实现(implementation)分离。

可以使用接口类型存放集合的应用,一旦改变了想法,可以轻松额使用另外一种不同的实现。

List<Integer> l = new ArrayList<>();

若想改为链表实现,只需上句为List<Integer> l = new LinkedList<>();

 

Abstract开头的类,如AbstractQueue,是为类库实现者设计的。

如果想要实现自己的队列类,会发现扩展AbstractQueue类要比实现Queue接口中的方法轻松的多。

 

集合类的基本接口是Collection接口

两个基本方法:

public interface Collection<E>
{boolean add(E element);Iterator<E> iterator();
}


iterator方法返回一个实现了Iterator接口的对象。

Iterator接口包含三个方法:

public interface Iterator<E>
{E next();boolean hasNext();void remove();
}


Java迭代器被认为是在两个元素之间的。

当调用next时,迭代器就越过下一个元素,并返回刚刚越过的那个元素的引用。

remove方法将会删除上次调用next方法时返回的元素。

如果调用remove之前没有调用next将是不合法的。

 

由于CollectionIterator都是泛型接口,可以编写任何集合类型实用方法。

 

 

 

 

 

 

13.2 具体的集合

Map结尾的类实现了Map接口;其他实现了Collection接口。

ArrayList

顺序表

LinkedList

双向链表

ArrayDeque

循环数组实现的双端队列

HashSet

没有重复元素的无序集合

TreeSet

有序集

EnumSet

包含枚举类型值的集

LinkedHashSet

可以记住元素插入顺序的集

PriorityQueue

允许高效删除最小元素的集合

HashMap

 

TreeMap

 

EnumMap

键值属于枚举类型

LinkedHashMap

可以记住K/V的添加次序

WeakHashMap

其值无用武之地后可以被垃圾回收器回收

IdentityHashMap

==而不是equals比较键值的映射表

 

 

LinkedList

interface ListIterator<E> extends Iterator<E>
{void add(E element);E previous();boolean hasPrevious();
}


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

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

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

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

 

当某个迭代器修改集合时,另一个迭代器对其进行遍历,一定会出现混乱的状况。

例如:一个迭代器指向另一个迭代器刚刚删除的元素前面,现在这个迭代器就是无效的,并且不应该再使用。

链表迭代器的设计使它能够检测到这种修改。

如果迭代器发现它的集合被另一个迭代器修改了,或是被该集合自身的方法修改了,就会抛出一个ConcurrentModificationException

例如:

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

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

iter1.next();

iter1.remove();

iter2.next(); //throws ConcurrentModificationException

 

链表不支持随机访问,但支持get(int index)

get方法的小优化:如果index > size() / 2 就从列表尾端开始搜索元素。

for (int i = 0; i < list.size(); ++i)do something with list.get(i);//效率极低。出现此代码说明用错数据结构。

nextIndex()  previousIndex()  返回索引值

list.listIterator(n)返回一个迭代器,这个迭代器指向索引为n的元素前面的位置。

 

 

ArrayList

适用于getset方法。

Vector类的所有方法都是同步的,如果由一个线程访问Vector,代码要在同步操作上耗费大量的时间。

ArrayList方法不是同步的。

 

散列集:

散列表(hash table

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

散列码是由对象的实例域产生的一个整数。具有不同数据域的对象将产生不同的散列码。

散列码要能够快速的计算出来。

 

Java中,散列表用链表数组实现。每个列表被称为桶(bucket)。

 


散列码与桶数的余数是元素的桶的索引。

 

散列冲突(hash collision

 

将桶数设置为预计元素个数的75%~150%,最好将桶数设置为一个素数,以防键的聚集。

标准库使用的桶数是2的幂,默认值为16。为表大小提供的任何值都将被自动的转换为2的下一个幂。

 

如果散列表太满,就需要再散列(rehashed)。

创建一个双倍桶数的表,将所有元素插入到这个新表中,然后丢弃原来的表。

装填因子(load factor)决定何时对散列表进行再散列。

对大多数应用程序来说,装填因子为0.75是比较合理的。

 

散列集迭代器依此访问所有的桶,所以访问顺序是随机的。

HashSet

 


树集:

有序集合(sorted collection

红黑树(red-black tree

迭代器以排好序的顺序访问每个元素

 

添加元素到树中要比添加到散列表中慢,但是,与将元素添加到数组或链表中相比还是快很多的。

TreeSet

 

对象的比较:

默认情况下,树集假定插入的元素实现了Comparable接口。

public interface Comparable<T>
{int compareTo(T other);
}
a.compareTo(b); //相等返回0;a在前返回负值;b在前返回正值。


使用Comparable接口定义排序有局限性。

对于一个给定的类,只能够实现这个接口一次。

如果在一个集合中需要按照部件编号进行排序,在另一个集合中却要按照描述信息进行排序,该如何?

如果一个类没有实现Comparable接口,又该如何?

可通过将Comparator对象传递给TreeSet构造器来告诉树集使用不同的比较方法。

pubic interface Comparator<T>
{int compare(T a, T b);
}


如:

class ItemComparator implements Comparator<Item>
{public int compare(Item a, Item b){  return a.getDescription().compareTo(b.getDescription()); }
}
ItemComparator comp = new ItemComparator();
SortedSet<Item> sortByDescription = new TreeSet<>(comp);

 

比较器是比较方法的持有器,不含数据,将这种对象称为函数对象(function object)。

函数对象通常动态定义,即定义为匿名内部类的实例。

SortedSet<Item> sortByDescription = new TreeSet<>(new
Comparator<Item>()
{public int compare(Item a, Item b)return a.getDescription().compareTo(b.getDescription());
}

 

 

队列与双端队列:

ArrayDeque

 

优先级队列:

priority queue

可以按照任意的顺序插入,却总是按照排序的顺序进行检索。

即,无论何时调用remove方法,总会获得当前优先级队列中最小的元素。

优先级队列使用的是堆(heap)。

 

映射表:

Map key/value

HashMap  TreeMap

三种视图:

Set<K> keySet()

Collection<K> values()

Set<Map.Entry<K, V>> entrySet()

 

弱散列映射表:

WeakHashMap

如果一个值,对应键的唯一引用来自散列表条目时,这一数据结构将与垃圾回收器协同工作一起删除键/值对。

 

连接散列集和连接映射表:

LinkedHashSet  LinkedHashMap 用来记住插入元素项的顺序。

 

链接散列映射表将用访问顺序而不是插入顺序,对映射表条目进行迭代。

 

标识散列映射表:

IdentityHashMap

键的散列不是用hashCode函数来计算的,而是用System.identityHashCode方法计算。

根据对象的内存地址来计算散列码。

两个对象进行比较时,IdentityHashMap使用的是”==”。

在实现对象遍历算法(如对象序列化)时,这个类非常有用,可以用来跟踪每个对象的遍历状况。


13.3 集合框架

框架(framework)是一个类的集,它奠定了创建高级功能的基础。

框架包含很多超类,这些超类拥有非常有用的功能、策略和机制。

框架使用者创建的子类可以扩展超类的功能,而不必重新创建这些基本的机制。

例如Swing就是一种用户界面的机制。

Java集合类库构成了集合类的框架,它为集合的实现定义了大量的接口和抽象类,并且对其中的某些机制给予了描述,例如,迭代协议。

 

如果想要实现用于多种集合类型的泛型算法,或者想要增加新的集合类型,必须了解框架。

 

集合有两个基本接口:CollectionMap


List是一个有序集合(ordered collection


标记接口RandomAccess,检测一个特定的集合是否支持随机检索。

 

集合接口有大量地方法,这些方法可以通过更基本的方法加以实现。

抽象类提供了许多这样的例行实现。

如果实现了自己的集合类,就可能要扩展上面某个类,以便可以选择例行操作的实现。

Java类库支持下面几种具体类:

 

 

视图与包装器:

keySet方法返回一个实现Set接口的类对象,这个类的方法对原映射表进行操作。

这种集合称为视图。

 

1、轻量级包装器

Arrays类的静态方法asList将返回一个包装了普通Java数组的List包装器。

Card[] cardDeck = new Card[52];

List<Card> cardList = Arrays.asList(cardDeck);

改变数组大小的所有方法都会抛出一个UnsupportedOperationException异常。

 

List<String> names = Arrays.asList(“Amy”, “Bob”, “Carl”);

这个方法调用Collections.nCopies(n, anObject)方法。

 

2、子范围视图

subList方法

List group2 = staff.subList(10, 20); //含首不含尾

可以将任何操作应用于子范围。

 

对于有序集和映射表,可以使用排序顺序建立子范围。

SortedSet接口声明了3个方法:

SortedSet<E> subSet(E from, E to);

SortedSet<E> headSet(E to);

SortedSet<E> tailSet(E from);

 

SortedMap<K, V> subSet(K from, K to);

SortedMap<K, V> headSet(K to);

SortedMap<K, V> tailSet(K from);

 

3、不可修改视图

Collections.unmodiffiableCollection

Collections.unmodifiableList

Collections.unmodifiableSet

Collections.unmodifiableSortedSet

Collections.unmodifiableMap

Collections.unmodifiableSortedMap

 

每个方法都定义于一个接口。

这些视图对现有集合增加了一个运行时的检查。

如果发现试图对集合进行修改,就抛出一个异常。

 

4、同步视图

如果由多个线程访问集合,就必须确保集不会被意外的破坏。

类库的设计者使用视图机制来确保常规集合的线程安全,而不是实现线程安全的集合类。

Map<String, Employee> map = Collections.synchronizedMap(new HashMap<String, Employee>());

 

5、检查视图

List<String> sateStrings = Collections.checkedList(strings, String.class);

视图的add方法将检测插入的对象是否属于给定的类。如果不是,则抛出ClassCastException

 

 

批操作:

bulk operation

result.retainAll(a); //保存了交集

result.removeAll(b);

result.addAll(b);

 

集合与数组之间的转换:

数组->集合:Arrays.asList包装器

集合->数组:toArray()方法

staff.toArray();//返回的是Object数组,不能强制类型转换;

staff.toArray(new String[0]);//返回的是String数组;

staff.toArray(new String[staff.size()]); //将元素一次复制到新数组中,并返回新数组

 

13.4 算法

泛型集合接口有一个很大的优点,即算法只需要实现一次。

 

排序:

Collections类中的sort方法。

这个方法假定元素实现了Comparable接口。

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

降序:Collections.reverseOrder()方法

 

Java直接将所有元素转入一个数组,并使用归并排序的变体对数组进行排序,然后将排序后的序列复制回列表。

集合类库中使用的归并排序算法比快速排序要慢,快速排序是通用排序算法的传统选择。

归并排序的优点,稳定,即不需要交换相同的元素。

 

排序的列表必须是可修改的,但不必是可以改变大小的。

·如果列表支持set,则是可修改的;

·如果列表支持addremove方法,则是可改变大小的。

 

混乱:

Collectionsshuffle算法,随机的混排列表中元素的顺序。

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

 

二分查找:

i = Collections.binarySearch(c, element);

i = Collections.binarySearch(c, element, comparator);

 

二分查找对顺序表有意义,如果对链表采用二分查找,则自动变为顺序查找。

 

编写自己的算法:

如果编写自己的算法,应该尽可能的使用接口,而不要使用具体的实现。

 

13.5 遗留的集合

Java程序设计语言自问世以来就存在的集合:Hashtable  Properties  Vector  Stack  BitSet

 

Hashtable

HashMap类的作用一样,拥有相同的接口。

Hashtable的方法也是同步的。

 

枚举:

使用Enumeration接口对元素序列进行遍历。

两个方法:hasMoreElementsnextElement

静态方法Collections.enumeration将产生一个枚举对象,枚举集合中的元素。

 

属性映射表:

property map

·键和值都是字符串;

·表可以保存到一个文件中,也可以从文件中加载

·使用一个默认的辅助表。

实现属性映射表的类称为Properties

通常用于程序的特殊配置选项。

 

栈:

stack

 

位集:

BitSet类提供了一个便于读取、设置或清除各个位的接口。

C++中的bitset功能一样。

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/387288.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Tensorflow验证码识别应用

简单的Tensorflow验证码识别应用&#xff0c;供大家参考&#xff0c;具体内容如下 1.Tensorflow的安装方式简单,在此就不赘述了. 2.训练集训练集以及测试及如下(纯手工打造,所以数量不多): 3.实现代码部分(参考了网上的一些实现来完成的) main.py(主要的神经网络代码) ?123456…

Linux 桌面玩家指南:09. X Window 的奥秘

Linux 桌面玩家指南&#xff1a;09. X Window 的奥秘 原文:Linux 桌面玩家指南&#xff1a;09. X Window 的奥秘特别说明&#xff1a;要在我的随笔后写评论的小伙伴们请注意了&#xff0c;我的博客开启了 MathJax 数学公式支持&#xff0c;MathJax 使用$标记数学公式的开始和结…

Storm教程1理论介绍

流式计算的历史: 早在7、8年前诸如UC伯克利、斯坦福等大学就开始了对流式数据处理的研究&#xff0c;但是由于更多的关注于金融行业的业务场景或者互联网流量监控的业务场景&#xff0c;以及当时互联网数据场景的限制&#xff0c;造成了研究多是基于对传统数据库处理的流式化&…

梯度下降原理及Python实现

梯度下降算法是一个很基本的算法&#xff0c;在机器学习和优化中有着非常重要的作用&#xff0c;本文首先介绍了梯度下降的基本概念&#xff0c;然后使用python实现了一个基本的梯度下降算法。梯度下降有很多的变种&#xff0c;本文只介绍最基础的梯度下降&#xff0c;也就是批…

matplotlib一些常用知识点的整理,

本文作为学习过程中对matplotlib一些常用知识点的整理&#xff0c;方便查找。 强烈推荐ipython 无论你工作在什么项目上&#xff0c;IPython都是值得推荐的。利用ipython --pylab&#xff0c;可以进入PyLab模式&#xff0c;已经导入了matplotlib库与相关软件包&#xff08;例如…

Storm教程3编程接口

Spouts Spout是Stream的消息产生源&#xff0c;Spout组件的实现可以通过继承BaseRichSpout类或者其他Spout类来完成&#xff0c;也可以通过实现IRichSpout接口来实现。 需要根据情况实现Spout类中重要的几个方法有&#xff1a; open方法 当一个Task被初始化的时候会调用此…

梳理操作系统概论

1、用一张图总结操作系统的结构、功能特征、采用的技术和提供服务方式等。 2、用一张图描述CPU的工作原理。 3、用一张图描述系统程序与应用程序、特权指令与非特权指令、CPU状态、PSW及中断是如何协同工作的&#xff1f; 转载于:https://www.cnblogs.com/ljgljg/p/10503190.ht…

位置指纹法的实现(KNN)

基本原理 位置指纹法可以看作是分类或回归问题&#xff08;特征是RSS向量&#xff0c;标签是位置&#xff09;&#xff0c;监督式机器学习方法可以从数据中训练出一个从特征到标签的映射关系模型。kNN是一种很简单的监督式机器学习算法&#xff0c;可以用来做分类或回归。 对于…

室内定位系列 ——WiFi位置指纹(译)

摘要 GPS难以解决室内环境下的一些定位问题&#xff0c;大部分室内环境下都存在WiFi&#xff0c;因此利用WiFi进行定位无需额外部署硬件设备&#xff0c;是一个非常节省成本的方法。然而WiFi并不是专门为定位而设计的&#xff0c;传统的基于时间和角度的定位方法并不适用于WiFi…

机器学习02线性回归、多项式回归、正规方程

单变量线性回归&#xff08;Linear Regression with One Variable&#xff09; 预测器表达式&#xff1a; 选择合适的参数&#xff08;parameters&#xff09;θ0 和 θ1&#xff0c;其决定了直线相对于训练集的准确程度。 建模误差&#xff08;modeling error&#xff09;&a…

机器学习03Logistic回归

逻辑回归 &#xff08;Logistic Regression&#xff09; 目前最流行&#xff0c;使用最广泛的一种学习算法。 分类问题&#xff0c;要预测的变量 y 是离散的值。 逻辑回归算法的性质是&#xff1a;它的输出值永远在 0 到 1 之间。 逻辑回归模型的假设是&#xff1a; 其中&a…

CNN理解比较好的文章

什么是卷积神经网络&#xff1f;为什么它们很重要&#xff1f; 卷积神经网络&#xff08;ConvNets 或者 CNNs&#xff09;属于神经网络的范畴&#xff0c;已经在诸如图像识别和分类的领域证明了其高效的能力。卷积神经网络可以成功识别人脸、物体和交通信号&#xff0c;从而为机…

Windows 安装Angular CLI

1、安装nvm npm cnpm nrm&#xff08;onenote笔记上有记录&#xff09; 参考&#xff1a;https://blog.csdn.net/tyro_java/article/details/51232458 提示&#xff1a;如果发现配置完后&#xff0c;出现类似“npm不是内部命令……”等信息。 可采取如下措施进行解决—— 检查环…

机器学习04正则化

正则化&#xff08;Regularization&#xff09; 过拟合问题&#xff08;Overfitting&#xff09;&#xff1a; 如果有非常多的特征&#xff0c;通过学习得到的假设可能能够非常好地适应训练集 &#xff1a;代价函数可能几乎为 0&#xff09;&#xff0c; 但是可能会不能推广到…

Adaboost算法

概述 一句话概述Adaboost算法的话就是&#xff1a;把多个简单的分类器结合起来形成个复杂的分类器。也就是“三个臭皮匠顶一个诸葛亮”的道理。 可能仅看上面这句话还没什么概念&#xff0c;那下面我引用个例子。 如下图所示&#xff1a; 在D1这个数据集中有两类数据“”和“-”…

机器学习05神经网络--表示

神经网络&#xff1a;表示&#xff08;Neural Networks: Representation&#xff09; 如今的神经网络对于许多应用来说是最先进的技术。 对于现代机器学习应用&#xff0c;它是最有效的技术方法。 神经网络模型是许多逻辑单元按照不同层级组织起来的网络&#xff0c; 每一层…

逻辑回归(Logistic Regression, LR)又称为逻辑回归分析,是分类和预测算法中的一种。通过历史数据的表现对未来结果发生的概率进行预测。例如,我们可以将购买的概率设置为因变量,将用户的

逻辑回归(Logistic Regression, LR)又称为逻辑回归分析&#xff0c;是分类和预测算法中的一种。通过历史数据的表现对未来结果发生的概率进行预测。例如&#xff0c;我们可以将购买的概率设置为因变量&#xff0c;将用户的特征属性&#xff0c;例如性别&#xff0c;年龄&#x…

机器学习06神经网络--学习

代价函数 标记方法&#xff1a; 神经网络的训练样本有 m 个 每个包含一组输入 x 和一组输出信号 y L 表示神经网络层数 Sl表示每层的 neuron 个数(SL 表示输出层神经元个数) 将神经网络的分类定义为两种情况&#xff1a; 二类分类&#xff1a;SL1, y0 or 1 表示哪一类&…

Logistic Regression Classifier逻辑回归

Logistic Regression Classifier逻辑回归主要思想就是用最大似然概率方法构建出方程&#xff0c;为最大化方程&#xff0c;利用牛顿梯度上升求解方程参数。 优点&#xff1a;计算代价不高&#xff0c;易于理解和实现。缺点&#xff1a;容易欠拟合&#xff0c;分类精度可能不高…

机器学习07应用机器学习的建议

决定下一步做什么&#xff08;Deciding What to Try Next&#xff09; 确保在设计机器学习系统时&#xff0c;能够选择一条最合适、最正确的道路。 具体来讲&#xff0c;将重点关注的问题是&#xff1a;假如你在开发一个机器学习系统&#xff0c;或者想试着改进一个机器学习…