映射TreeMap的实现

映射Map

Map 在有些编程语言中也叫做字典

在这里插入图片描述
Map接口

public interface Map<K,V> {
    /**
     * 存入键值对
     * @param key
     * @param value
     * @return 返回之前key对应的value
     */
    V put(K key,V value);
    V get(K key);
    V remove(K key);
    int size();
    boolean containsKey(K key);
    boolean containsValue(V value);
    boolean isEmpty();
    void clear();
    void traversal(Visitor<K,V> visitor);

    public static abstract class Visitor<K,V>{
        public abstract void visit(K key,V value);
    }
}

TreeMap

在这里插入图片描述
TreeMap本身其实是一棵红黑树,只不过他的节点中存储了Key和Value,其实现与红黑树基本相同。

import java.util.Comparator;
import java.util.LinkedList;
import java.util.Queue;

public class TreeMap<K,V> {
    private Node<K,V> root;
    private int size=0;
    private Comparator<K> comparator;//比较器
    public TreeMap(){}//不传入比较器的构造
    public TreeMap(Comparator<K> comparator){//传入比较器的构造
        this.comparator=comparator;
    }

    @Override
    public V put(K key, V value) {
        //如果是第一个元素
        if(null==root){
            root=createNode(key,value,null);
            size++;
            afterAdd(root);//后续操作
            return null;
        }
        //不是第一个节点
        Node<K,V> node=root;
        Node<K,V> parent=null;
        int cmp=0;
        while(node!=null){
            cmp=compare(key,node.key);
            parent=node;
            if(cmp<0){ //进入左侧节点
                node=node.left;
            }else if(cmp>0){//进入右侧节点
                node=node.right;
            }else{//相等覆盖
                node.key=key;
                V oldValue=node.value;
                node.value=value;
                afterAdd(node);
                return oldValue;
            }
        }
        Node<K,V> newNode=createNode(key,value, parent);
        //如果左侧节点为空,放置于左节点
        if(cmp<0)
            parent.left = newNode;
        else
            parent.right = newNode;
        size++;
        afterAdd(newNode);
        return null;//返回之前的节点,此处为空
    }

    @Override
    public V get(K key) {//获取键值对
        Node<K,V> node=node(key);
        return node==null?null:node.value;
    }

    @Override
    public V remove(K key) {
        return remove(node(key));
    }

    @Override
    public int size() {
        return size;
    }

    @Override
    public boolean containsKey(K key) {
        return node(key)!=null;
    }

    @Override
    public boolean containsValue(V value) {
        Queue<Node<K,V>> queue=new LinkedList<>();
        queue.offer(root);
        Node<K,V> cuNode=null;
        while(!queue.isEmpty()){
            cuNode=queue.poll();//出队
            if(value== cuNode.value)
                return true;
            if(null!=cuNode.left)
                queue.offer(cuNode.left);
            if(null!=cuNode.right)
                queue.offer(cuNode.right);
        }
        return false;
    }

    @Override
    public boolean isEmpty() {
        return size==0;
    }

    @Override
    public void clear() {
        root=null;
        size=0;
    }

    @Override
    public void traversal(Visitor<K, V> visitor) {
        if(null==visitor)return;
        inorderTraversal(root,visitor);
    }
    public static final boolean BLACK=false;
    public static final boolean RED=true;

    //树节点
    private static class Node<K,V>{
        K key;
        V value;
        boolean color=RED;
        Node<K,V> left;
        Node<K,V> right;
        Node<K,V> parent;

        public Node(){}
        public Node(K key,V value,Node<K,V> parent){
            this.key=key;
            this.value=value;
            this.parent=parent;
        }
        public boolean isLeaf(){
            return left==null&&right==null;
        }

        public boolean hasTwoChildren(){
            return left!=null&&right!=null;
        }

        //判断当前节点是否是父节点的左节点
        public boolean isLeftChild(){
            return parent!=null&&this==parent.left;
        }

