java基础-集合-day14

1. 数据结构 算法

算法:解决问题的步骤
例如 1+2+3+...+100
50*(1+100)=5050
算法优劣的度量:时间复杂度 空间复杂度

数据结构:
计算机中如何高效的管理数据

逻辑结构:
思想层面的数据存放编排结构

物理结构:
计算机内存或者硬盘上具体的存放逻辑

以线性表这个逻辑结构来举例:两种物理结构(实现方式)

  1. 紧密结构

线性表逻辑结构,对应的真实结构如果是跳转结构---》典型就是 链表:
优点:删除元素,插入元素效率高
缺点:查询元素效率低

可以 通过第一个索引的位置计算出其他的元素索引位置

  1. 链式结构 --跳转结构
    单项链表 双向链表 循环链表 具体的可以baidu

2. 本章的重点 集合

集合:存放数据 组织数据的容器
增提分成2大阵营:一个一个存储 一对一对的存储

3. collections

    Collection接口的常用方法:
    增加:add(E e) addAll(Collection<? extends E> c)
    删除:clear() remove(Object o)
    修改:
    查看:iterator() size()
    判断:contains(Object o)  equals(Object o) isEmpty()
package com.msb.coll01;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 9:41
 * @Description: com.msb.coll01
 * @version: 1.0
 */
public class Test01 {
    public static void main(String[] args) {
        Collection col = new ArrayList();
        col.add(18);
        col.add(12);
        col.add(11);
        col.add(17);
        System.out.println(col);

        List li = Arrays.asList(new Integer[]{1, 2, 3, 4});
        col.addAll(li);
        System.out.println(col);

        //col.clear();

        System.out.println(col.size());
        System.out.println(col.isEmpty());

        boolean isRemove = col.remove(12);
        System.out.println(col);
        System.out.println(isRemove);

        Collection col1 = new ArrayList();
        col1.add(18);
        col1.add(12);
        col1.add(11);
        col1.add(17);

        Collection col2 = new ArrayList();
        col2.add(18);
        col2.add(12);
        col2.add(11);
        col2.add(17);

        System.out.println(col2.equals(col1));
        System.out.println(col2.contains(12));
    }
}

遍历:
1.普通for
2. 增强for
3. iter
迭代器的原理:

hasNext 则执行next方法
next方法:获取当前的元素 并将“指针”下移

package com.msb.coll01;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 9:48
 * @Description: com.msb.coll01
 * @version: 1.0
 */
public class Test02 {
    public static void main(String[] args) {
        Collection col = new ArrayList();
        col.add(18);
        col.add(12);
        col.add(11);
        col.add(17);
        col.add("abc");
        col.add(9.8);

        // 1.
//        for (int i = 0; i < col.size(); i++) {
//            System.out.println(col.);;
//        }

        // 2.
        for (Object o : col) {
            System.out.println(o);
        }

        //3.
        Iterator it = col.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

    }
}

4. list

List接口中常用方法:
增加:add(int index, E element)
删除:remove(int index) remove(Object o)
修改:set(int index, E element)
查看:get(int index)
判断:

package com.msb.coll01;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 9:59
 * @Description: com.msb.coll01
 * @version: 1.0
 */
public class TesList01 {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add(13);
        list.add(17);
        list.add(-1);
        list.add(2);
        list.add("abc");
        System.out.println(list);

        list.add(3, 66);//插入数据
        System.out.println(list);

        //list.remove(0);//index 0位置移除元素
        System.out.println(list);

        System.out.println(list.get(0));

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

        for (Object o : list) {
            System.out.println(o);
        }

        Iterator it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }
    }
}

ArrayList源码分析
transient Object[] elementData 存放数据
private int size; 当前有效数据的个数

容量扩容 确保能放下原色

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // Increments modCount!!
        elementData[size++] = e;
        return true;
    }

初始开辟的是10个
int newCapacity = oldCapacity + (oldCapacity >> 1);
容量不够进行扩容 新的容量是原来的1.5倍数
oldCapacity >> 1 右移动一位 相当于 除以2

jdk1.8之后
elementData 的初始赋值是空的ArrayList 只有add数据之后才会第一次扩容为10

5. 泛型

