思想:在面向对象的思想里,一种数据结构被认为是一种容器。在本质上来讲是一个类,提供方法支持查找,插入和删除等等操作。
Java集合框架支持以下俩种类型的容器:
存储一个元素集合,简称为集合Collection
存储键值对,称为图Map
集合collection
三种主要类型 : 规则集(set) , 线型表(List) , 队列(Queue)
set: 存储一组不重复的数据
List: 存储由元素构成的有序集合
Queue: 存储先进先出方式处理的对象
细说Collection接口: 它是处理对象集合的根接口。有基本的添加和删除操作。有类似于规则集的并,差,交运算。
简单的
细致的
规则集Set接口
Set接口的三个孩子是 散列类HashSet,链式散列集LinkedHashSet和树形集TreeSet
散列集HashSet
在这之前散列是啥意思? ::: -》 Hash,一般翻译做“散列”,也有直接音译为“哈希”的,就是把任意长度的输入(又叫做预映射,
pre-image),通过散列算法,变换成固定长度的输出,该输出就是散列值。 简单的说就是一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。
------来源百度百科
这个看起来和MD5加密算法一样,对吧。 继续走
HashSet的无参构造函数有点意思 : 可以创建空的,也可以由一个现有的集合来创建
默认情况下初始容量为16而客座率为0.75,如果知道集合的大小可自己指定其参数从而不需要系统自动分配。
那问题来了,客座率是啥?
我的理解是: 集合大致会使用其申请空间的百分比,比如你new一个列数为10的一维数组,并没有放满10个,而是7个,这样客座率为0.7
正式解答
客座率是测量在增加规则集的容量之前,该规则集的饱满程度。在0.0~1.0之间。 当元素个数超过了容量与客座率的乘积,容量就会翻倍。 (不得不佩服java设计大师)
当然这样也有弊端,客座率高会降低空间开销,但是会增加查找时间。通常是0.75,权衡的很好 。
HashSet是用来存储互不相同的任何元素
添加到散列集中的对象必须以一种正确分散散列码的方式来实现hashCode方法。 这个是为了效率.( 其实 我也不懂这个所追求的是哪方面的效率,应该是查找吧,求大神解答)
它的api中有三个方法很好玩,一个addAll removeAll retainAll 类似于规则集中的并 差 交 运算 (难怪我在看数据挖掘时代码中使用了Set集合,难怪如此.....)
set1.addAll(set2); //set2是一个规则集,这样会添加set2中的元素进入set1 当然set1不会重复的
set1.removeAll(set2); //从set1中删除在set1中出现set2中的元素
set1.retainAll(set2); //得到公共元素
链式散列集LinkedHashSet
这个支持对规则集的元素排序,只是对插入的时间来排序。
其余和上面的一样 ,但是如果不需要排序的话就使用HashSet,因为高效率。
树形集TreeSet
这个可以确保规则集是有序的 方法headSet(toElement)
和tailSet(fromElement) 以返回规则集中元素小于toElement和大于或等于fromElement的那一部分
那么是怎么比的呢??? TreeSet实现了SortedSet接口的一个具体类,有comparableTo方法(因为添加到规则集中的对象都是Comparable的实例) 许多Java API中的类,例如String,Date,Calender类以及所有基本数据类型的包装类,都实现了Comparable接口,这种方法定义的顺序通常称为自然顺序。
Set<String> set=new TreeSet<String>(); set.add("London"); set.add("Paris"); set.add("New York"); set.add("San Francisco"); set.add("Beijing"); set.add("New York"); TreeSet<String> treeSet=new TreeSet<String>(set); System.out.println(treeSet); System.out.println("first():"+treeSet.first()); System.out.println("last():"+treeSet.last()); System.out.println("headSet():"+treeSet.headSet("New York")); //返回之前的 System.out.println("tailSet():"+treeSet.tailSet("New York")); //返回之后的,包括它自身 System.out.println("lower(\"p\"):"+treeSet.lower("P")); //返回小于P的最大元素 System.out.println("higher:"+treeSet.higher("P")); //返回大于P的最小元素 System.out.println("floor:"+treeSet.floor("P")); //返回小于或等于P的最大元素 System.out.println("ceiling:"+treeSet.ceiling("P")); //返回大于或者等于P的最小元素 System.out.println("poolFirst:"+treeSet.pollFirst()); //删除第一个并返回 System.out.println("pollLast:"+treeSet.pollLast()); //删除最后一个并返回 System.out.println("new Set"+treeSet);
Java集合框架张的所有具体类都至少有俩个构造方法,一个是创建空集合的无参构造方法,另一个是用某个集合来创建实例的构造方法,这样,TreeSet类中就含有从集合c创建 TreeSet对象的构造方法TreeSet(Collection c) 在上面的例子里,new TreeSet(set)方法从集合set创建了一个TreeSet的一个实例,因为涉及到更新规则集,有时候会牵涉到集合的重新排序。如果不需要保持元素的排序关系,就使用散列集HashSet,因为插入和删除元素效率高,当需要一个排好序的集合时就可以从这个散列集创建一个树形集。
比较器Comparator
这个接口有俩个方法equals和compare 可以自己实现这个接口,还有Serizlizable接口(可序列化数据结构)
Compareable用于比较实现Compareable的类的对象,而Compareator用于比较没有实现Compareator的类的对象
线性表List
数组线性表 ArrayList 链表 LinkedList
增加了面向位置的操作
ArrayList用数组存储元素,这个数组是动态创建的,如果元素个数超过了数组容量,就创建一个更大的新数组,并当前数组中的所有元素都复制到新数组中。 它不能自动减少。
LinkedList在一个链表中存储元素。
如果需要通过下标随机访问元素,但是除了在末尾处之外,不能在其他位置插入或删除元素,ArrayList高效率。
如果需要在任意位置插入或删除元素,就应该选择LinkedList。
List<Integer> alist=new ArrayList<Integer>(); alist.add(1); //10 alist.add(2); alist.add(3); alist.add(1); //30 alist.add(4); //4 1 30 3 2 1 10 alist.add(0,10); //把下标为0的元素挤到下标为1的地方 alist.add(3,30); System.out.println(" A list of integer in array list:\n"+alist); LinkedList<Object> llist=new LinkedList<Object>(alist); llist.add(1,"red"); llist.removeLast(); llist.addFirst("green"); //顺序输出 System.out.println("Display the linked list forward:"); ListIterator<Object> iterator=llist.listIterator(); while(iterator.hasNext()){ System.out.print(iterator.next()+" "); } System.out.println(); //逆序输出 System.out.println("Display the linked list backward"); iterator=llist.listIterator(llist.size()); while(iterator.hasPrevious()){ System.out.print(iterator.previous()+" "); }
总结: 若要提取元素或在线型表的尾部插入和删除元素,ArrayList效率高,如果是任意位置,那么LinkedList效率高。
Java提供了静态的asList方法创建线性表
线性表和集合的静态方法
sort(List) 排序
binarySearch(List,Comparator) 二分法查找
reverse(List) 颠倒指定的列表
reverseOrder() 返回逆序的比较器
shuffle(List) 随机打乱指定的列表
shuffle(List,Random)
copy(List,List) 将源列表复制给目标列表
nCopies(int,Object) 返回含n个副本的列表
fill(List,Object) 用对象填充列表
max(Collection,Comparator) 返回max对象
min(Collection,Comparator)
dijoint(Collection,Collection) 没有公共元素就返回true
frequency(Collection,Object) 返回指定元素的出现次数
List<String> list=Arrays.asList("red","green","blue"); Collections.sort(list); //排序 System.out.println(list); Collections.sort(list,Collections.reverseOrder()); //逆序输出 System.out.println(list); List<Integer> list1=Arrays.asList(2,4,7,10,11,45,50,59,60,69); System.out.println("(1) Index:"+Collections.binarySearch(list1,7)); System.out.println("(2) Index:"+Collections.binarySearch(list1,9)); System.out.println("(3) Index:"+Collections.binarySearch(list,"blue")); //-1 System.out.println("(4) Index:"+Collections.binarySearch(list,"cyna")); Collections.reverse(list); //逆序排序 System.out.println("reverse:::::"+list); Collections.reverse(list); System.out.println("reverse2:::::"+list); Collections.shuffle(list,new Random(2)); //随机打乱顺序 System.out.println("shuffle::::"+list); System.out.println("*********************copy()**********************"); List<String> list2=Arrays.asList("yellow","red","green","blue"); List<String> list3=Arrays.asList("white","black"); Collections.copy(list2,list3); System.out.println(list2); List<Integer> list4=Collections.nCopies(5,5); /*用nCopies()方法创建的线性表是不可变的,不能在该线性表中添加删除或更新*/ //list4.add(new Integer(6)); System.out.println(list4); List<String> list5=Arrays.asList("red","green","blue"); Collections.fill(list5,"aha~"); //全部替换成"aha~" System.out.println("fille():"+list5);
性能测试
public static void main(String[] args) { Collection<Integer> set1=new HashSet<Integer>(); System.out.println("the time of HashSet is:"+getTestTime(set1,500000)+"milliseconds"); Collection<Integer> set2=new LinkedHashSet<Integer>(); System.out.println("the time of LinkedHashSet is:"+getTestTime(set2,500000)+"milliseconds"); Collection<Integer> set3=new TreeSet<Integer>(); System.out.println("the time of TreeSet is:"+getTestTime(set3,500000)+"milliseconds"); Collection<Integer> set4=new ArrayList<Integer>(); System.out.println("the time of ArrayList is:"+getTestTime(set4,500000)+"milliseconds"); Collection<Integer> set5=new LinkedList<Integer>(); System.out.println("the time of LinkedList is:"+getTestTime(set5,500000)+"milliseconds"); } public static long getTestTime(Collection<Integer> c , int size){ long start=System.currentTimeMillis(); List<Integer> list=new ArrayList<Integer>(); for(int i=0;i<size;i++) list.add(i); Collections.shuffle(list); for(int element: list) c.add(element); Collections.shuffle(list); for(int element: list) c.remove(element); long end=System.currentTimeMillis(); return end-start; }
C:\Users\Administrator\Desktop>javac TestTreeSet.java
C:\Users\Administrator\Desktop>java TestTreeSet
the time of HashSet is:407milliseconds
the time of LinkedHashSet is:1185milliseconds
the time of TreeSet is:1178milliseconds
the time of ArrayList is:267940milliseconds
the time of LinkedList is:705575milliseconds
向量类Vector和栈类Stack
除了包含用于访问和修改向量的同步方法之外,和ArrayList是一样的,同步是为了防止多个线程同时访问某个向量时引起数据损坏。如果不需要这个,ArrayList效率高一些。
实现了List接口,详情查看API手册,除l了添加元素方法是同步的之外
队列和优先队列
先进先出
接口Queue<E> 一般使用LinkedList<E>来实现它
boolean |
offer(E e)
将指定的元素插入此队列(如果立即可行且不会违反容量限制),当使用有容量限制的队列时,此方法通常要优于 |
E |
poll()
获取并移除此队列的头,如果此队列为空,则返回 |
E |
remove()
获取并移除此队列的头。 |
E |
peek()
获取但不移除此队列的头;如果此队列为空,则返回 |
E |
element()
获取,但是不移除此队列的头。 |
public static void main(String[] args) { Queue<String> queue=new LinkedList<String>(); queue.offer("first"); queue.offer("second"); queue.offer("third"); queue.offer("fourth"); /** * poll():获取并删除队列头,队列为空返回null * remove():获取并删除队列头,队列为空返回异常 * peek():获取但不删除队列头,队列为空返回null * element():获取但不删除队列头,队列为空返回异常 */ System.out.println("队头为:"+queue.element()); System.out.println("队长为:"+queue.size()); }
类PriorityQueue<E>
构造方法摘要 | |
---|---|
PriorityQueue()
使用默认的初始容量(11)创建一个 |
|
PriorityQueue(Collection<?
创建包含指定 collection 中元素的 |
|
PriorityQueue(int initialCapacity)
使用指定的初始容量创建一个 |
|
PriorityQueue(int initialCapacity, Comparator<?
使用指定的初始容量创建一个 |
|
PriorityQueue(PriorityQueue<?
创建包含指定优先级队列元素的 |
|
PriorityQueue(SortedSet<?
创建包含指定有序 set 元素的 |
public static void main(String[] args) { // 默认为自然排序 PriorityQueue<String> queue=new PriorityQueue<String>(); queue.offer("java"); queue.offer("net"); queue.offer("C"); queue.offer("python"); while(queue.size()>0){ System.out.print(queue.remove()+"\t"); } System.out.println(); // 修改排序方式 PriorityQueue<String> queue2=new PriorityQueue<String>(4,Collections.reverseOrder()); queue2.offer("java"); queue2.offer("net"); queue2.offer("C"); queue2.offer("python"); while(queue2.size()>0){ System.out.print(queue2.remove()+"\t"); } }
图
这是一种存储键值对的容器,不能有重复的键值。
分为三种,HashMap,LinkedHashMap,TreeMap
public static void main(String[] args) { Map<String,Integer> hashmap=new HashMap<String, Integer>(); hashmap.put("chenjian", 21); hashmap.put("liuzhenguang", 22); hashmap.put("guoliangjun", 23); hashmap.put("qiufubi", 22); System.out.println(hashmap); //随机输出 //从一个散列图创建一个树形图 Map<String,Integer> treemap=new TreeMap<String, Integer>(hashmap); System.out.println(treemap); //按照键值排序输出 Map<String,Integer> linkedmap=new LinkedHashMap<String, Integer>(11,0.75f,false); linkedmap.put("chenjian", 21); linkedmap.put("liuzhenguang", 22); linkedmap.put("guoliangjun", 23); linkedmap.put("qiufubi", 22); System.out.println(linkedmap); //按照插入的时间顺序输出 }
统计单词出现的次数
/**统计单词出现的次数 * 在TreeMap中,键值排序 * Have 比 a 优先级要高 大写比小写高 */ public static void main(String[] args) { String text="Hello,Chicago! Have a nice day! Baby! Have fun this day."; TreeMap<String, Integer> map=new TreeMap<String, Integer>(); String[] words=text.split("[ \n\t\r.,;:!?(){]"); for (int i = 0; i < words.length; i++) { String key=words[i].toLowerCase(); if(key.length()>0){ if(map.get(key)==null){ map.put(key, 1); }else{ int value=map.get(key).intValue(); map.put(key, value+1); } } } for(Map.Entry<String, Integer> m:map.entrySet()){ System.out.println(m.getKey()+" \t "+m.getValue()); } }
单元素和不可变的集合和图
|
singleton(T o)
返回一个只包含指定对象的不可变 set。 |
|
static
|
singletonList(T o)
返回一个只包含指定对象的不可变列表。 |
|
static
|
singletonMap(K key,
返回一个不可变的映射,它只将指定键映射到指定值。 |
|
unmodifiableCollection(Collection<?
返回指定 collection 的不可修改视图。 |
|
static
|
unmodifiableList(List<?
返回指定列表的不可修改视图。 |
|
static
|
unmodifiableMap(Map<?
返回指定映射的不可修改视图。 |
|
static
|
unmodifiableSet(Set<?
返回指定 set 的不可修改视图。 |
|
static
|
unmodifiableSortedMap(SortedMap<K,?
返回指定有序映射的不可修改视图。 |
|
static
|
unmodifiableSortedSet(SortedSet<T> s)
返回指定有序 set 的不可修改视图。 |
问题: Comparable接口和Comparator接口有啥区别?
Comparator位于包java.util下,而Comparable位于包 java.lang下。
都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator
是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。
在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序。
Comparator
是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
例如:
public class AbsComparator implements Comparator<Object> { public int compare(Object o1, Object o2) { int v1=Math.abs(((Integer)o1).intValue()); int v2=Math.abs(((Integer)o2).intValue()); return v1>v2?1:(v1==v2?0:-1); } }
public static void main(String[] args) { Random random=new Random(); Integer[] ints=new Integer[20]; for (int i = 0; i < ints.length; i++) { ints[i]=new Integer(random.nextInt(100)*(random.nextBoolean()?1:-1)); } System.out.println("使用内置方法排序"); Arrays.sort(ints); System.out.println(Arrays.asList(ints)); System.out.println("使用自定义排序"); Arrays.sort(ints,new AbsComparator()); System.out.println(Arrays.asList(ints)); }
使用内置方法排序
[-99, -93, -91, -90, -55, -47, -39, 14, 26, 27, 27, 44, 53, 63, 65, 77, 81, 82, 84, 93]
使用自定义排序
[-4, -12, -18, 25, 40, 42, 44, -62, -71, -74, -77, -81, 82, -87, 87, 87, 90, -93, -94, 95]
而使用Comparable接口做比较
public class Person implements Comparable<Object> { public int compareTo(Object o) { // TODO Auto-generated method stub return 0; } }
就可以自定义写比较方法
参照书籍《Java语言程序设计·进阶篇》 下一篇是编程练习题
2015年6月5日19:42:49
我是菜鸟,我在路上。