        //判断当前节点是否是父节点的左节点
        public boolean isRightChild(){
            return parent!=null&&this==parent.right;
        }

        /**
         * 获取兄弟节点
         * @return
         */
        public Node<K,V> sibling(){
            if(isLeftChild()){
                return parent.right;
            }else if(isRightChild()){
                return parent.left;
            }
            //否则说明没有父节点
            return null;
        }
    }

    private Node<K,V> createNode(K key,V value, Node<K,V> parent){
        return new Node(key,value,parent);
    }

    /**比较方法中使用Key进行比较
     * @param k1 键1
     * @param k2 键2
     * @return -1代表k1大,0代表一样大,1代表k2大
     */
    private int compare(K k1,K k2){
        //调用自身比较器的方法
        if(null!=comparator)
            return comparator.compare(k1,k2);
        //强转为Comparable类型
        return ((Comparable<K>)k1).compareTo(k2);
    }

    private void afterAdd(Node<K,V> node) {
        Node<K,V> parent=node.parent;
        if(parent==null){//0.node是根节点
            black(node);//根节点必须是黑色
            return;
        }
        if(isBlack(parent))//1.父节点为黑色则无需处理
            return;
        Node<K,V> uncle=parent.sibling();//获取node叔父节点
        Node<K,V> grand=parent.parent;
        if(isRed(uncle)){//2.uncle是红色节点的情况
            black(parent);//将父节点和叔父节点涂黑,独立
            black(uncle);
            afterAdd(red(grand));//将祖父节点向上合并
            return;
        }
        //3.uncle节点是黑色
        if(parent.isLeftChild()){//L
            if(node.isLeftChild()){//LL
                red(grand);
                black(parent);
                rotateRight(grand);
            }else{//LR
                red(grand);
                black(node);
                rotateLeft(parent);
                rotateRight(grand);
            }
        }else{//R
            if(node.isLeftChild()){//RL
                red(grand);
                black(node);
                rotateRight(parent);
                rotateLeft(grand);
            }else{//RR
                red(grand);
                black(parent);
                rotateLeft(grand);
            }
        }

    }

    //右旋
    private void rotateRight(Node<K,V> grand){
        Node<K,V> parent=grand.left;
        Node<K,V> child=parent.right;//移交给grand节点的子节点
        grand.left=child;
        parent.right=grand;
        //后续操作
        afterRotate(grand,parent,child);
    }

    //左旋
    private void rotateLeft(Node<K,V> grand){
        Node<K,V> parent=grand.right;
        Node<K,V> child=parent.left;
        grand.right=child;
        parent.left=grand;
        //后续操作
        afterRotate(grand,parent,child);
    }