【1】什么是泛型(Generic):
泛型就相当于标签
形式:<>
集合容器类在设计阶段/声明阶段不能确定这个容器到底实际存的是什么类型的对象,所以在JDK1.5之前只能把元素类型设计为Object,
JDK1.5之 后使用泛型来解决。因为这个时候除了元素的类型不确定,其他的部分是确定的,例如关于这个元素如何保存,如何管理等是确定的,因此此时把元素的类型设计成一个参数,这个类型参数叫做泛型。
Collection, List, ArrayList 这个就是类型参数,即泛型。
元素的类型设计成一个参数,这个类型参数叫做泛型。

/创建一个ArrayList集合,向这个集合中存入学生的成绩:
//加入泛型的优点:在编译时期就会对类型进行检查,不是泛型对应的类型就不可以添加入这个集合。

package com.msb.generic01;

import java.util.ArrayList;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 10:37
 * @Description: com.msb.generic01
 * @version: 1.0
 */
public class Test01 {
    public static void main(String[] args) {
        ArrayList<Integer> al = new ArrayList<>();
        al.add(98);
        al.add(92);
        al.add(78);
//        al.add("lili");
        for (Integer i : al) {
            System.out.println(i);
        }
    }
}

泛型:<>里面传递的参数 是这个对象的类型 使用的时候才会确定
注意:泛型的类型:都是引用数据类型,不能是基本数据类型

  • GenericTest 就是一个泛型类
  • <>里面就是一个参数类型,但是这个类型是什么呢?这个类型现在是不确定的,相当于一个占位
  • 但是现在确定的是这个类型一定是一个引用数据类型,而不是基本数据类型
package com.msb.generic01;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 10:41
 * @Description: com.msb.generic01
 * @version: 1.0
 */
public class GenericTest<E> {

    int age;
    String name;
    E sex;

    public void a(E n){

    }

    public void b(E[] m){

    }
}

泛型类

package com.msb.generic01;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 10:41
 * @Description: com.msb.generic01
 * @version: 1.0
 */
public class GenericTest<E> {

    int age;
    String name;
    E sex;

    public void a(E n){

    }

    public void b(E[] m){

    }
}


class Test{


    public static void main(String[] args) {
        //实例化的时候不指定泛型
        GenericTest gt1 = new GenericTest();
        gt1.a("abc");
        gt1.a(17);
        gt1.a(3.14);
        gt1.b(new String[] {"a", "b", "c"});

        //指定泛型
        GenericTest<String> gt2 = new GenericTest<>();
        gt2.sex = "男";
        gt2.a("abc");
        gt2.b(new String[]{"abc", "123"});

    }
}

泛型方法:

  • 1.什么是泛型方法:
  • 不是带泛型的方法就是泛型方法
  • 泛型方法有要求:这个方法的泛型的参数类型要和当前的类的泛型无关
  • 换个角度:
  • 泛型方法对应的那个泛型参数类型 和 当前所在的这个类 是否是泛型类,泛型是啥 无关
  • 2.泛型方法定义的时候,前面要加上
  • 原因:如果不加的话,会把T当做一种数据类型,然而代码中没有T类型那么就会报错
    
  • 3.T的类型是在调用方法的时候确定的
package com.msb.generic01;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 10:48
 * @Description: com.msb.generic01
 * @version: 1.0
 */
public class GenericTest02<E> {

    public void a(E e){}//不是泛型方法

    public static <T> void b(T t){}//是泛型方法 注意<T>的位置
}

class Demo{
    public static void main(String[] args) {
        GenericTest02<String> gt = new GenericTest02<>();
        
        gt.a("abc");
        //gt.a(123);// 不可以
        //b方法的泛型
        gt.b(19);
        gt.b("abc");
        gt.b(true);
    }
}

6. 泛型通配符

package com.msb.generic01;

import java.util.ArrayList;
import java.util.List;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 11:02
 * @Description: com.msb.generic01
 * @version: 1.0
 */
public class Test02 {
    public static void main(String[] args) {
        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<Integer> list3 = new ArrayList<>();

        List<?> li = null;//?泛型通配符
        li = list1;
        li = list2;
        li = list3;
    }
}

方法里面使用泛型通配符

package com.msb.generic01;

import java.util.List;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 11:04
 * @Description: com.msb.generic01
 * @version: 1.0
 */
public class Test03 {
//    public void a(List<Object> li){
//
//    }
//
//    public void a(List<String> li){
//
//    }

    public void a(List<?> li){

        for (Object o : li) {
            System.out.println(o);
        }
    }


}

使用

class T{

