Java Map和Set

目录

一.二叉搜索树

1.概念

2.二叉搜索树功能的模拟实现

2.1 查找

2.2 插入

2.3 删除

二.Map

1. Map.Entry,v>

2.Map的常用方法

3.TreeMap和HashMap的区别

4.注意事项

三.Set

1.Set的常见方法

2.TreeSet和HashSet的区别

3.注意事项


一.二叉搜索树

1.概念

二叉搜索树具有以下特性:

若它的左子树不为空,则左子树上所有节点的值都小于根节点的值;

若它的右子树不为空,则右子树上所有节点的值都大于根节点的值;

它的左右子树也分别为二叉搜索树;

空树也是二叉搜索树。

2.二叉搜索树功能的模拟实现

基本信息:

static class TreeNode {
        public int val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }
public TreeNode root ;

2.1 查找

根据二叉搜索树的特性,我们首先比较要查的值与根节点的大小关系,如果相等,正好找到;如果大于,说明可能在右子树上;如果小于,说明可能在左子树上。

这个思路很简单,直接上代码:

    public TreeNode search(int val) {
        if(root==null){
            return null;
        }

        TreeNode cur=root;

        while(cur!=null){
            if(cur.val==val){
                return cur;
            }else if(cur.val>val){
                cur=cur.left;
            }else{
                cur=cur.right;
            }
        }

        return null;
    }

2.2 插入

首先我们要先查找这个点是否存在,因为这是一颗搜索树,是用来查某一个 val 是否存在的,存一个和存两个没有区别。如果不存在,说明我们可以插入了,所以说下面我们要找一个合适的位置插入。

第一步先判断是不是空树,如果是空树直接在root上操作。如果不是就遍历这颗树,我们要不断往下找,操作类似查找。如果一个节点比 key 的值小(说明   key 在节点的右子树上),同时这个节点的右子树还是空的,那么直接插在这个节点的右子树上;相反,如果一个节点比 key 的值大,同时左子树还是空的,那么直接插在这个节点的左子树上。

public void insert(int key) {
    if(root==null){
        root=new TreeNode(key);
        return ;
    }

    TreeNode node=new TreeNode(key);

    TreeNode cur=root;

    while(cur!=null){
        if(cur.val<key && cur.right==null){
            cur.right=node;
        }else if (cur.val>key && cur.left==null){
            cur.left=node;
        }else{
            if(cur.val<key){
                cur=cur.right;
            }else if(cur.val>key){
                cur=cur.left;
            }else{
                return ;
            }
        }
    }
}

2.3 删除

删除操作是最难的,要考虑的情况较多。

要删除的节点可以分为以下几种情况:1.左子树是空;2.右子树是空;3.左右子树都不是空;4.左右子树都是空。

我们要定义一个 parent 节点,这个节点用来存储cur的父节点。图中的例子cur是parent的右节点,cur当然也可以是parent的左节点。

cur的左子树为空,那么要删除cur的话首先要判断cur的parent的左节点还是右节点。如果和图中例子一样为右节点,那么 parent.right = cur.right;如果为左节点,那么 parent.left = cur.right。

cur的右子树为空的判断处理与左子树的相同这里就不过多赘述了。

重量级的来的,cur的左右子树都不为空。对于这个问题,我们采用的是替换,将cur的值替换掉。

那么谁来替换cur呢?这又要说到搜索树的性质了,cur的左子树上的值都比cur小,所以说,可以取出cur左子树中的最大值来替代cur,这样能继续满足搜索树的要求即左子树的上的值都比cur上的小(因为它是最大值)。取cur右子树的最小值行不行?也行。

那什么样的节点是最值节点呢?在左子树中,一个节点没有右子树,说明其是左子树最右面的节点,即为最大节点。同理在右子树中,一个节点没有左子树,说明其是右子树最左面的节点,即为最小节点。

知道了这些我们可以写代码了,代码上有注释:

public void remove(int key){
    TreeNode cur=root;
    TreeNode parent=root;

    //找到我们要删除节点在哪里
    while(cur!=null){
        if(cur.val>key){
            parent=cur;
            cur=cur.left;
        }else if(cur.val<key){
            parent=cur;
            cur=cur.right;
        }else{
            //找到了
            removeNode(parent,cur);
            return;
        }
    }
}

private void removeNode(TreeNode parent, TreeNode cur) {
    if(cur.left==null){
        //左子树为空
        if(cur==root){
            root=cur.right;
        }else if(parent.left==cur){
            parent.left=cur.right;
        }else{
            parent.right=cur.right;
        }
    }else if(cur.right==null){
        //右子树为空
        if(cur==root){
            root=cur.left;
        }else if(parent.right==cur){
            parent.right=cur.left;
        }else{
            parent.left=cur.left;
        }
    }else{
        //这里以找右子树的最小值为例
        TreeNode tem=cur.right;
        //存它的目的是为了一会删最值节点用的
        TreeNode temParent=cur;

        //找最小值所在的节点
        while(tem.left!=null){
            temParent=tem;
            tem=tem.left;
        }

        cur.val=tem.val;
        if(temParent.left==tem){
            temParent.left=tem.right;
        }else{
            temParent.right=tem.right;
        }
    }
}

二.Map

Map是一个接口类,该类没有继承自Collection,该类中存储的是结构的键值对,并且K一定是唯一的,不能重复。