    void afterRotate(Node<K,V> grand, Node<K,V> parent, Node<K,V> child){
        parent.parent=grand.parent;
        if(grand.isRightChild())
            grand.parent.right=parent;
        else if(grand.isLeftChild())
            grand.parent.left=parent;
        else //grand是根节点
            root=parent;
        if(child!=null)
            child.parent=grand;
        grand.parent=parent;
    }

    
    private void afterRemove(Node<K,V> node, Node<K,V> replacement) {
        if(isRed(node))//如果删除的是红色节点
            return;
        if(isRed(replacement)){//如果用于取代的是红色节点
            black(replacement);//将节点染黑
            return;
        }
        //此时删除的是黑色叶子节点,会导致下溢(4阶B树的节点元素范围[1,3]
        //情况分类
        //0.删除的节点是根节点,无需操作
        if(node.parent==null)return;
        //1.兄弟节点是黑色且有红色子节点(此时parent可能为黑色,但是操作相同):对parent进行旋转,从兄弟节点分一个节点到待删除节点
        Node<K,V> parent=node.parent;
        //叶子节点删除后为空,利用空判断之前是左是右
        boolean left=parent.left==null||node.isLeftChild();//可能是递归进入的该函数,判断条件需加上是否是左节点
        Node<K,V> sibling=left?parent.right:parent.left;//不能用node判断,parent已经不指向它了

        if(!left){//被删除节点在右边,兄弟节点在左边
            if(isRed(sibling)){//兄弟节点是红色
                black(sibling);//将兄弟节点染黑
                red(parent);//parent节点染红
                rotateRight(parent);//parent右旋转
                sibling=parent.left;//更换兄弟
            }
            //兄弟节点一定是黑色
            if(isBlack(sibling.left)&&isBlack(sibling.right)){//兄弟节点为黑色且没有红色子节点
                //此时父节点需要向下和兄弟节点合并
                boolean parentBlack=isBlack(parent);
                black(parent);
                red(sibling);
                if(parentBlack)//若parent之前为黑色,则也产生了下溢
                    afterRemove(parent,null);
            }else{
                if(isBlack(sibling.left)){//兄弟节点没有红色节点可用
                    rotateLeft(sibling);
                    sibling=parent.left;
                }
                color(sibling,colorOf(parent));
                black(parent);
                black(sibling.left);
                rotateRight(parent);
            }
        }else{
            if(isRed(sibling)){//兄弟节点是红色
                black(sibling);//将兄弟节点染黑
                red(parent);//parent节点染红
                rotateLeft(parent);//parent右旋转
                sibling=parent.right;//更换兄弟
            }
            //兄弟节点一定是黑色
            if(isBlack(sibling.left)&&isBlack(sibling.right)){//兄弟节点为黑色且没有红色子节点
                //此时父节点需要向下和兄弟节点合并
                boolean parentBlack=isBlack(parent);
                black(parent);
                red(sibling);
                if(parentBlack)//若parent之前为黑色,则也产生了下溢
                    afterRemove(parent,null);
            }else{
                if(isBlack(sibling.right)){//兄弟节点没有红色节点可用
                    rotateLeft(sibling);
                    sibling=parent.right;
                }
                color(sibling,colorOf(parent));
                black(parent);
                black(sibling.right);
                rotateLeft(parent);
            }
        }

        //2.兄弟节点是黑色且没有红色子节点:将父节点染黑,兄弟节点染红,父节点与兄弟节点合并
        //(这样会带来黑色节点的子节点都是黑色节点的情况),若此时parent也是黑色节点,则会产生parent节点也下溢
        //这种情况下,我们可以看作对parent节点进行了删除处理
        //3.兄弟节点是红色,将兄弟节点染黑,父节点染红,情况就和上一样了
    }

    /**
     * 染色方法
     * @param node
     * @param color
     * @return
     */
    private Node<K,V> color(Node<K,V> node, boolean color){
        if(node==null)return node;
        node.color=color;
        return node;
    }

    /**
     * 染红
     * @param node
     * @return
     */
    private Node<K,V> red(Node<K,V> node){
        node.color= RED;
        return node;
    }

    /**
     * 染黑
     * @param node
     * @return
     */
    private Node<K,V> black(Node<K,V> node){
        node.color= BLACK;
        return node;
    }

    /**
     * 获取颜色
     * @param node
     * @return
     */
    private boolean colorOf(Node<K,V> node){
        return node==null?BLACK:node.color;
    }

    /**
     * 判断是否是红色
     * @param node
     * @return
     */
    private boolean isRed(Node<K,V> node){
        return colorOf(node)==RED;
    }

    /**
     * 判断是否是黑色
     * @param node
     * @return
     */
    private boolean isBlack(Node<K,V> node){
        return colorOf(node)==BLACK;
    }