    public static void main(String[] args) {
        Test03 t = new Test03();
        ArrayList<Integer> arr1 = new ArrayList<Integer>();
        arr1.add(1);
        arr1.add(12);
        arr1.add(123);
        t.a(arr1);
        t.a(new ArrayList<StringList>());
        t.a(new ArrayList<ObjectList>());
    }


}

泛型受限

package com.msb.generic02;

import java.util.ArrayList;
import java.util.List;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 11:14
 * @Description: com.msb.generic02
 * @version: 1.0
 */
public class Test {
    public static void main(String[] args) {
        List<Object> a = new ArrayList<>();
        List<Person> b = new ArrayList<>();
        List<Student> c = new ArrayList<>();

        List<? extends Person> list1 = null;//指定 ?必须是继承Person 相当于?的上限是Person

//        list1 = a;
        list1 = b;
        list1 = c;

        List<? super Person> list2 = null;//下限是Person Person之上的才可以
        list2 = a;
        list2 = b;
//        list2 = c;

    }
}

7. linkedList

    LinkedList常用方法:
    增加 addFirst(E e) addLast(E e)
         offer(E e) offerFirst(E e) offerLast(E e)
    删除 poll()
        pollFirst() pollLast()  ---》JDK1.6以后新出的方法,提高了代码的健壮性
        removeFirst() removeLast()
    修改
    查看 element()
         getFirst()  getLast()
         indexOf(Object o)   lastIndexOf(Object o)
         peek()
         peekFirst() peekLast()
    判断
package com.msb.linkedtest01;

import java.util.Iterator;
import java.util.LinkedList;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 11:24
 * @Description: com.msb.linkedtest01
 * @version: 1.0
 */
public class Test01 {
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        list.add("fff");

        list.addFirst("ggg");
        list.addLast("hh");

        list.offer("kk");//添加元素在尾端
        list.offerFirst("pp");
        list.offerLast("rr");

        System.out.println(list);

        System.out.println(list.poll());//删除头上的元素并且将元素输出
        list.pollFirst();
        list.pollLast();

        list.removeFirst();
        list.removeLast();
        list.remove();


        System.out.println(list);

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));

        }

        for (String s : list) {
            System.out.println(s);
        }

        Iterator<String> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

        for(Iterator<String> it1 = list.iterator();it1.hasNext();){
            System.out.println(it1.next());//节省内存
        }


    }
}

8. 模拟linkedList源码 --面试重点

package com.msb.linkedtest01;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 11:35
 * @Description: com.msb.linkedtest01
 * @version: 1.0
 */
public class MyLinkedList {
    Node first;
    Node last;
    int count;

    public MyLinkedList() {
    }

    public void add(Object o){
        if(first==null){
            Node n = new Node(null, null, o);
            first = n;
            last = n;
        }else {
            Node n = new Node(last, null, o);
            last.setNext(n);
            last = n;
        }
        count ++;

    }

    public int getSize(){
        return count;

    }

    public Object get(int index){
        Node n = first;
        for (int i = 0; i < index; i++) {
            n = n.getNext();

        }
        return n.getObj();

    }
}

class T{
    public static void main(String[] args) {
        MyLinkedList ml = new MyLinkedList();
        ml.add("aa");
        ml.add("bb");
        ml.add("cc");

        System.out.println(ml.getSize());
        System.out.println(ml.get(1));
        
    }
}

源码的实现:

package com.msb.linkedtest01;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 14:30
 * @Description: com.msb.linkedtest01
 * @version: 1.0
 */
public class JackLinkList<E> {
    transient int size = 0;
    private static class Node<E>{
        E item;
        Node<E> next;
        Node<E> prev;

        public Node(Node<E> prev, E item, Node<E> next) {
            this.item = item;
            this.next = next;
            this.prev = prev;
        }
    }

    transient Node<E> first;//链表的首节点
    transient Node<E> last;//链表的尾节点

    public JackLinkList() {
    }

    public boolean add(E e){
        linkLast(e);
        return true;
    }
    public int size(){
        return size;
    }

    //追加元素
    void linkLast(E e){
        final Node<E> l = last;
        final Node<E> newNode = new Node<E>(l, e, null);
        last = newNode;
        if(l==null){
            first = newNode;//如果是第一个被添加的元素 first指向该节点即可
        }else{
            l.next = newNode;//如果不是新节点 last的next指向新节点即可
        }
        size++;
    }
    public E get(int index){
        return node(index).item;
    }