1. Map.Entry<K,V>

Map.Entry是Map的一个内部类,用来存放K和V的映射关系,也就是说它存的是一个集合,集合里都是映射关系。这个内部类里也提供了也写方法:

方法

功能
K getKey()返回 key 值
V getValue()返回 value 值
V setValue(V value)替换 value 值

2.Map的常用方法

注意这里总结的是常用的方法,不是全部方法,全部方法去idea上看即可。

方法功能
V get(Object key)返回 key 对应的 value
V getOrDefault(Object key, V defaultValue)返回 key 对应的 value,key 不存在,返回默认值
V put(K key, V value)设置 key 对应的 value
V remove(Object key)删除 key 对应的映射关系
Set keySet()返回所有 key 的不重复集合
Collection values()返回所有 value 的可重复集合
Set<Map.Entry<K,V>>  entrySet()返回所有的 key-value 映射关系
boolean containsKey(Object key)判断是否包含 key
boolean containsValue(Object value)判断是否包含 value
void clear()清空集合
int size()获得集合大小
boolean isEmpty()判断集合是否为空

3.TreeMap和HashMap的区别

MapTreeMapHashMap
底层结构红黑树哈希桶
基本操作的时间复杂度O(log(N))O(1)
是否有序关于key有序无序
线性安全不安全不安全
基本操作的区别需要进行元素的比较通过哈希实现
比较和覆写key必须可以比较自定义类型需要覆写
应用场景需要key有序场景下key有序无关,需要更高的时间性能

4.注意事项

1.Map是一个接口,接口不能直接实例化,要借助TreeMap或HashMap来实例化。

Map<Integer,Integer> map1=new TreeMap<>();
Map<Integer,Integer> map2=new HashMap<>();

2.key和value是一种映射关系,就是说我们可以用key来找其对应的value值。比如我们可以存姓名和年龄,姓名的key,年龄是value。我们就可以通过姓名来找到这个人的年龄。这里注意,姓名也就是key是不能重复的,但年龄(value)是可以重复的。

3. TreeMap插入关系时,value可以为空,key不为空;但HashMap中都可以为空

4.Map中的Key可以全部分离出来,存储到Set中来进行访问(因为Key不能重复);Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)。

三.Set

Set继承自 Collection 的类接口,Set中只存储Key。

1.Set的常见方法

方法功能
boolean add(E e)添加key进集合
boolean remove(Object o)删除集合中的o
void clear()清空集合
boolean isEmpty()判断集合是否为空
boolean contains(Object o)判断集合中是否有o
int size()集合中元素的个数
Iterator iterator()返回迭代器
Object[] toArray()将set中的元素转换为数组返回
boolean containsAll(Collection<?> c)集合c中的元素是否在set中全部存在,是返回true,否则返回 false
boolean addAll(Collection<?extends E> c)将集合c中的元素添加到set中,可以达到去重的效果

2.TreeSet和HashSet的区别

SetTreeSetHashSet
底层结构红黑树哈希桶
基本操作的时间复杂度O(log(N))O(1)
是否有序关于key有序不一定有序
线性安全不安全不安全
基本操作的区别需要进行元素的比较通过哈希实现
比较和覆写key必须可以比较自定义类型需要覆写
应用场景需要key有序场景下key有序无关,需要更高的时间性能

3.注意事项

1.Set这个接口适用于只需要判断某一元素是否在集合里的这种情况,像判断某一班级里有没有XX这个同学。

2.TreeSet插入的key值不可以是空的,而HashSet可以插入空的

  • 14
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Java中,也有类似于C++ STL中的mapset的容器。Java中的mapset都是基于接口实现,常用的实现类有HashMap、TreeMap、LinkedHashMap等。常用的set实现类有HashSet、TreeSet、LinkedHashSet等。 Map接口和Set接口的主要区别在于,Map接口用于存储键值对,而Set接口用于存储不重复的元素。Map接口提供了put()、get()、remove()等方法,Set接口提供了add()、remove()、contains()等方法。 HashMap是一种基于哈希表实现的Map接口的实现类,它提供了快速的查找、插入和删除操作,查找、插入和删除操作的时间复杂度都为O(1)。HashMap中的键和值都可以为null,但HashMap不保证元素的有序性。如果需要按照元素的插入顺序访问元素,可以使用LinkedHashMap。 TreeMap是一种基于红黑树实现的Map接口的实现类,它保证了元素的有序性,元素按照键的自然顺序或比较器顺序进行排序。TreeMap的查找、插入和删除操作的时间复杂度都为O(logN)。 HashSet是一种基于哈希表实现的Set接口的实现类,它提供了快速的查找、插入和删除操作,查找、插入和删除操作的时间复杂度都为O(1)。HashSet不保证元素的有序性,元素可以为null。 TreeSet是一种基于红黑树实现的Set接口的实现类,它保证了元素的有序性,元素按照自然顺序或比较器顺序进行排序。TreeSet的查找、插入和删除操作的时间复杂度都为O(logN)。 LinkedHashSet是一种基于哈希表和链表实现的Set接口的实现类,它保证了元素的插入顺序,同时提供了快速的查找、插入和删除操作。LinkedHashSet的查找、插入和删除操作的时间复杂度都为O(1)。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值