集合接口
一、引言:
接口与实现分离,使用队列举例
//提供接口规范
interface Queue
{...}
//具体实现
class LinkedListQueue<E> impements Queue<E> {...}
class CircularArrayQueue<E> impements Queue<E> {...}
Queue<Customer> e = new LinkedListQueue<Customer>
二、迭代器
1.集合类基本接口是Collection,该接口包括两种基本方法:
public interface Collection
{
boolean add(E element);
Iterator<E> iterator();
...
}
public interface Iterator<E>
{
E next();
boolean hasNext();
void remove();
}
在javase 5.0起,可以使用for each的方式循环操作
for each可以与任何实现了Iterable接口的对象一起工作
public interface Iterable<E>
{
iterator<E> iterator();
}
C++:与C++不同。c++迭代器指针可以单独的在stl模板上进行移动。
for(vector<int>::Iterable it = vect.begin(); it != vect.end(); it++) 通过对指针解引用可以获取指针所引用对象的值
但是java不同,java遍历整个集合时,必须调用next方法,指针才会向下移动。每次移动之前,都需要hasNext判断下一个值是否存在。从某种意义上说。查找操作指针移动时紧密相连的。
2.删除元素
iterator接口中remove方法时删除上次next方法返回时的元素。因此在调用remove方法时,必须首先要调用next方法。
3.泛型的实用方法(举例)
public static <E> boolean contains(Collection<E> c, object obj)
{
for(E element:c)
if(element.equal(obj))
return true;
return false;
}
Collection接口声明的很多类似于上述的泛型方法
比Collection更容易实现的抽象类
public abstract class AbstractCollection<E> implements Collection<E>
{
public abstract Iterator iterator();
public boolean contance(object obj)
{
for(E element:c)
if(element.equal(obj))
return true;
return false;
}
...
}
//api 原书 567页
三、具体集合
ArrayList 索引 vector
LinkedList 高效插入删除 List
ArrayDeque 循环数组 双端队列
HastSet 没有重复元素的无序集合
TreeSet 有序集合
EmnuSet 包含枚举类型的集
LinkedHastSet 记住元素插入次序的集合
PriorityQueue 允许高效删除最小元素的集合
HastMap 键值对
TreeMap 有序排列的映射表
LinkedHastMap 记住键值对插入次序的集合
WeakHashMap 值无效可以被垃圾回收期回收的映射表
IdentityHaspMap 使用==而不是equals比较键值的映射表
set是没有重复的元素集合
1.链表:
链表是一个有序集合,因此可以使用add方法将元素插入链表的任意位置。对于无序的集合HastSet则没有该方法
ListIterator接口中也有两个方法用于逆向遍历
E previous(); 反向遍历元素
boolean hasPrevious()
remove始终删除上一次 next/previous 刚刚遍历的元素
add方法依赖于迭代器的位置
remove方法依赖于迭代器的状态
set的方法用于替换 next/previous 刚刚遍历的元素
ListIterator<String> iter = list.listIterator();
String oldValue = iter.next();
iter.set(newValue);
迭代器指向两个元素之间,因此可以返回两个指向的对象。使用nextIndex方法返回下一个将要遍历的元素的整数索引。previous返回刚刚遍历元素的整数索引
get方法,效率不高。。。
简单例子:
List<String> a = new LinkedList();
a.add("hh")
ListIterator<String> iter = a.listIterator();
while(iter.hasNext())
{
a.next();
a.remove();
}
//api 原书 575页
C++:
list<string> list;
list<string>::iterator iter;
list.push_back("hh");
for(it = list.begin(); it != list.end; it++)
{
std::cout << *it << std::end;
}
2.数组列表 ArrayList
与list相同。但是,对于以数组为底层封装的列表来说,set/get方法将变得非常有用
3.散列集 快速查找需要的对象
散列表为每个对象计算一个整数,成为散列码
散列码是由对象的实际域产生的一个整数
具有不同数据域的对象将产生不同的散列码
(如果自定义域,就要实现HashCode方法。实现的方法要与equal方法相同,即a.equal(b)为true时,a,b必须有相同的散列码) ==》具体第五章
散列表使用链表数组实现。每个列表称之为桶。要查找表中对象的位置,就要计算它的散列码,然后与桶的余数取余。得到该对象元素的索引。
set是没有重复的元素集合。contains方法重新定义可以快速查看元素是否已经插入。使用add方法添加元素。它的访问顺序几乎是随机的。
//api 原书 578页
4.树集
TreeSet与散列集十分类似,它是一个有序集合,可以以任意顺序将元素插入集合。遍历时将依次访问。
将元素添加到TreeSet比添加到散列表慢,但是比将元素添加到链表或数组的正确位置上还是快很多。并且,TreeSet还可以自动排序
TreeSet();
TreeSet(Collection<? extends E> elements);
5.对象的比较 compareTo方法和equal方法
6.队列与双端队列 (不支持在队列中间添加元素)
Javase6 引入了Deque接口,并由ArrayDeque和LinkedList类实现
api:
//如果满了,抛出异常IIlegalStateException
boolean add(E element);
//如果满了,返回false
boolean offer(E element);
//如果不为空,删除并返回头部元素,如果为空,抛出异常NoSuchElementException
E remove();
//同上,如果为空,返回null
E poll();
//如果不为空,返回头部元素不删除,如果为空,抛出异常NoSuchElementException
E element();
//同上,如果为空,返回null
E peek();
//如果满了,抛出异常IIlegalStateException
void addFirst(E element)
void addLast(E element)
//如果满了,返回false
boolean offerFirst(E element)
boolean offerLast(E element)
//如果不为空,删除并返回头部元素,如果为空,抛出异常NoSuchElementException
E removeFirst();
E removeLast();
//同上,如果为空,返回null
E pollFirst();
E pollLast();
//如果不为空,删除并返回头部元素,如果为空,抛出异常NoSuchElementException
E getFirst();
E getLast();
//同上,如果为空,返回null
E peekFirst();
E peekLast();
ArrayDeque();
ArrayDeque(int initialCapacity);
//初始容量16或给定初始容量构造一个无限双端队列
7.优先级队列
元素可以任意顺序输入,却总是按照排序顺序检索。无论何时调用remove方法,总是会获取当前优先级队列中最小元素,但是,优先级队列并没有进行排序。
使用数据结构==》 堆
堆是一个可以自我调整的二叉树。可以让最小元素移动到树根而不必花时间进行排序。
典型案例: 任务调度
PriorityQueue();
//构造一个用于存放Compareable对象的优先级队列
PriorityQueue(int initialCapacity);
//构造一个优先级队列,并用指定比较器对元素排序
PriorityQueue();
8.映射表 键值对 --------------字典
HashMap(散列映射表)和TreeMap(树映射表),这两个类都实现了Map接口
散列映射表对键进行散列
树映射表用键的整体顺序进行排序,并组成搜索树
散列稍微快一点,如果不需要按照顺序访问,最好选择散列
put方法新增或者更改键对应的值
remove();删除键对应的值 size();//返回元素个数