    //通过index获取元素
    Node<E> node(int index){
        if(index<(size>>1)){
            Node<E> x = first;
            for (int i = 0; i < index; i++) {
                x = x.next;

            }
            return x;
        }else{
            Node<E> x = last;
            for (int i = size-1; i >index ; i--) {
                x = x.prev;
            }
            return x;

        }
    }
}


class T1{
    public static void main(String[] args) {
        JackLinkList<String> ml = new JackLinkList<>();
        ml.add("aa");
        ml.add("bb");
        ml.add("cc");

        System.out.println(ml.size());
        System.out.println(ml.get(1));

    }
}

这里面用到了 二分法 从前遍历 从后遍历

9. Iterrable

package com.msb.linkedtest01;

import java.util.Iterator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:00
 * @Description: com.msb.linkedtest01
 * @version: 1.0
 */
public class MyArrayList<E> {
    transient Object[] elementData;
    private int size;

    private class Itr implements Iterator<E>{
        int cursor;
        int lastRet = 1;
        @Override
        public boolean hasNext() {
            return cursor != size;//只要不相等 都返回true
        }

        @Override
        public E next() {
            int i = cursor;
            cursor = i + 1;
            Object[] elementData = MyArrayList.this.elementData;
            return (E)elementData[lastRet=i];
        }
    }
}

package com.msb.linkedtest01.com;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:08
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class msb01 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        list.add("eeee");

        Iterator<String> it = list.iterator();//调用迭代方法得到迭代对象
        while (it.hasNext()){
            if("ccc".equals(it.next())){
                //System.out.println(it.next());
                list.add("ffff");
            }

        }

    }
}


一边迭代 一边 改变集合对象 则会报错

解决办法iterator方法改成 listIterator方法

package com.msb.linkedtest01.com;

import java.util.ArrayList;
import java.util.ListIterator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:08
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class msb01 {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("aaa");
        list.add("bbb");
        list.add("ccc");
        list.add("ddd");
        list.add("eeee");

        ListIterator<String> it = list.listIterator();//调用迭代方法得到迭代对象
        while (it.hasNext()){
            if("ccc".equals(it.next())){
                //System.out.println(it.next());
                it.add("ffff");//这里也需要换成it
            }

        }

        System.out.println(it.hasNext());
        System.out.println(it.hasPrevious());

        while (it.hasPrevious()){
            System.out.println(it.previous());
        }

        while (it.hasNext())
            System.out.println(it.next(
            ));
        System.out.println(list);
    }
}

10. HashSet

唯一 无序

package com.msb.linkedtest01.com;

import java.util.HashSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:34
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class TestSet01 {
    public static void main(String[] args) {
        HashSet<String> hs = new HashSet<>();
        hs.add("hello");
        hs.add("apple");
        hs.add("banana");
        hs.add("html");
        hs.add("apple");
        hs.add("css");
        System.out.println(hs.size());
        System.out.println(hs);
    }
}

package com.msb.linkedtest01.com;

import java.util.HashSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:35
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class TestSet02 {

    public static void main(String[] args) {
        HashSet<Integer> hs = new HashSet<>();
        System.out.println(hs.add(19));
        hs.add(5);
        hs.add(20);
        System.out.println(hs.add(19));
        hs.add(41);
        hs.add(0);
        System.out.println(hs.size());
        System.out.println(hs);
    }
}

package com.msb.linkedtest01.com;

import java.util.HashSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:39
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class TestSet03 {
    public static void main(String[] args) {
        HashSet<Person> hs = new HashSet<>();
        hs.add(new Person(19, "lili"));
        hs.add(new Person(20, "lilu"));
        hs.add(new Person(18, "feifei"));
        hs.add(new Person(19, "lili"));
        hs.add(new Person(20, "nana"));

        System.out.println(hs.size());//5
        System.out.println(hs);

    }

}

11. LinkedHashSet

package com.msb.linkedtest01.com;

import java.util.LinkedHashSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:47
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class TestSet04 {
    public static void main(String[] args) {
        LinkedHashSet<Integer> hs = new LinkedHashSet<>();
        hs.add(5);
        hs.add(20);
        System.out.println(hs.add(19));
        hs.add(51);
        hs.add(0);
        System.out.println(hs.add(19)); //false 第二次放入 19 失败

        System.out.println(hs.size());
        System.out.println(hs);//[5, 20, 19, 51, 0] 唯一 有序

    }

}

