TreeMap与TreeSet(初步了解)

日升时奋斗,日落时自省 

目录

一、Map和Set

1、搜索树的基本概念

 2、二叉搜索查找

3、二叉搜索树插入

4、二叉搜索树删除

 二、TreeMap

 三、TreeSet

一、Map和Set

Map/Set 及实际实现类 HashMap/TreeMap/HashSet/TreeSet 的使用,本次复习TreeMap和TreeSet

Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关:

1.直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢
2. 二分查找,时间复杂度为O(log_{2}n ),但搜索前必须要求序列是有序的
放入现实中都很难遇到巧合的情况,集合就更针对实现的复杂情况,动态查找集合便是更优的选择Map和Set就是动态查找容器

TreeMap是一个搜索树,但是不仅仅是一颗搜索树,因为单单的搜索树是不能实现很多情况为最优

搜索树相对于TreeMap其他底层代码更简单,初步入手

1、搜索树的基本概念

二叉搜索树也叫二叉排序树,基本性质:
左子树所有节点的值都小于根节点的值;

右子树所有节点的值都大于根节点的值;

它的左右子树都遵循前面的条件,分别也会构成二叉搜索树,这一整棵树才算是二叉搜索树

用一个数据举例:5  3  4  1  7  8  2  6  0  9

 2、二叉搜索查找

二叉搜索树的查找有点类似于二分法查找,每次找的数据都会与当前根的值进行比较,大于根节点的就向根的右边进行查找,小于根节点的就向左边进行查找

借上面的图

思路解析:

(1)一颗搜索树不为空情况下

(2)节点值==key,return true;

(3)节点值>key,向左子树找

(4)节点值<key,向右子树找

(5)key在二叉搜索树中不存在,return false

 图解:

(1)空树

 (2)非空书

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

        public NodeTree(int val){
            this.val=val;
        }
    }
    public static NodeTree root=null;
public boolean search(int key){
        NodeTree cur=root;
        while(cur!=null){   //树不为空
            if(cur.val>key) {    //节点值>key,向左子树找
                cur=cur.left;
            }else if(cur.val<key){   //节点值<key,向右子树找
                cur=cur.right;
            }else{
                return true;    //节点值==key,return true;
            }
        }
        return false;  //没有找到情况
    }

3、二叉搜索树插入

开始已经知道二叉树是什么了,插入其实就比较简单了

思路:

(1)树为空的情况,直接插入  (树为空)

(2)比根节点小,向左子树走 (树不为空)

(3)比根节点大,向右子树走

(4)如果找到一样的值了,就返回false

(5)直到走到空,就可以插入了

注:找到空了,怎么插入呢,这里就需要一个知道他的父节点,所以这里要记录一个父节点

(1)空树 

 (2)非空树

代码解析:

public  boolean insert(int key){   //二叉搜索树进行插入
        if(root==null){
            root=new NodeTree(key);   //如果为空的话就只插入
            return true;
        }
        NodeTree cur=root;
        NodeTree parent=null;          //这里记录一下父节点,为了后面找到插入位置,进行连接
        while(cur!=null){               //树不为空,一直找
            if(cur.val>key){          //跟节点值小的,
                parent=cur;           //记录当前父节点
                cur=cur.left;          //找右子树
            }else if(cur.val<key){     //根节点值大的,
                parent=cur;            //记录当前父节点
                cur=cur.right;         //找左子树
            }else{                 //搜索树中不存在相同的值,如果相同的话就返回false
                return false;
            }
        }
        NodeTree node=new NodeTree(key);   //找到插入位置了建立新节点
        if(key> parent.val){           //比父亲节点小,左边插入
            parent.right=node;
        }else{                         //比父亲节点大,右边插入
            parent.left=node;                
        }
        return true;
    }

4、二叉搜索树删除

删除的步骤就相对较多了

思路: 分析以下情况   (设置待删除节点为cur,当前父节点为parent)

(1)cur.left==null

(2)cur.right==null

(3)cur.left!=null&&cur.right!=null

以上三种情况,我们通过图解来详细解释

用替换法将待删除的值替换,并且保证整个二叉搜索树不会动摇

图解:

特殊情况:

 

 代码解析:

代码是与图是相反的可以看着图来推当前代码

public void removeNode(NodeTree parent,NodeTree cur){
        if(cur.left==null){   //为了找到待删除的值
            if(cur==root){
                root=cur.right;
            }else if(cur==parent.left){
                parent.left=cur.right;
            }else if(cur==parent.right){
                parent.right=cur.right;
            }
        }else if(cur.right==null){
            if(cur==root){
                root=cur.left;
            }else if(cur==parent.left){
                parent.left=cur.left;
            }else  if(cur==parent.right){
                parent.right=cur.left;
            }
        }else{   //这里我们取一种就可以了
            NodeTree target=cur.right;
            NodeTree targetparent=cur;
            while(target.left!=null) {   //为了找替换值
                targetparent=target;
                target=target.left;
            }
            cur.val=target.val;
            if(target==targetparent.left){  //分两种情况
                targetparent.left=target.right;
            }else{
                targetparent.right=target.right;
            }
        }
    }

 二、TreeMap

里面是一个集合 ,TreeMap的底层代码是一个Map集合接口

Map底层结构TreeMap
底层结构红黑树
插入/删除/查找时间
复杂度
O(1)
是否有序关于Key有序
线程安全不安全
插入/删除/查找区别需要进行元素比较
比较与覆写key必须能够比较,否则会抛出
ClassCastException异常
应用场景需要Key有序场景下

 泛型有两个第一个传入key,第二个传入value

这里的key是可以比较的key值,传key时调用了比较器,如果不是可以比较的,就会报错

 put方法就是将我们需要的key,value值放入存储起来

getOrDefault方法是key是否找到,如果没有就返回默认值

除了上面的方法,还有以下比较基本的方法使用,可以尝试 

方法解释
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<K> keySet()返回所有 key 的不重复集合
Collection<V> values()返回所有 value 的可重复集合
Set<Map.Entry<K, V>> entrySet()返回所有的 key-value 映射关系
boolean containsKey(Object key)判断是否包含 key
boolean containsValue(Object value)判断是否包含 value

 前面的图TreeMap用Set棘手后打印

那Map的打印应怎么处理呢

这里肯定不能用foreach,迭代打印因为都没有继承关系

代码解释:

public static void main(String[] args) {
        Map<String,Integer> map=new TreeMap<>();
        map.put("hello",2);
        map.put("abc",1);
        Set<Map.Entry<String,Integer>> entries=map.entrySet();
        for (Map.Entry<String,Integer> set:entries) {
            System.out.println(set.getKey()+" "+set.getValue());
        }
    }

图解一下:

 三、TreeSet

TreeSet的底层是TreeMap,去掉重复的元素,key的重复不会再搜索树中出现

TreeSet继承了Set,Set又继承了Collection

注:将Map与Set联系起来Set<Map.Entry<String,Integer>> entries=map.entrySet();

才能使用Iterable中迭代打印,foreach打印等方法,Map一系中是独立出来并没有实现在下面的关系图中,TreeSet弥补了当前的缺陷。

 TreeSet的底层是TreeMap,直接将TreeMap与上面的关系图联系起来,TreeSet也同样有TreeMap的限制,泛型传值中是需要经过比较。(用于Map相同的方法)

 Set<Map.Entry<String,Integer>> entries=map.entrySet();

解释:

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值