天天看点

java retainall双链表_java集合 读书笔记

Java库中的具体集合和整个集合框架

链表

数组列表

散列集

树集

队列与双端队列

优先级队列

映射表

Java库中的具体集合和整个集合框架

链表(LinkedList)

数据和数组列表有一个重大缺陷,因为删除一个或者添加一个元素都需要付出很大的代价,原因是出于被删除或被添加的元素后面的所有元素都要被移动,而链表就解决了这个问题。删除添加只需要对被删除元素附近的节点更新一下即可。但因为结果原因,如果要对集合经常随机访问,则最好使用arraylist.

LinkedList.add方法是把元素添加到尾部,如果想添加到中间,就的借助迭代器。因为linkedlist里面的元素是有序的,所以他的迭代器里面是有添加方法的,而集(set)里面的元素完全无序,所以他的迭代器接口就没有add方法。ListIterator里面的add方法就可以把元素添加到迭代器位置之前。。

如果有多个迭代器在一个集合上迭代,集合被一个迭代器或者自身修改,那么迭代器都没有意义了,就会发出异常!

列表不支持快速随机访问,如果想访问第N个元素,那就就的才能够头开始越过n-1个元素,所以在这种情况下一般不选择链表。但是尽管如此LinkedListjava类库还是提供了理论上存在争议的一些方法。比如采用整数索引访问元素,get(n)但是这个效率肯定不高,previousIndex,nextIndex这个效率还是很高的。

数组列表(ArrayList)

ArrayList实现了list接口,而且对于get,set方法随机访问每个元素是非常的效率,封装了一个动态再分配的对象数组。

散列集(hashSet)

散列码由hashcode方法生成,应该于equals方法兼容,就是说如果a.equals(b)为true,那么a,b的散列码一定相同,如果自己定义类就应该负责实现这个类的hashCode方法。里面的元素是没有顺序的,而且元素不能重复。迭代器也是随机的遍历元素。

数集(treeSet)

与散列集不同的是,添加完元素后,元素会按照树结构把元素自动有序的排列起来,这样便利的时候得到的是已经排好序列的元素列表。当然添加元素的速度要比散列集慢点,但是还是比链表和数组的正确位置上要快点。

队列与双端队列

队列java.util.Queue 双头队列java.util.Deque可以在头部或尾部添加删除元素。

优先级队列(priority queue)

元素可以随便插入队列。也就是说remove的时候一定是优先级最小的元素。优先级队列使用了一个优雅且高效的数据结构堆(heap),这是一个可以自我调整的二叉树,添加删除操作,可以让最小的元素移动到跟。举个例子更好的了解,他不是把全部元素排序,而是只是把最小的放在的最头上面。TreeSet却是把全部排序,所以优先级队列速度要比treeset快。

PriorityQueuepq = new PriorityQueue(); pq.add(new GregorianCalendar(1906, Calendar.DECEMBER, 9)); // G. Hopper pq.add(new GregorianCalendar(1815, Calendar.DECEMBER, 10)); // A. Lovelace pq.add(new GregorianCalendar(1903, Calendar.DECEMBER, 3)); // J. von Neumann pq.add(new GregorianCalendar(1910, Calendar.JUNE, 22)); // K. Zuse System.out.println("Iterating over elements..."); for (GregorianCalendar date : pq) System.out.println(date.get(Calendar.YEAR)); System.out.println("Removing elements..."); while (!pq.isEmpty()) System.out.println(pq.remove().get(Calendar.YEAR));

结果

Iterating over elements...

1815

1906

1903

1910

Removing elements...

1815

1903

1906

1910

映射表(hashMap TreeMap)

散列映射对键进行散列,而树映射表用键的整体顺序对元素进行排列,只作用于键,对关联的值不能进行散列和比较。这里有3个试图,键集,值集合,键值对集。

SetkeySet()

Collectionvalues()

Set> entrySet()

for(String key:keys)//遍历键集

{

do something with key

}

//遍历对集

for(Map.Entryemtry : staff-emtrySet()){

String key=entry.getKey();

Employee value= entry.getValue();

do something with key,value

}

专业集与映射表类

弱散列映射表(weakHashMap)

有些值的键被引用一次后就不用了如果不明确的删除,垃圾收集器收集器又不会自动收集垃圾,所以就用到了弱散列映射表。

链接散列集和链接映射表(linkedhashset,linkedhashmap)

