Java Set集合 Map集合 | DAY 6

set集合

HashSet 无序 不重复 无索引

LinkedHashSet 有序 不重复 无索引

TreeSet 排序 不重复 无索引

特点

  • 无序(添加数据顺序和获取数据的顺序不一样)

  • 不重复

  • 无索引

HashSet底层原理

  • 基于哈希表实现 增删改查性能都较好

  • 默认创建长度16的数组 默认加载因子为0.75

    • 即 16*0.75=12 占满12 个位置后 会进行扩容原数组两倍

    • jdk8 开始 当链表长度超过8 且数组长度>=64 自动将链表转化成红黑树

      [红黑树]  自平衡二叉树,增删改查数据性能都较好

  • 使用元素的哈希值对数组长度求余计算出应存入的位置

  • 判断当前位置是否为null

    • 如果是直接存

    • 否则调用equals比较是否相等

      • 相等 不存

      • 不相等

        • jdk8 之前 新元素存入数组 占老元素位置 老元素挂下面

        • jdk8 之后 新元素直接挂老元素下面

去重复机制
默认不能对内容一样的两个不同对象去重复

如何更改?

  • 重写对象的hashcode 和equal方法

LinkedHashSet底层原理

有序 不重复 无索引

每个元素都额外多了一个双链表机制记录它前后元素的位置

TreeSet底层原理

不重复 无索引 可排序

基于红黑树进行排序

自定义对象 会报错

必须自定义排序规则(就近选择自带的比较器进行排序)

  • 自定义类 实现comparable接口 重写compareTo方法 来指定比较规则

    • 左边对象大于右边对象返回正整数

  • 调用TreeSet集合有参构造器 设置Comparator对象

    • public TreeSet(Comparator<? super E>comparator)

’HashSet和TreeSet取一个元素的时间复杂度为多少?存一个元素的时间复杂度为多少?

  1. HashSet:
    • 取元素的时间复杂度:O(1)
    • 存元素的时间复杂度:O(1)
  2. TreeSet:
    • 取元素的时间复杂度:O(log n)。TreeSet是基于红黑树(一种自平衡的二叉搜索树)实现的。从TreeSet中检索元素需要遍历树,直到找到所需的元素。因此,检索操作的时间复杂度与树的高度成正比,对于红黑树来说,其高度大约是O(log n)。
    • 存元素的时间复杂度:O(log n)。向TreeSet添加元素也涉及到在红黑树中插入节点。插入操作可能需要调整树的结构以保持其平衡,这通常需要O(log n)的时间。

前置知识

可变参数

  1. 声明:在Java中,可变参数(Varargs)允许你在方法调用时传递任意数量的参数,这些参数被视为数组。在方法声明中,通过在参数类型后面添加三个点(...)来声明可变参数。例如

public void myMethod(String... args) { 
// 方法体 
}
  1. 特点

    • 可变参数只能作为方法的最后一个参数。
    • 调用方法时,可以传递任意数量的参数(包括零个),这些参数会自动被封装成数组。
    • 如果一个方法既接受普通参数又接受可变参数,那么普通参数必须位于可变参数之前。

集合工具类:Collections

Collections 是Java中提供的一个实用工具类,包含了很多用于操作和处理集合的静态方法。以下是一些常用的 Collections API 及其功能:

  1. addAll():将一个集合的所有元素添加到另一个集合中。
  2. binarySearch():使用二分查找算法在已排序的列表中搜索指定元素。
  3. copy():将一个列表的元素复制到另一个列表中。
  4. emptyMap():返回一个不可变的、空的 Map
  5. emptySet():返回一个不可变的、空的 Set
  6. fill():使用指定的元素替换列表中的所有元素。
  7. max() 和 min():返回集合中的最大和最小元素。
  8. reverse():反转列表中元素的顺序。
  9. rotate():将列表中的元素循环移动指定的位置。
  10. shuffle():对列表中的元素进行随机排序。
  11. sort():对列表进行排序。

Map集合

概述

双列集合 一次需要存储一对数据作为一个元素

不允许出现键重复 但是值可以重复

场景 需要存储一一对应的数据时

Map<k,v> 泛型接口

  • HashMap 无序 不重复 无索引

    • LinkedHashMap 有序 不重复 无索引

  • TreeMap 升序排序 不重复 无索引

后面重复数据会覆盖前面的数据

哈希表冲突解决方式   

线性探测再散列

当出现哈希冲突时  会自动检测下一个桶是否有位置  如果有位置则会存储到下一个桶 否则继续寻找

二次探测再散列