比较器 的使用
a - b > 0 --> a>b

package com.msb.linkedtest01.com;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:51
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class Test04 {
    public static void main(String[] args) {
        double d1 = 3.15;
        double d2 = 4.9;
        int bol1 = ((Double) d1).compareTo((Double) d2);// -1  d1<d2
        System.out.println(bol1);
    }
}

package com.msb.linkedtest01.com;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 15:37
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class Person implements Comparable<Person> {
    int age;
    String name;
    double height;

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }

    @Override
    public int compareTo( Person p) {

//        // 按照年龄
//        return this.age - p.age;

//        // 按照身高
//        return ((Double)(this.height)).compareTo((Double)(p.height));
        
        // 按照名字
        return (this.name).compareTo(p.name);
    }
}

package com.msb.linkedtest01.com;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:00
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class TestCompare01 {
    public static void main(String[] args) {
        Person p1 = new Person(14, "alili", 188.0);
        Person p2 = new Person(15, "blili", 178.0);
        System.out.println(p1.compareTo(p2));
    }

}

外部比较器

package com.msb.linkedtest01.com;

import java.util.Comparator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:04
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class BiJiao01 implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.name.compareTo(o2.name);
    }
}

package com.msb.linkedtest01.com;

import java.util.Comparator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:06
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class Bijiao02 implements Comparator<Person> {

    @Override
    public int compare(Person o1, Person o2) {
        return o1.age - o2.age;
    }
}

package com.msb.linkedtest01.com;

import java.util.Comparator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:08
 * @Description: com.msb.linkedtest01.com
 * @version: 1.0
 */
public class TestComparator {
    public static void main(String[] args) {
        Person p1 = new Person(14, "alili", 188.0);
        Person p2 = new Person(15, "blili", 178.0);

        Comparator comparator1 = new BiJiao01();//名字
        System.out.println(comparator1.compare(p1, p2));

        Comparator comparator2 = new Bijiao02();// age
        System.out.println(comparator2.compare(p1, p2));
    }
}

建议使用外部比较器 多态实现不同方式的比较

12. TreeSet

package com.msb.treeset01;

import java.util.TreeSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:33
 * @Description: com.msb.treeset01
 * @version: 1.0
 */
public class Test10 {
    public static void main(String[] args) {
        TreeSet<Integer> ts = new TreeSet<>();
        ts.add(12);
        ts.add(3);
        ts.add(7);
        ts.add(9);
        ts.add(3);
        ts.add(16);
        System.out.println(ts.size());
        System.out.println(ts);
    }
}

有序 且唯一

原理: 二叉树 --一种逻辑接口--思想 上的结构 --跳转结构

放入元素的时候:

  1. 比较 小的往左放 大的往右放 相同则不放
package com.msb.treeset01;

import java.util.TreeSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:41
 * @Description: com.msb.treeset01
 * @version: 1.0
 */
public class Test11 {
    public static void main(String[] args) {
        TreeSet<String> ts = new TreeSet<>();
        ts.add("elili");
        ts.add("blili");
        ts.add("alili");
        ts.add("elili");
        ts.add("clili");
        ts.add("flili");
        ts.add("glili");
        System.out.println(ts.size());
        System.out.println(ts);//[alili, blili, clili, elili, flili, glili]
    }
}



自定义类的比较

package com.msb.treeset01;

import java.util.TreeSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:46
 * @Description: com.msb.treeset01
 * @version: 1.0
 */
public class Test2 {
    public static void main(String[] args) {

        TreeSet<Person> ts = new TreeSet<>();
        ts.add(new Person(10, "elili"));
        ts.add(new Person(8, "blili"));
        ts.add(new Person(4, "alili"));
        ts.add(new Person(9, "elili"));
        ts.add(new Person(10, "flili"));
        ts.add(new Person(1, "dlili"));
        System.out.println(ts.size());
        System.out.println(ts);
//[Person{age=1, name='dlili'}, Person{age=4, name='alili'}, Person{age=8, name='blili'}, Person{age=9, name='elili'}, Person{age=10, name='elili'}]
    }
}

package com.msb.treeset01;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:43
 * @Description: com.msb.treeset01
 * @version: 1.0
 */
public class Person implements Comparable<Person> {
    private int age;
    private String name;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Person() {
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }

    @Override
    public int compareTo(Person o) {
        return this.getAge() - o.getAge();//根据年龄比较
    }

