TreeMap的实现原理

TreeMap的结构是红黑树又称红-黑二叉树,它首先是一颗二叉树,它具体二叉树所有的特性。同时红黑树更是一颗自平衡的排序二叉树。关于红-黑二叉树,可以参考:点击打开链接


在这里,我们主要简单分析TreeMap的源码实现。


 public Object put(Object obj, Object obj1)



TreeMap里的数据都是存放在Entry里的,这也是树的节点,下面是Entry的构造方法


<span style="font-size:18px;"> <span>	</span>Object key;
        Object value;
        Entry left;
        Entry right;
        Entry parent;
        boolean color;

        Entry(Object obj, Object obj1, Entry entry)
        {
            left = null;
            right = null;
            color = true;
            key = obj;
            value = obj1;
            parent = entry;
        }</span>


new一个Entry的时候,进行初始化,指定key、value、parent,同时把左右孩子设为null;


下面是创建一个新节点的put方法的源码,并对代码附上相应解释


 public Object put(Object obj, Object obj1)
    {
        Entry entry = root;
        if(entry == null)   //如果entry==Null,说明该TreeMap为空,则把entry设为根节点
        {
            compare(obj, obj);
            root = new Entry(obj, obj1, null);  //创建一个根节点
            size = 1;      
            modCount++;
            return null;
        }
        Comparator comparator1 = comparator;
        int i;                     //变量i,用来记录新创建节点的key值与TreeMap原有节点key值的大小关系
        Entry entry1;
        if(comparator1 != null)
        {
            do
            {                   //这个循环是为了寻找新创建节点的parent,entry1就是新创建节点的parent
                entry1 = entry;
                i = comparator1.compare(obj, entry.key);
                if(i < 0)
                    entry = entry.left;
                else
                if(i > 0)
                    entry = entry.right;
                else
                    return entry.setValue(obj1);
            } while(entry != null);
        } else
        {
            if(obj == null)
                throw new NullPointerException();
            Comparable comparable = (Comparable)obj;
            do	              //这个循环是也是为了寻找新创建节点的parent,entry1就是新创建节点的parent
            {
                entry1 = entry;
                i = comparable.compareTo(entry.key);
                if(i < 0)
                    entry = entry.left;
                else
                if(i > 0)
                    entry = entry.right;
                else
                    return entry.setValue(obj1);
            } while(entry != null);
        }
        Entry entry2 = new Entry(obj, obj1, entry1);//这里正式创建一个节点了,并指定entry1为新创建节点的parent
        if(i < 0)                               //判断新创建节点是该作为entry1的左孩子还是右孩子
            entry1.left = entry2;                         
        else
            entry1.right = entry2;                        
        fixAfterInsertion(entry2);
        size++;
        modCount++;
        return null;
    }

private void deleteEntry(Entry entry)

其实更为复杂的还是删除节点,删除节点分为三种情况,一种是删除叶子节点,只要把被删除节点的left,right,parent都设为null就可以;第二种是删除的节点只有一个孩子,也就是只有左孩子或者只有右孩子,假设只有左孩子entryLeft,那就只要把被删除节点的左孩子的parent指向被删除节点的parent,然后再判断被删除节点是自身parent的左孩子还是右孩子,如果是右孩子,则把parent的right指向entryLeft,这样就完成了删除操作;复杂的是第三种情况,就是当被删除节点拥有两个孩子left和right的时候,要判断出哪个是被删除节点的后继节点,由于二叉树的特殊结构决定了某个节点entry的left以及left下所有的节点都小于entry,而entry的right以及right下所有的节点都大于entry,而要满足这一要求,就得从entry的left下找,而且得找最小的节点,这样才满足比entry的left下所有结点都大,同时比entry的right下的所有节点都小。下面是deleteEntry(Entry entry)的源码,并附上解析


static Entry successor(Entry entry)    
    {
        if(entry == null)
            return null;
        if(entry.right != null)
        {
            Entry entry1;
            for(entry1 = entry.right; entry1.left != null; entry1 = entry1.left);
            return entry1;//返回entry节点的右子树中最小的节点(其实就是寻找entry的右子树中最小的左孩子)
        }
        Entry entry2 = entry.parent;
        for(Entry entry3 = entry; entry2 != null && entry3 == entry2.right; entry2 = entry2.parent)
            entry3 = entry2;

        return entry2;
    }
	
	
private void deleteEntry(Entry entry)
{
        modCount++;
        size--;
        if(entry.left != null && entry.right != null)//entry有两个孩子的时候的处理
        {
            Entry entry1 = successor(entry); //寻找entry的后继节点,然后用后继节点替换
            entry.key = entry1.key;
            entry.value = entry1.value;
            entry = entry1;
        }
        Entry entry2 = entry.left == null ? entry.right : entry.left;//entry2是被删除节点的后继节点(这种情况是针对entry只有一个孩子的时候)
        if(entry2 != null)               //entry2!=null说明entry有一个左孩子或者右孩子
        {
            entry2.parent = entry.parent;       //把要删除的entry的parent作为后继节点entry2的parent
            if(entry.parent == null)             //如果entry.parent==null,说明entry是根节点,则把entry2作为根节点
                root = entry2;
            else
            if(entry == entry.parent.left)       //如果entry是属于entry.parent的左孩子,则把后继节点entry2也作为entry.parent的左孩子。
                entry.parent.left = entry2;
            else											
                entry.parent.right = entry2;	//如果entry是属于entry.parent的右孩子,则把后继节点entry2也作为entry.parent的右孩子。		
            entry.left = entry.right = entry.parent = null;  //把entry的left、right、parent都设为null。
            if(entry.color)
                fixAfterDeletion(entry2);        
        } else
        if(entry.parent == null)     //如果entry.parent==null,说明该树只有一个节点,而且是根节点,把根节点设为null
        {
            root = null;
        } else                        
        {
            if(entry.color)
                fixAfterDeletion(entry);
            if(entry.parent != null)         //entry为叶子节点的时候的处理,把被删除的left、right、parent都设为Null
            {
                if(entry == entry.parent.left)
                    entry.parent.left = null;
                else
                if(entry == entry.parent.right)
                    entry.parent.right = null;
                entry.parent = null;
            }
        }
 }




  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值