    /**
     * 删除对印的节点
     * @param node
     */
    private V remove(Node<K,V> node){
        if(null==node)return null;
        size--;
        V oldValue=null;
        if(node.hasTwoChildren()) {//有两个叶子节点,使用后继节点代替
            Node<K,V> successor = successor(node);//后继节点
            oldValue=node.value;//保存待删除节点元素值
            node.key = successor.key;//替换元素值
            node.value=successor.value;
            node=successor;//将node指向待删除元素
        }
        //对指向的节点进行删除
        if(null==oldValue)oldValue=node.value;//若上方未保存值,则此处保存
        Node<K,V> replacement=node.left!=null?node.left:node.right;
        if(replacement==null) {//没有子节点,是叶子节点
            if (root == node) {//node是根节点
                root = null;
                afterRemove(node,null);
            }
            else {
                if (node == node.parent.left)
                    node.parent.left = null;
                else
                    node.parent.right = null;
                afterRemove(node,null);
            }
        }else{//非叶子节点
            replacement.parent=node.parent;//更改父节点
            if(root==node) {//如果node是根节点
                root = replacement;
            }else if(node==node.parent.left)
                node.parent.left=replacement;
            else
                node.parent.right=replacement;
            afterRemove(node,replacement);
        }
        return oldValue;//返回之前的元素值
    }

    /**
     * 查找到元素为key的节点
     * @param key
     */
    private Node<K,V> node(K key){
        Node<K,V> node=root;
        while(null!=node){
            int cmp=compare(key,node.key);
            if(cmp==0)return node;
            else if(cmp<0)node=node.left;
            else node=node.right;
        }
        return null;
    }

    /**
     * 获取该节点的后继节点,即中序遍历的后节点
     * @param node
     * @return
     */
    private Node<K,V> successor(Node<K,V> node){
        Node<K,V> prev=node.right;
        //当右节点不为空,寻找右子树中最左端的节点
        if(null!=prev){
            while(prev.left!=null){
                prev=prev.left;
            }
            return prev;
        }
        //此时右节点为空,后继节点为父节点(祖父..),且父节点的左节点是当前节点
        //去掉中间的作为父节点右节点的节点
        while(null!=node.parent&&node==node.parent.right){
            node=node.parent;
        }
        //null==node
        //node==node.parent.right
        return node.parent;
    }

    private void inorderTraversal(Node<K,V> node,Visitor<K,V> visitor){
        if(null==node)return;
        inorderTraversal(node.left,visitor);
//        System.out.print(node.key+":"+node.value+" ");
        visitor.visit(node.key,node.value);
        inorderTraversal(node.right,visitor);
    }

    private void levelOrderTraversal(Node<K,V> node){
        Queue<Node<K,V>> queue=new LinkedList<>();
        queue.offer(node);
        Node<K,V> cuNode=null;
        while(!queue.isEmpty()){
            cuNode=queue.poll();//出队
            System.out.print(node.key+":"+node.value+" ");//访问
            if(null!=cuNode.left)
                queue.offer(cuNode.left);
            if(null!=cuNode.right)
                queue.offer(cuNode.right);
        }
    }
}

                         ┌──────────────────────────────H:34-BLACK─────────────────────────────┐
                         │                                                                     │
            ┌───────D:27-BLACK──────┐                                 ┌────────────────────P:69-BLACK────────────────────┐
            │                       │                                 │                                                  │
     ┌─B:20-BLACK─┐           ┌─F:53-BLACK─┐             ┌────────L:51-RED───────┐                        ┌───────────T:49-RED───────────┐
     │            │           │            │             │                       │                        │                              │
A:60-BLACK    C:21-BLACK E:62-BLACK    G:85-BLACK ┌─J:99-BLACK─┐           ┌─N:32-BLACK─┐          ┌─R:18-BLACK─┐            ┌───────X:64-BLACK───────┐
                                                  │            │           │            │          │            │            │                        │
                                              I:9-BLACK    K:67-BLACK M:72-BLACK    O:57-BLACK Q:7-BLACK    S:53-BLACK ┌─V:23-RED─┐             ┌──o:23-RED───┐
                                                                                                                       │          │             │             │
                                                                                                                  U:45-BLACK  W:72-BLACK ┌─Z:95-BLACK─┐ world:2-BLACK─┐
                                                                                                                                         │            │               │
                                                                                                                                     Y:33-RED    hello:3-RED       变态:6-RED

Set与Map的关系

只需将Map节点中的value始终置空,即只是用Key和Value中的一个,Map就可以转变为Set。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值