相比较线性探测 二次探测则会跳过一些桶 再进行添加防止聚集现象 一般的我们会使用平方法进行跳过某些桶

链表法

发生哈希冲突 冲突位置的地方将会是一个链表的头结点这样 冲突的数据可以直接挂在到该链表下 但是数据多的时候会导致时间增加 所以java的hashmap使用链表加红黑树的技巧 在链表达到一定程度时 会自动转成红黑树 这样搜寻时间会大大降低 

常用方法

clear 删除所有映射

containsKey 判断集合包含某个键

containsValue 判断集合包含某个值

get 根据建取出值

keySet 获取集合中的所有键

put 添加元素

remove 根据键删除元素

size 获取大小

values 获取全部值

isEmpty 判断是否为空

遍历方式

  • 键找值

    • 先获取map全部键 再遍历键来找值

    • keySet 获取键存入set

    • 遍历set

  • 键值对

    • 把 键值对看成整体进行遍历

    • entry对象 存入set

  • lambda jdk1.8

    • forEach

实现myHashMap

public class myHashMap<K,V> {

    private final int hashFactor=7; //一个质数 用于增加哈希函数的散列性
    private Entry[] table;  //用于存放键值对对象的数组
    private int capacity;  // 数组的总容量
    private int size; //数组实际使用大小

    private int actsize;//实际存放数量 包括相同哈希挂载的链表数据

    private int length;// 当链条长度超过8 并且数组长度大于等于64 自动转成红黑树
    private final float factor=0.75f; //负载因子 当存储数量达到总数量的0.75就会自动扩容
    private int initialSize=16;

    myHashMap(){
        table=new Entry[initialSize];
        capacity=initialSize;
        size=0;

    }
    //封装一个存放键值对的对象
    private static class Entry<K, V> {
        K key;
        V value;
        Entry<K,V> next;


        Entry(K key,V value){
            this.value=value;
            this.key=key;

        }


        public K getKey() {
            return key;
        }

        public V getValue(){
            return value;
        }

        public Entry(K key, V value, Entry<K,V> next){
            this.key=key;
            this.value=value;
            this.next=next;

        }
        public void setValue(V v){
            this.value=v;
        }

    }
    //我的哈希函数 将键的值转换成字符串 输出字符的ascii码与原哈希值和加载因子的积相加
    private  int myHashCode(K k){
        String h=k.toString();
        int hash=0;
        for(int i=0;i<h.length();i++){
            hash=hash*hashFactor+h.charAt(i);

        }
        return hash%capacity;

    }



    public V get(K key){
       int code=myHashCode(key);
       if(table[code].getKey().equals(key)){
           return (V)table[code].getValue();
       }
       //数组没有目标数值 开始查询数组对应下标下的链表
       Entry temp;
       temp= table[code];
       while(temp.next!=null)
       {
           if(temp.getKey().equals(key)) {
               return (V) temp.getValue();
           }
               else
               {temp=temp.next;

           }
       }
       return null;

    }



    public boolean isEmpty(){
        if(size==0){
            return true;
        }
        else return false;

    }


    public boolean contains(K key){
        int index=myHashCode(key);
        if(table[index]==null){
            return false;

       }
        else{
            Entry temp=table[index];
            if(temp.getKey().equals(key))
                return true;
            while (temp.next!=null)
            {
                if(temp.getKey().equals(key))
                    return true;
                else
                {
                    temp=temp.next;
                }
            }
            return false;
        }


    }
//向map添加数值 首先检查数组大小 然后再计算添加数据键的哈希值 
// 如果有相同的 再比较键是否相同 如果相同就覆盖 不相同就挂载
    public void put(K key,V value){
        riseArray();//调用数组扩容函数,检查size是否等于指定扩容数值

        Entry e= new Entry(key,value);


        int index=myHashCode(key);

        if(table[index]==null)
        {
            table[index]=e;
            size++;
            actsize++;
        }
        else{
            if(table[index].getKey().equals(key)){
                table[index].setValue(value);
                return;
            }
            Entry temp=table[index];
            while(temp.next!=null){
                if(temp.getKey().equals(key)){
                    table[index].setValue(value);
                    return;
                }
                temp=temp.next;

            }
            temp.next=e;
            actsize++;

        }

        }



    private void riseArray() {
        if (size == capacity * factor) {
            Entry[] newTable = new Entry[capacity * 2];
            newTable = Arrays.copyOf(table, capacity);
            table = newTable;

        }
        return ;


    }

}

目前哈希冲突仅仅挂载在同一链表 并没有实现链表自动转换红黑树  

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值