这样就能记住插入元素项的顺序。遍历的时候就能按照插入的顺序遍历。 当然也可以按照存取顺序遍历,当用get or put方法,那么这个被取出或者放进去的元素就会被从当前位置去掉,然后放到最后面。这样有利于实施一个 最近最少使用的cache。

枚举集与枚举映射集(EnumSet,EnumMap)

EnumSet是一个枚举类型元素集的高效实现。 由于枚举类型只有有限个实例, 所以EnumSet内部用位序实现,如果对应的值集中,则相应的位置为1.

enum Weekday {MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY};

EnumSetalways = EnumSet.allOf(Weekday.class);

EnumSetnever = EnumSet.noneOf(Weekday.class);

EnumSetworkday= EnumSet.range(Weekday.MONDAY, Weekday.FRIDAY);

EnumSetmwf = EnumSet.of(Weekday.MONDAY, Weekday.WEDNESDAY, Weekday.FRIDAY);

EnumMap

EnumMappersonInCharge = new EnumMap(Weekday.class);

标识散列映射表(IdentityHashMap)

键的散列值不是用hashcode计算的,而是用System.identityHashCode计算的,这是object.hashCode方法根据对象的内存地址来计算散列码时用的方式。对两个对象进行比较时,不用equals,而是==。也就是说不同的键对象,即使内容相同,也被视为不同的对象。

视图与包装器

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

Card[] cardDeck = new Card[52];

ListcardList = Arrays.asList(cardDeck);

这是个视图对象,可以使用get,set方法,但是添加删除都会抛出异常。

Collections.nCopies(n,anObject)创建一个包含n个元素的list,每个元素都是一个anObject.

Collections.singleton(anObject)返回一个视图对象,实现了set接口,不可修改的单元素集。

subList(),subSet,headSet,tailSet,subMap,headMap,tailMap方法可以得到相应集合的子范围,而且子范围上的修改直接反应到原集合上。

Collections.unmodifiableCollection,Collections.unmodifiableList,Collections.unmodifiableSet,Collections.unmodifiableSortedSet,

Collections.unmodifiableMap,Collections.unmodifiableSortedMap可以得到不可更改视图,只能读不能修改。但是原集合依然可以修改。

Collections.synchronizedMap可以得到线程安全的同步视图,这样就可以多线程访问同步视图了,get,put这种操作都被串行操作,是线程安全的。

被检查视图可以检测是否有classCast错误例子如下:

ArrayListstrings=new ArrayList(); ArrayList rawList = strings;//get warning only, not an error, for compatibility with legacy code. rawList.add(new Date());// now String contains a Date object!! //这个错误的命令在运行的时候是检测不到的。只有在稍后的另一部分代码中那个调用get,并将结果转化为string,才会抛出ClassCastException错误异常 ListsafeStrings = Collections.checkedList(strings,String.class); ArrayList rawList = safeStrings; rawList.add(new Date());//Checked list throws a ClassCastException

这里还有一些批操作

Setresult=new HashSet(a);

result.retainAll(b)在result保留a与b中出现的元素。就是交集。

removeAll,allAll

集合与数组之间的转化

String[] values = ...;

HashSetstaff= new HashSet(Arrays.asList(values));

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

算法

Collections.sort(staff,itemComparator);

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

Collections.schuffle(ArrayList);随机混排列表里面的元素。

Collecitions.binarySearch(c,element),Collections.binarySearch(c,element,comparator);但是前提是集合必须是有序的而且是支持随机访问的。否则不是有序的就出异常,不是随机访问的,效率非常低就跟线性查找一样的效率了,如果找不到对应元素,那么可以根据范围的负值索引,插入这个元素,if(i<0) c.add(-i-1,element); i是返回的负值索引。

min,max,copy,fill,addAll,indexOfSubList,lastIdexOfSubList,swap,reverse,rotate,frequency,disjoint方法。

遗留的集合

hashTable跟hashMap作用一样,而且是同步的,但是如果对同步性或者与遗留代码的兼容性没有任何要求,就应该使用hashMap.

枚举Enumeration有两个方法,hasMoreElements,nextElement类似与iterator接口的hasNext,next方法。

属性映射表(perperty map)比较特殊,有3个特性:键与值都是字符串,可以保存到一个文件中,也可以从文件中加载。还有一个默认的辅助表。

位集(BitSet)用来存放一个位序列,由于位集将位包装在字节里面,所以比使用Boolean对象的ArrayList更加有效。