集合
数据的容器,都在java.util
数组:元素是固定的,动态扩容麻烦
集合:对数据结构的实现
常见的数据结构:
栈、队列、数组、链表、红黑树
栈:Stack 线性表, ** 先进后出。 压栈进栈push(存),出栈弹栈pop(取)
队列:queue线性表 先进先出
数组:查找元素快, 增删慢因为要移动
链表:linked list 查找元素慢,增删快
红黑树(平衡二叉树):binary tree 二叉树(有序)
类集中最大的几个操作接口:Colletion、Map、Iterator
1、单值存储:Collection
2、双值存储:Map
3、迭代器:Iterator
-
(数组扩容,很慢,占内存)
-
(数组不利于删除,因为要挪位子。查容易)
链表
单向链表示意:(内存不一定相连,数组的内存是相连的)
- 插入删除都很快(因为内存不连续,所以不能和数组一样挪位子)
不用挪
链表类型
Collection
开发中,一般使用子接口,List(允许重复元素)和Set(不允许重复元素)
List 接口
List接口内容是允许重复的。
实现类:ArrayList(线程不安全) ,Vector(线程安全)←【动态数组,扩容】,
【链表】→LinkList()
子类:ArrayList
优点,增加删除慢,查找快
ArrayList<类型(包装类)> 名字 = new ArrayList();
构造方法:
ArrayList()无参构造: 构建一个初始容量为10的空列表
ArrayList(int x) 构建一个初始容量为x的空列表
ArrayList(Collection<? extends E> c) 按照集合的迭代器返回的顺序构造一个包含指定集合 的元素列表
ArrayList<Integer> data = new ArrayList();
data.add(100);
// 因为是创建空列表(其实,起始长度为0.因为调用add方法,add发现内存不够,所以进行扩容。)
//调用扩容方法grow(),
//增加长度 = 旧长度往右移以为 eg1010(10) 移以为 = 101(5)(相当于加了0.5倍)
//因为每次扩容为0.5倍,所以注意ArrayList范围,一直扩容会浪费内存。
//新长度 = 旧长度+增加长度
//第一次增加时,会进行选择max(默认长度,新长度),其中默认长度=10
//容器最大为Int的最大范围
-
ArrayList 方法
Vector
- vector是同步的,如果不需要线程安全实现,建议使用ArrayList替代Vector
- Vector可以指定每次扩容的数量,(ArrayList的是0.5倍)
Vector<Integer> data = new Vector<>();
构造方法
Vector() 构造一个空向量,使其内部数据数组大小为10,其标准容量增量为0
Vector(int x) 构造一个具有指定初始容量且容量增量等于0的空向量
Vector(int x,int y) 构造具有指定初始容量x和容量增量y的空向量
Vector(Collection<? extends E> c)
如果容量增量>0,则扩容是加容量增量
如果容量增量<0,则扩容是加旧长度
方法和ArrayList差不多
add() , remove() , size(), get()
LinkedList(用的少)
使用双向链表结构,对于增删快,查找慢(和ArrayList相反)
LinkedList<Integer> data = new LinkedList<>();
data.addFirst(100);//往首部添加
data.addLast(300);//往尾部添加
data.removeFirst();
data.push(200);//往首部添加,模拟栈
Iterator迭代器
ArrayList<Integer> data =new ArrayList<>();
data.add(1);
data.add(2);
data.add(3);
data.add(4);
data.add(5);
方法
hasNext(); //判断next指针有没有下一个
next(); //将next指针往下移一位
remove(); //删除当前next指针指的位置的数据(在起始位置删不掉)
Iterator<Integer> iterator = data.iterator();
while(tierator.hasNext()){
//hasNext是判断有无下一个,而不是移动。
Integer i = iterator.next(); //获取这个next指针指的数据
System.out.println(i); //打印i
}
ListIterator(Iterator的子类)
ListIterator<Integer> listIterator = new ListIterator<>();
listIterator.add(100); //添加会添加在当前next指针的位置,其他往下挪
listIterator.next(); //next往下移动
listIterator.next();
listIterator.set(200); //next往下移动两次。将这个next设置为200
listIterator.previous(); //listIterator的Next指针往上移动
listIterator.previous();
listIterator.previous(); //移动三次是因为这个add添加在首部了
while(listIterator.hasNext()){
System.out.println(listIterator.next());
}
//结果 100,1,200,3,4,5
for each (增强for)
- 用于迭代数组,集合(Collection)
-
- 语法:
- for(数据类型 变量名:集合或者数组名){}
-
- 变量名 = 集合或者数组的数据
int [] arr = {6,5,4,3,2,1};
for(int data:arr){
System.out.println(data);
}
ArrayList<String> data = new ArrayList<>();
data.add("abc");
data.add("bcd");
for(String s : data){
System.out.println(s);
}
Set集合(继承Collection接口)
- 不允许重复(包括null也只能存在一个)
- 无get方法,如果想要get
-
- 1、iterator进行迭代
- 2、用toArray(),转成数组
HashSet子类
-
HashSet:散列存放,不能保证顺序(内部是哈希表HashMap)
HashSet<String> set = new HashSet<>(); set.add("123") //返回boolean //底层: add(E e){ return map.put(e,PRESENT(这个是固定的常量))==null //把双指的map,一个值给固定死 }
HashSet<String> set = new HashSet<>(); set.add("123"); set.add("234"); //如果add内容重复的,会反回false,存储失败,而不是覆盖 //打印 Iterator<String> iterator = set.iterator(); while(iterator.hasNext()){ sout(iterator.next()); } for(String s:set){ sout(e); } // 输出的结果不一定是 123 234 .因为是无须的 ,可能是234 123
TreeSet(二叉树存储,基于TreeMap)
-
有顺序存储
TreeSet<String> data = new TreeSet<>(); data.add("B"); data.add("D"); data.add("C"); data.add("A"); for(String a:data){ sout(a); } //结果:A B C D //==有序是按asc2码的顺序==
-
如果不是asc2表的数据,比如自己的类和对象(Person类)
-
Person p1 = new Person("张三",18); Person p1 = new Person("张三",19); Person p1 = new Person("里斯",18); data.add(p1); data.add(p2); data.add(p3); // 这样编译器不知道那个顺序在前,那个在后 // 要重写这个比较的方法 // 如果发现两个一样大,两个18.那么里斯不存,因为是Set不允许重复
class Person implements Comparable<Person(拿person和person比)>{ private String name; private int age; @ 抽象方法 public int comparaTo(Person o){ //this和o比较,反回正数(this>o) 0(相等) 负数 if(this.age>o.age){ return 1; }else if(this.age=o.age){ return 0; } return -1; } }
-
Map(Mapping映射)
- HashMap ,TreeMap
- Map集合存储的是一个个键值对 键→值
- Map集合的键(key)不可重复
Map<int,String> data = new Map<>();
data.put(1,"你好"); // boolean型
data.put(1,"您好");
// 系统会把key = 1 的位置给替换,并且反回false,打印数据(1,"你好");
// 如果key没有存在,则put方法返回null,并且不打印
// 同理,remove方法也是,删除并取出(get方法,单纯取出)
// replace ,如果有key存在,替换值
// equals 判断key
哈希表概述
- HashMap 是基于哈希表的Map接口实现 ------ 数据结构: 哈希表
- 哈希表: 对象数组+链表(链表长度到达一定长度(8个)<==>(6个) 变成 红黑二叉树)
- HashCode 哈希码值。 优点,找值的时候,根据哈希值就可以直接找到下标。
- 默认数组长度16 , 散列因子默认0.75 (如果75%的桶已经存储数据了,对数组扩大一倍)
HashMap
- HashMap
- Hashtable(输出顺序不一样,后入先输出)
- ConcurrentHashMap (导包不同)
- TreeMap(需要接口)
- LinkedHashMap
- 16 = 1<<4 (1左移4位 1 → 10000)
HashMap 工作流程
HashMap<String,String> data = new HashMap<>();
data.put("键key1","内容value");
String value = data.get("键key1"); //value = 内容value
// 遍历
Set<String> set = data.keySet(); // 获取key集合
for(String key: set){
sout("key = " + key );
sout("value= " + data.get(key));
}
// 遍历2
Collection<String> values = data.values();
for(String value: values){
sout(value);
}
-iRNqIush-1621652386814)]
HashMap<String,String> data = new HashMap<>();
data.put("键key1","内容value");
String value = data.get("键key1"); //value = 内容value
// 遍历
Set<String> set = data.keySet(); // 获取key集合
for(String key: set){
sout("key = " + key );
sout("value= " + data.get(key));
}
// 遍历2
Collection<String> values = data.values();
for(String value: values){
sout(value);
}