    @Override
    public String toString() {
        return "Person{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}

外部比较器

package com.msb.treeset01;

import java.util.Comparator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:49
 * @Description: com.msb.treeset01
 * @version: 1.0
 */
public class MyComparator01 implements Comparator<Person> {
    @Override
    public int compare(Person o1, Person o2) {
        return o1.getName().compareTo(o2.getName());
    }
}

package com.msb.treeset01;

import java.util.Comparator;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:50
 * @Description: com.msb.treeset01
 * @version: 1.0
 */
public class MyComparator02 implements Comparator<Person> {

    @Override
    public int compare(Person o1, Person o2) {
        return o1.getAge() - o2.getAge();
    }
}

package com.msb.treeset01;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:46
 * @Description: com.msb.treeset01
 * @version: 1.0
 */
public class Test12 {
    public static void main(String[] args) {

//        Comparator<Person> com1 = new MyComparator01();
        Comparator<Person> com2 = new MyComparator02();
        TreeSet<Person> ts = new TreeSet<>(com2);

        ts.add(new Person(10, "elili"));
        ts.add(new Person(8, "blili"));
        ts.add(new Person(4, "alili"));
        ts.add(new Person(9, "elili"));
        ts.add(new Person(10, "flili"));
        ts.add(new Person(1, "dlili"));
        System.out.println(ts.size());
        System.out.println(ts);
        // name 比较
        // [Person{age=4, name='alili'}, Person{age=8, name='blili'}, Person{age=1, name='dlili'}, Person{age=10, name='elili'}, Person{age=10, name='flili'}]

        // age 比较
        // [Person{age=1, name='dlili'}, Person{age=4, name='alili'}, Person{age=8, name='blili'}, Person{age=9, name='elili'}, Person{age=10, name='elili'}]
        
        
    }
}

使用匿名类

package com.msb.treeset01;

import java.util.Comparator;
import java.util.TreeSet;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 16:46
 * @Description: com.msb.treeset01
 * @version: 1.0
 */
public class Test13 {
    public static void main(String[] args) {


        TreeSet<Person> ts = new TreeSet<>(new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                return o1.getName().compareTo(o2.getName());
            }
        });

        ts.add(new Person(10, "elili"));
        ts.add(new Person(8, "blili"));
        ts.add(new Person(4, "alili"));
        ts.add(new Person(9, "elili"));
        ts.add(new Person(10, "flili"));
        ts.add(new Person(1, "dlili"));
        System.out.println(ts.size());
        System.out.println(ts);
        // name 比较
        // [Person{age=4, name='alili'}, Person{age=8, name='blili'}, Person{age=1, name='dlili'}, Person{age=10, name='elili'}, Person{age=10, name='flili'}]
        
    }
}


遍历方式
左 根 右
左 12 16
3 (7和9) 12 16
3 7(9) 12 16
3 7 12 16

13. map

基本接口:
增加:put(K key, V value)
删除:clear() remove(Object key)
修改:
查看:entrySet() get(Object key) keySet() size() values()
判断:containsKey(Object key) containsValue(Object value)
equals(Object o) isEmpty()

遍历有些特殊

package msb.com.map01;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 20:54
 * @Description: msb.com.map01
 * @version: 1.0
 */
public class Test01 {
    public static void main(String[] args) {

        Map<String, Integer> map = new HashMap<>();
        System.out.println(map.put("lili", 1010101));
        map.put("name", 123456);
        map.put("feifei", 23453456);

        System.out.println(map.put("lili", 34565677));

        System.out.println(map.size());
        System.out.println(map);


        System.out.println(map.containsKey("lili"));
        System.out.println(map.containsValue("34565677"));

        Set<String> set = map.keySet();
        for (String s : set) {
            System.out.println(s);
        }

        Collection<Integer> col = map.values();
        for (Integer integer : col) {
            System.out.println(integer);
        }
        // 遍历
        Set<String> set2 = map.keySet();
        for (String s : set2) {
            System.out.println(map.get(s));
        }

        Set<Map.Entry<String, Integer>> entries = map.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            System.out.println(entry.getKey()+"-----"+entry.getValue());
        }

    }
}

14 TreeMap

内部比较器

package msb.com.map01;

import java.util.Objects;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 21:04
 * @Description: msb.com.map01
 * @version: 1.0
 */
public class Student implements Comparable<Student>{
    private int age;
    private String name;
    private double height;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getHeight() {
        return height;
    }

