集合&数据结构

本文深入解析Java集合框架,包括迭代器、泛型、各种集合类型的特性及应用,如List、Set、Queue、Stack等,以及它们之间的区别和联系。特别对比了ArrayList与LinkedList的效率,探讨了树状结构如二叉树的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

E E E 表示集合的元素类型 T T T表示任意类型

K K K V V V 分别表示表的关键字和值的类型 < S t r i n g String String / I n t e g e r Integer Integer /引用类型>

泛型相当于一个参数,泛型在使用的时候,就是将类型作为一个参数(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();  //也可以不写泛型
Epeek() 获取但不移除此队列的头;如果此队列为空,则返回 null
Epoll() 获取并移除此队列的头,如果此队列为空,则返回 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);
    }
有哪些类型是可以比较的?

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值