集合&数据结构

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.泛型

EE 表示集合的元素类型 TT表示任意类型

KK VV 分别表示表的关键字和值的类型 <StringString /IntegerInteger /引用类型>

泛型相当于一个参数,泛型在使用的时候,就是将类型作为一个参数(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 带有线程同步锁 ???? 安全但是效率低 (但是优先考虑效率)

ListArrayList 几乎一样

LinkedList 是一个双向链表(头first 尾last)

List本身是一个有序集合,允许集合中出现重复元素

List 在Collection 的基础上多了 增删改查index相关的方法

方法(和index相关) 作用
add(index,obj)
remove(index)
get(index)
addAll(index,Collection) 添加另一个集合
set(index,obj)

使用 .subList 后切割出来的子集合和父集合共用一个空间

测试 ArrayList 和 LinkedList 的效率

在测试了 addget 后认为使用 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

  1. 不允许重复,equals方法判断是否重复
  2. 内存的存储位置,由hashCode值决定

存储过程:

  1. 调用自身的hashCode方法计算存储位置

  2. 如果位置上没有元素,直接存入

  3. 如果位置上有元素,再调用自身的equals方法和该位置上的元素比较

  4. 如果比较不一致,另计算位置

  5. 如果比较一致,不存入

    需要同时重写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存储过程:

  1. 和根节点比较 - 通过compareTo方法比较
  2. 如果比根节点大,存在右子树中 (反之同理)
  3. 如果 == 根节点,则不存储
@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);
    }

有哪些类型是可以比较的?

集合&数据结构