    public void setHeight(double height) {
        this.height = height;
    }

    public Student() {
    }

    public Student(int age, String name, double height) {
        this.age = age;
        this.name = name;
        this.height = height;
    }

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", height=" + height +
                '}';
    }

    @Override
    public int compareTo(Student o) {
//        return this.getAge() - o.getAge();
        return this.getName().compareTo(o.getName());
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return getAge() == student.getAge();
    }

    @Override
    public int hashCode() {
        return Objects.hash(getAge(), getName(), getHeight());
    }
}

package msb.com.map01;

import java.util.HashMap;
import java.util.Map;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 21:07
 * @Description: msb.com.map01
 * @version: 1.0
 */
public class Test03 {
    public static void main(String[] args) {
        Map<Student, Integer> map = new HashMap<>();
        map.put(new Student(19,"blili",170.5),1001);
        map.put(new Student(18,"blili",150.5),1003);
        map.put(new Student(19,"alili",180.5),1023);
        map.put(new Student(17,"clili",140.5),1671);
        map.put(new Student(10,"dlili",160.5),1891);

        System.out.println(map);
        System.out.println(map.size());
        /*
        {Student{age=18, name='blili', height=150.5}=1003,
        Student{age=17, name='clili', height=140.5}=1671,
        Student{age=19, name='blili', height=170.5}=1001,
        Student{age=19, name='alili', height=180.5}=1023,
        Student{age=10, name='dlili', height=160.5}=1891}

         */

    }
}

外部比较器

package msb.com.map01;

import java.util.Comparator;
import java.util.Map;
import java.util.TreeMap;

/**
 * @Auther: jack.chen
 * @Date: 2023/9/24 - 09 - 24 - 21:07
 * @Description: msb.com.map01
 * @version: 1.0
 */
public class Test04 {
    public static void main(String[] args) {
        Map<Student, Integer> map = new TreeMap<>(new Comparator<Student>(){
            @Override
            public int compare(Student o1, Student o2) {
                return ((Double)(o1.getHeight())).compareTo((Double)(o2.getHeight()));
            }
        });
        map.put(new Student(19,"blili",170.5),1001);
        map.put(new Student(18,"blili",150.5),1003);
        map.put(new Student(19,"alili",180.5),1023);
        map.put(new Student(17,"clili",140.5),1671);
        map.put(new Student(10,"dlili",160.5),1891);

        System.out.println(map);
        System.out.println(map.size());


    }
}

总结:

15. HashMap部分源码

