根据数据结构,简单罗列java集合种类及相关介绍和使用,在此附上java官方api帮助文档,通过本文简单了解、整体把握住要点后,具体使用可参考帮助文档:
链接: https://pan.baidu.com/s/1ic_kiSV6ZN_dYHWp8HeM1g
提取码:40dv
1.常见数据结构
数据存储的常用结构有:栈、队列、数组、链表和红黑树
- 栈 记住一句话“先进后出的线性表”,存取数据时先进去的被压到栈底,等它上面的出去后才能出;
- 队列 在表的一端进行插入,而在另一端进行删除元素的线性表,同样记住“先进先出”,因为它是两个口,一个口入,一个出,先进去的可以先从出口出;
- 数组 在内存中开辟一段连续的空间,存储相同类型的数据,可通过下标快速获取对应位置的数据,但是分配空间时要指定大小,插入删除元素很慢(慢是因为每次插入一个元素,要把原来的数组复制到一个更大的数组中);
- 链表 :由一组不必相连的内存结构(节点),按特定的顺序链接在一起的抽象数据类型;每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
特点:离散存储线性结构;空间没有限制;插入删除快,但存取慢
类别:单链表、双向链表、循环链表(上图一看就明白): - 二叉树是每个结点不超过2的有序树
结构:也是直接上图: - 遍历:先序遍历,中序遍历,后序遍历
• 先序遍历
先访问根节点,然后访问左节点,最后访问右节点(根->左->右)
• 中序遍历
先访问左节点,然后访问根节点,最后访问右节点(左->根->右)
• 后序遍历
先访问左节点,然后访问右节点,最后访问根节点(左->右->根)
由上图可知(自行领会,很简单):
先序遍历(根-左-右):1-2-4-8-9-5-10-3-6-7
中序遍历:(左-根-右):8-4-9-2-10-5-1-6-3-7
后序遍历(左-右-根):8-9-4-10-5-2-6-7-3-1
集合
在数据结构中的数组是我们最长见的一种,但是它的长度是固定的,且只能存储基本数据类型,这就使我们在平常使用中受到了很多限制。而java中为我们提供了可以存储对象的不定长的集合,因此集合就是一种容器。
集合包含了单列集合(Collection)和双列集合(Map):
- 单列集合
Collection:单列集合类的根接口,包括两个常用的子接口: java.util.List 和 java.util.Set
List 存取有序,带有索引
子类:ArrayList集合(数组结构)、LinkedList集合(链表结构)
ArrayList:
注意:帮助文档中说无参构造后默认大小为10,但其实无参构造后是大小为0的数组,调用add方法后默认才是10,(add:返回一定为true),见源码:
每次扩容增量为原来的1.5倍
其他常用方法使用:
Vector 与List差不多,不多说了,注意一点,vector扩容时增量为原来的2倍(查看源码如图所示)
注意:ArrayList是线程不安全的,vector是线程安全的(具体原因后面的文章中专门讲解)
LinkedList集合:
操作与以上两者大致相同,具体可参考API
提供了模拟栈结构的push和pop方法进行压栈和弹栈操作
Iterator:迭代器,可用来迭代collections下所有集合
Iterator<Integer> it=data.iterator();
while(it.hasnext){
Integer a=it.next();
it.remove();//必须通过next()获取到再删
ListIterator:只能迭代list下的集合
ListIterator<Integer> iterator=arrList.listIterator();
System.out.println("开始时的数据:");
System.out.println(arrList);
iterator.next();//向下移动
iterator.add(300);//在这个位置添加
iterator.previous();//返回上一步
iterator.previous();//返回上一步到起点
//重新遍历
System.out.println("重新遍历:");
while (iterator.hasNext()){
System.out.println(iterator.next());
}
forEach:
迭代数组和集合(collection下的集合):
遍历数组和集合:
//forEach
int[] array={1,3,5,7,8,4,6};
for (int data:array) {
System.out.println(data);
}
//forEach遍历集合
ArrayList<String> aList=new ArrayList<>();
aList.add("一路向北");
aList.add("枫");
aList.add("最长的电影");
aList.add("晴天");
for (String str:aList) {
System.out.println(str);
}
Set集合 继承自collection接口,不能有重复元素,注意存储可变对象时要小心
HashSet:
散列存放结构:不可重复,无序的
//HashSet
HashSet<String> zhou=new HashSet<>();
zhou.add("稻香");
zhou.add("七里香");
zhou.add("可爱女人");
zhou.add("告白气球");
//不可重复:
boolean ret=zhou.add("七里香");
System.out.println(ret);
//无序
System.out.println("打印");
for (String str:zhou) {
System.out.println(str);
}
打印结果与存储顺序不一样:
TreeSet: 有序(数据的顺序而非存储顺序)二叉树存储(基于TreeMap结构)
TreeSet<String> jay=new TreeSet<>();
jay.add("y印第安老斑鸠");
jay.add("x鞋子特大号");
jay.add("t土耳其冰淇淋");
jay.add("c床边故事");
for (String str:jay) {
System.out.println(str);
}
有序是指数据根据的顺序:
排序时如果是自定义对象时必须要实现Comparable接口:
重写compareTo()方法,指定排序规则:
static class jayChou implements Comparable<jayChou>{
private String album;
private int year;
public jayChou(String album, int year) {
this.album = album;
this.year = year;
}
@Override
public String toString() {
return "jayChou{" +
"album='" + album + '\'' +
", year=" + year +
'}';
}
@Override
public int compareTo(jayChou o) {
if (this.year<o.year){
return -1;
}else if (this.year==o.year){
return 0;
}
return 1;
}
}
存储:
jayChou qlx=new jayChou("七里香",2004);
jayChou yhm=new jayChou("叶惠美",2003);
jayChou ftx=new jayChou("范特西",2001);
TreeSet<jayChou> album=new TreeSet<>();
album.add(ftx);
album.add(yhm);
album.add(qlx);
for (jayChou str:album) {
System.out.println(str.toString());
}
两个概念:
快速失败:一个迭代器遍历时另一个对集合进行了修改就会抛出异常;
安全失败:失败不会出错,遍历时复制一份进行遍历
重写Comrator的compare,调用Arrays.sort()进行排序:
static class myComparator implements Comparator{
@Override
public int compare(Object o1, Object o2) {
if (((jayChou)o1).year<((jayChou)o2).year)
return -1;
else if (((jayChou)o1).year==((jayChou)o2).year)
return 0;
return 1;
}
}
调用:
jayChou[] jc=new jayChou[]{qlx,yhm,ftx};
System.out.println("排序前:");
for (jayChou str:jc) {
System.out.println(str.toString());
}
//用Arrays.sort()进行排序
Arrays.sort(jc,new myComparator());
System.out.println("排序后:");
for (jayChou str:jc) {
System.out.println(str.toString());
}
结果:
2. 双值集合
Map:
单值:List 和set
双值:Map:key唯一且不能重复
常用方法:
clear():清楚
keySet():把key存储为Set集合返回,通过遍历获取键后用get方法获取值
put():如果已经存在用新值替换旧值,返回旧值;不存在返回空
remove(key,value)
remove(key):返回被删除的值,没有返回null(获取并删除)
hashmap:
先了解哈希表结构:
优点:无须遍历,只需获取到对象的哈希值做个简单的取余运算就可获取到其在对象数组中的下标。
默认初始容量16,散列因子0.75,达到0.75后自动扩容至原来的2倍
hashmap存储过程(具体结合下图过程查看源代码):
常用方法使用示例:
//hashmap
HashMap<String,String> hMap=new HashMap<>();
//存储
hMap.put("2018","等你下课");
hMap.put("2019","说好不哭");
hMap.put("2020","Mojito");
//获取值
String name=hMap.get("2018");
System.out.println(name);
//遍历(先获取键)
Set<String> hSet=hMap.keySet();
for (String str:hSet) {
System.out.println("key:"+str+" value:"+hMap.get(str));
}
//直接获取值进行遍历
Collection<String> hValue=hMap.values();
for (String ss:hValue) {
System.out.println("value:"+ss);
}
对应结果如下:
其他集合hashmap,hashtable,Concurrenthashmap等用法类似不作详解,列举以上三者区别:
hashmap:效率高,线程不安全,没有存储顺序
hashtable:排队(整个集合排队),效率低,线程安全
Concurrenthashmap:分段锁机制(操作同一个值的时候排队),保证线程安全,同时效率较高
Treemap:有序
补充:散列因子(负载因子)
过下:浪费空间
过大:效率低