当前位置:   article > 正文

TreeMap与TreeSet(初步了解)_treemap和treeset

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)非空书

  1. static class NodeTree{
  2. public int val;
  3. public NodeTree left;
  4. public NodeTree right;
  5. public NodeTree(int val){
  6. this.val=val;
  7. }
  8. }
  9. public static NodeTree root=null;
  10. public boolean search(int key){
  11. NodeTree cur=root;
  12. while(cur!=null){ //树不为空
  13. if(cur.val>key) { //节点值>key,向左子树找
  14. cur=cur.left;
  15. }else if(cur.val<key){ //节点值<key,向右子树找
  16. cur=cur.right;
  17. }else{
  18. return true; //节点值==key,return true;
  19. }
  20. }
  21. return false; //没有找到情况
  22. }

3、二叉搜索树插入

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

思路:

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

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

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

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

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

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

(1)空树 

 (2)非空树

代码解析:

  1. public boolean insert(int key){ //二叉搜索树进行插入
  2. if(root==null){
  3. root=new NodeTree(key); //如果为空的话就只插入
  4. return true;
  5. }
  6. NodeTree cur=root;
  7. NodeTree parent=null; //这里记录一下父节点,为了后面找到插入位置,进行连接
  8. while(cur!=null){ //树不为空,一直找
  9. if(cur.val>key){ //跟节点值小的,
  10. parent=cur; //记录当前父节点
  11. cur=cur.left; //找右子树
  12. }else if(cur.val<key){ //根节点值大的,
  13. parent=cur; //记录当前父节点
  14. cur=cur.right; //找左子树
  15. }else{ //搜索树中不存在相同的值,如果相同的话就返回false
  16. return false;
  17. }
  18. }
  19. NodeTree node=new NodeTree(key); //找到插入位置了建立新节点
  20. if(key> parent.val){ //比父亲节点小,左边插入
  21. parent.right=node;
  22. }else{ //比父亲节点大,右边插入
  23. parent.left=node;
  24. }
  25. return true;
  26. }

4、二叉搜索树删除

删除的步骤就相对较多了

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

(1)cur.left==null

(2)cur.right==null

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

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

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

图解:

特殊情况:

 

 代码解析:

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

  1. public void removeNode(NodeTree parent,NodeTree cur){
  2. if(cur.left==null){ //为了找到待删除的值
  3. if(cur==root){
  4. root=cur.right;
  5. }else if(cur==parent.left){
  6. parent.left=cur.right;
  7. }else if(cur==parent.right){
  8. parent.right=cur.right;
  9. }
  10. }else if(cur.right==null){
  11. if(cur==root){
  12. root=cur.left;
  13. }else if(cur==parent.left){
  14. parent.left=cur.left;
  15. }else if(cur==parent.right){
  16. parent.right=cur.left;
  17. }
  18. }else{ //这里我们取一种就可以了
  19. NodeTree target=cur.right;
  20. NodeTree targetparent=cur;
  21. while(target.left!=null) { //为了找替换值
  22. targetparent=target;
  23. target=target.left;
  24. }
  25. cur.val=target.val;
  26. if(target==targetparent.left){ //分两种情况
  27. targetparent.left=target.right;
  28. }else{
  29. targetparent.right=target.right;
  30. }
  31. }
  32. }

 二、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,迭代打印因为都没有继承关系

代码解释:

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

图解一下:

 三、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();

解释:

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/991688
推荐阅读
相关标签
  

闽ICP备14008679号