public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable{
		
	static final int DEFAULT_INITIAL_CAPACITY = 16;
	static final float DEFAULT_LOAD_FACTOR = 0.75f;
	
	transient Entry<K,V>[] table;//主数组,每个元素为Entry类型
	
	transient int size;
	
	int threshold;//数组扩容的界限值,门槛值   16*0.75=12 
	
	final float loadFactor;//用来接收装填因子的变量
	
	//构造器
	//this(16,0.75f);调用了当前类中的带参构造器
	public HashMap() {
	this(DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR);
	
	}
	
	int capacity = 1;
	while (capacity < initialCapacity)
		capacity <<= 1;
    
	//【7】给loadFactor赋值,将装填因子0.75赋值给loadFactor
	this.loadFactor = loadFactor;
    
	//【8】数组扩容的界限值,门槛值
	threshold = (int)Math.min(capacity * loadFactor, MAXIMUM_CAPACITY + 1);
			
	
	//【9】给table数组赋值,初始化数组长度为16
	table = new Entry[capacity];	
		
		
		
	public V put(K key, V value) {
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        modCount++;
        addEntry(hash, key, value, i);
        return null;
    }

        static int indexFor(int h, int length) {
        //其实这个算法就是取模运算:h%length,取模效率不如位运算
		//计算元素放入table中的位置
        return h & (length-1);
		
		
	void addEntry(int hash, K key, V value, int bucketIndex) {
    //【25】size的大小  大于 16*0.75=12的时候,比如你放入的是第13个,这第13个你打算放在没有元素的位置上的时候
    if ((size >= threshold) && (null != table[bucketIndex])) {
            //【26】主数组扩容为2倍
            resize(2 * table.length);
            //【30】重新调整当前元素的hash码
            hash = (null != key) ? hash(key) : 0;
            //【31】重新计算元素位置
            bucketIndex = indexFor(hash, table.length);
        }
        //【19】将hash,key,value,bucketIndex位置  封装为一个Entry对象:
        createEntry(hash, key, value, bucketIndex);
    }
	
	void createEntry(int hash, K key, V value, int bucketIndex) {
        //【21】获取bucketIndex位置上的元素给e
        Entry<K,V> e = table[bucketIndex];
        //【22】然后将hash, key, value封装为一个对象,然后next的指向为e (链表的头插法)
        //【23】将新的Entry放在table[bucketIndex]的位置上
        table[bucketIndex] = new Entry<>(hash, key, value, e);//7上8下
        //【24】集合中加入一个元素 size+1
        size++;
    }
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
		
}

16. 主数组table的容量capacity的长度是如何确定的

不断地左移 直到不能扩

17. 计算索引的位置

static int indeFor(int h, int length){
	return h&(length-1);
}
&运算:两个1 才返回1

hash=3           0000 0011
legnth 8-1=7     0000 0111
&                0000 0011 -->3

hash=2           0000 0010
legnth 8-1=7     0000 0111
&                0000 0010 -->3

length-1 转成二进制-->所有位上面被1占
hash&(length-1) 输出的就是hash

18 装填因子

如果装填因子是1, 那么数组满了再扩容,可以做到 最大的空间利用率
但是这是一个理想状态,元素不可能完全的均匀分布,很可能就哈西碰撞产生链表了。产生链表的话 查询时间就长了。
--->空间好,时间不好

那么有人说 ,把装填因子搞小一点,0.5, 如果是0.5的话,就浪费空间,但是可以做到 到0.5就扩容 ,然后哈西碰撞就少,
不产生链表的话,那么查询效率很高
--->时间好,空间不好

所以在空间和时间中,
取中间值,平衡这个因素 就取值为 0.75

19 TreeMap底层原理

递归搜寻 放入正确的位置

public class TreeMap<K,V>{
        //重要属性:
        //外部比较器:
        private final Comparator<? super K> comparator;
        //树的根节点:
        private transient Entry<K,V> root = null;
        //集合中元素的数量:
        private transient int size = 0;
        //空构造器:
        public TreeMap() {
        comparator = null;//如果使用空构造器,那么底层就不使用外部比较器
    }
        //有参构造器:
        public TreeMap(Comparator<? super K> comparator) {
        this.comparator = comparator;//如果使用有参构造器,那么就相当于指定了外部比较器
    }
        
        public V put(K key, V value) {//k,V的类型在创建对象的时候确定了
        //如果放入的是第一对元素,那么t的值为null
        Entry<K,V> t = root;//在放入第二个节点的时候,root已经是根节点了
                //如果放入的是第一个元素的话,走入这个if中:
        if (t == null) {
                        //自己跟自己比
            compare(key, key); // type (and possibly null) check
                        //根节点确定为root
            root = new Entry<>(key, value, null);
                        //size值变为1
            size = 1;
            modCount++;
            return null;
        }
                
        int cmp;
        Entry<K,V> parent;
        // split comparator and comparable paths
                //将外部比较器赋给cpr:
        Comparator<? super K> cpr = comparator;
                //cpr不等于null,意味着你刚才创建对象的时候调用了有参构造器,指定了外部比较器
        if (cpr != null) {
            do {
                parent = t;
                cmp = cpr.compare(key, t.key);//将元素的key值做比较
                                //cmp返回的值就是int类型的数据:
                                //要是这个值《0 =0  》0
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else//cpm==0
                                //如果key的值一样,那么新的value替换老的value  但是key不变 因为key是唯一的
                    return t.setValue(value);
            } while (t != null);
        }
                //cpr等于null,意味着你刚才创建对象的时候调用了空构造器,没有指定外部比较器,使用内部比较器
        else {
            if (key == null)
                throw new NullPointerException();
            Comparable<? super K> k = (Comparable<? super K>) key;
            do {
                parent = t;
                cmp = k.compareTo(t.key);//将元素的key值做比较
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else
                    return t.setValue(value);
            } while (t != null);
        }
        Entry<K,V> e = new Entry<>(key, value, parent);
        if (cmp < 0)
            parent.left = e;
        else
            parent.right = e;
        fixAfterInsertion(e);
        size++;//size加1 操作
        modCount++;
        return null;
    }
        
        
}

posted @ 2023-09-24 17:08  jack-chen666  阅读(3)  评论(0编辑  收藏  举报