集合&数据结构
文章目录
1. 迭代器
Iterator - 普通迭代器
Iterator
本身就是集合的一个方法,直接使用.iterator
使用即可
ConcurrentModificationException
- 隐含风险
如果要迭代删除每一个元素,必须使用迭代器的删除方法
Iterator it = col.iterator(); //完整版的迭代器
while (it.hasNext()) {
System.out.println("有下一个");
Object obj = it.next();
System.out.println(obj);
it.remove();
}
foreach - 简化版迭代器
foreach
是一个[简化版的迭代器]
只有遍历访问的功能,不能删除集合中的元素
foreach
也可以用于数组中,用来遍历数组
//foreach 是一个[简化版的迭代器] ---只有遍历访问的功能,不能删除集合中的元素
//col 是要迭代的集合 obj是每取出来一个元素,赋值给obj
for (Object obj : col) {
System.out.println(obj);
}
2. 集合&数组
集合转化为数组
使用 .toArray
将集合转化为数组
数组转化为集合
数组转化为集合,使用 Arrays
来调用方法
String[] ss = {"tom","jack","tim"};
Collection col = Arrays.asList(ss); //返回的是一个List
System.out.println(col);
Collection c = new ArrayList(col);//利用集合来创建一个ArrayList对象
c.add("nice");
System.out.println(c);
在改变数组元素的时候,集合元素也会同时改变,说明生成的集合和数组是共用空间
3.泛型
表示集合的元素类型 表示任意类型
分别表示表的关键字和值的类型 < / /引用类型>
泛型相当于一个参数,泛型在使用的时候,就是将类型作为一个参数(type parameters)
类型参数的作用:使得程序具有更好的可读性和安全性
Iterator<String> it = col.iterator();
在使用迭代器的时候,也是String类型,不需要强转
在泛型状态下,将集合转为数组:
Collection<String> col = new ArrayList<>(); //在JDK7+版本后,构造函数可以省略泛型类型
col.add("nice");
col.add("ka");
col.add("bob");
col.add("ni");
String[] ss = col.toArray(new String[0]); //确定类型,给一个空数组就行
System.out.println(Arrays.toString(ss));
4. 集合类型
强调:子类一定比父类的功能更强大,子类能够继承父类功能的基础上,增加功能
1. List - 有序集合
List
包含 ArrayList
LinkedList
Vector
三种类型
Vector
带有线程同步锁 ???? 安全但是效率低 (但是优先考虑效率)
List
和ArrayList
几乎一样
LinkedList
是一个双向链表(头first
尾last
)
List
本身是一个有序集合,允许集合中出现重复元素
List 在Collection 的基础上多了 增删改查 和 index相关的方法
方法(和index相关) | 作用 |
---|---|
add(index,obj) |
增 |
remove(index) |
删 |
get(index) |
查 |
addAll(index,Collection) |
添加另一个集合 |
set(index,obj) |
改 |
使用 .subList
后切割出来的子集合和父集合共用一个空间
测试 ArrayList 和 LinkedList 的效率
在测试了 add
和 get
后认为使用 ArrayList
更好 (综合考虑了插入和查找的效率之后) ????
结论:使用ArrayList
就完事了
ArrayList<String> arr = new ArrayList<>();
LinkedList<String> linked = new LinkedList<>();
//构造数组
for (int i = 0; i < 500000; i++) {
arr.add("i"+i);
linked.add("i"+i);
}
long time1 = System.currentTimeMillis();
//从头查询效率
arr.get(10);
long time2 = System.currentTimeMillis();
linked.get(10);
long time3 = System.currentTimeMillis();
System.out.println("arr from head"+(time2 - time1));
System.out.println("linked from head"+(time3 - time2));
//从中间查询效率
arr.get(250000);
long time4 = System.currentTimeMillis();
linked.get(250000);
long time5 = System.currentTimeMillis();
System.out.println("arr from mid"+(time4 - time3));
System.out.println("linked from mid"+(time5 - time4));
//从尾部查询效率
arr.get(490000);
long time6 = System.currentTimeMillis();
linked.get(490000);
long time7 = System.currentTimeMillis();
System.out.println("arr from tail"+(time6 - time5));
System.out.println("linked from tail"+(time7 - time6));
2. Set - 无序集合
Set属于Map集合
3. 队列 - Queue
队列是一种先进先出(FIFO)的数据结构
队列只有顺序,没有标号
Queue<Integer> queue = new LinkedList<>();
queue.offer(1); //当使用有容量限制的队列时,此方法通常要优于 add(E)
Queue queue = new LinkedList(); //也可以不写泛型
E |
peek() 获取但不移除此队列的头;如果此队列为空,则返回 null 。 |
---|---|
E |
poll() 获取并移除此队列的头,如果此队列为空,则返回 null 。 |
Deque - 双端队列
一个线性 collection,支持在两端插入和移除元素。
大多数 Deque
实现对于它们能够包含的元素数没有固定限制,但此接口既支持有容量限制的双端队列,也支持没有固定大小限制的双端队列。
Deque<String> dq = new LinkedList<>();
dq.offerFirst("dog");
dq.offerFirst("cat");
dq.offerLast("bob");
dq.offerLast("dick");
System.out.println(dq);
//[cat, dog, bob, dick]
System.out.println(dq.peekFirst()); //从左边取
System.out.println(dq.peekLast()); //从右边取
4. 栈 - Stack
栈是一种先进后出(FILO)的数据结构
可以用Deque来实现栈的所有功能
用链表的方式来实现栈
//用链表的方式实现栈
public class StackDemo {
private Node head = new Node();
private class Node {
Object data;
Node next;
}
public void push(Object obj) {
Node newNode = new Node();
newNode.data = obj;
if (head.next != null) {
newNode.next = head.next;
}
head.next = newNode;
}
public Object pop() {
//出栈先判空
//1.为空的时候
if(head.next == null){
return null;
//或者在这里使用抛出异常
}
//2.不空的时候
Node node = head.next; //暂存
head.next= head.next.next;
return head.next.data;
}
区分 peek poll push pop
5. HashSet
- 不允许重复,equals方法判断是否重复
- 内存的存储位置,由hashCode值决定
存储过程:
-
调用自身的hashCode方法计算存储位置
-
如果位置上没有元素,直接存入
-
如果位置上有元素,再调用自身的equals方法和该位置上的元素比较
-
如果比较不一致,另计算位置
-
如果比较一致,不存入
需要同时重写equals 和 hashCode方法
6. 树状结构 - 二叉树
TreeSet 用的是二叉树的中序遍历
程序员基本使用中序遍历就可以了 ????????
Set<Integer> set = new TreeSet<>();
set.add(1);
set.add(3);
set.add(-1);
set.add(-19);
set.add(20);
System.out.println(set);
比较按照从小到大输出,String类型则是按照ASCII码表顺序
Tree存储过程:
- 和根节点比较 - 通过compareTo方法比较
- 如果比根节点大,存在右子树中 (反之同理)
- 如果 == 根节点,则不存储
@Override //优先比较Age,之后比较Name
public int compareTo(User u) {
//比较规则 this 比u小,返回负数
//比较规则 this 比u大,返回正数
//比较规则 this 和u一样大,返回0
if (this.age != u.age){
return this.age - u.age;
}else {
return u.name.compareTo(this.name);
}