182Java8利用二叉查找树实现Map

Posted zhangchao19890805

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了182Java8利用二叉查找树实现Map相关的知识,希望对你有一定的参考价值。

本文利用二叉查找树写了一个Map,用来保存键值对。

二叉查找树的定义

二叉查找树又名二叉搜索树,英文名称是 Binary Search Tree,缩写BST。

二叉排序树,英文名称是 Binary Sorted Tree,缩写BST。

二叉查找树、二叉搜索树、二叉排序树,这三者是一回事,只是名字不同。

二叉查找树的定义如下:

二叉查找树或者是一棵空树,或者是具有下列性质的二叉树:

  1. 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值。

  2. 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值。

  3. 它的左、右子树也分别为二叉查找树。

二叉查找树的时间复杂度和空间复杂度

Java8代码实现

二叉查找树的节点类:

package zhangchao.bst;

/**
 *
 * 二叉查找树的节点类。
 *
 * @author zhangchao
 *
 * @param <K> 二叉查找树的键。
 * @param <V> 二叉查找树的值。
 */
public class BstTreeMapNode<K,V> 

    // 键
    public K key = null;
    // 值
    public V value = null;

    // 父节点的引用。
    public BstTreeMapNode parent = null;
    // 左子节点的引用。
    public BstTreeMapNode left = null;
    // 右子节点的引用。
    public BstTreeMapNode right = null;




二叉查找树写的 BstTreeMap

package zhangchao.bst;

import java.util.*;

/**
 * 利用二叉查找树实现的Map
 *
 * @author zhangchao
 *
 * @param <K> 键
 * @param <V> 值
 */
public class BstTreeMap<K, V> 

    // 根节点
    private BstTreeMapNode root = null;

    // 用户自定义的比较器
    private Comparator<K> comparator;

    /**
     * 构造方法
     * @param comparator 用户自定义的比较器
     */
    public BstTreeMap(Comparator<K> comparator) 
        this.comparator = comparator;
    

    /**
     * 向map中放入键值对
     * @param key  键
     * @param value 值
     */
    public void put(K key, V value) 
        if (null == root) 
            root = new BstTreeMapNode<K, V>();
            root.parent = null;
            root.key = key;
            root.value = value;
            return;
        

        BstTreeMapNode<K, V> parent = null;
        BstTreeMapNode<K, V> current = root;
        int compareResult = 0;
        while (null != current) 
            compareResult = this.comparator.compare(key, current.key);
            if (compareResult < 0) 
                parent = current;
                current = current.left;
             else if (compareResult > 0) 
                parent = current;
                current = current.right;
             else 
                // 有相等的key,直接设置值就可以了。
                current.value = value;
                return;
            
        

        BstTreeMapNode<K, V> newItem = new BstTreeMapNode<K, V>();
        newItem.key = key;
        newItem.value = value;
        newItem.parent = parent;
        if (compareResult < 0) 
            parent.left = newItem;
         else if (compareResult > 0) 
            parent.right = newItem;
        
    

    /**
     * 根据键获取值
     * @param key 键
     * @return 值
     */
    public V get(K key) 
        BstTreeMapNode<K, V> current = root;
        int compareResult;
        while (null != current) 
            compareResult = this.comparator.compare(key, current.key);
            if (compareResult < 0) 
                current = current.left;
             else if (compareResult > 0) 
                current = current.right;
             else 
                // 有相等的key,直接返回值就可以了。
                return current.value;
            
        
        return null;
    

    /**
     * 获取键的列表,按照比较器的顺序排列。
     * @return 键的列表,按照比较器的顺序排列。
     */
    public List<K> keyList() 
        if (null == root) 
            return new ArrayList<K>();
        
        List<K> result = new ArrayList<K>();

        Stack<BstTreeMapNode> stack = new Stack<>();
        BstTreeMapNode<K, V> current = root;
        do 
            while (null != current) 
                stack.push(current);
                current = current.left;
            
            current = stack.pop();
            result.add(current.key);
            current = current.right;
         while (!stack.isEmpty() || null != current);

        return result;
    

    /**
     * 是否为空。
     * @return true表示为空;false表示不为空。
     */
    public boolean isEmpty() 
        return null == root;
    

    /**
     * 根据键获取 BST 树的节点。
     * @param key 键
     * @return BST树的节点
     */
    public BstTreeMapNode<K, V> getNode(K key) 
        BstTreeMapNode<K, V> current = root;
        int compareResult;
        while (null != current) 
            compareResult = this.comparator.compare(key, current.key);
            if (compareResult < 0) 
                current = current.left;
             else if (compareResult > 0) 
                current = current.right;
             else 
                // 有相等的key,直接返回值就可以了。
                return current;
            
        
        return null;
    

    /**
     * 根据键删除键值对。
     * @param key 键
     */
    public void remove(K key) 
        BstTreeMapNode<K, V> node = getNode(key);
        if (null == node) 
            return;
        
        // 叶子节点
        if (null == node.left && null == node.right) 
            if (node == root) 
                this.root = null;
             else if (node == node.parent.left) 
                node.parent.left = null;
             else if (node == node.parent.right) 
                node.parent.right = null;
            
            node.parent = null;
        
        // 只有左子节点
        else if (null != node.left && null == node.right) 
            if (node == root) 
                this.root = node.left;
             else if (node == node.parent.left) 
                node.parent.left = node.left;
             else if (node == node.parent.right) 
                node.parent.right = node.left;
            
            node.left.parent = node.parent;
            node.parent = null;
            node.left = null;
        
        // 只有右子节点
        else if (null == node.left && null != node.right) 
            if (node == root) 
                this.root = node.right;
             else if (node == node.parent.left) 
                node.parent.left = node.right;
             else if (node == node.parent.right) 
                node.parent.right = node.right;
            
            node.right.parent = node.parent;
            node.parent = null;
            node.right = null;
        
        // 不是根节点并且有左右子节点。
        else 
            BstTreeMapNode<K,V> current = node.left;
            while (null != current.right) 
                current = current.right;
            
            if (current == current.parent.left) 
                current.parent.left = current.left;
             else if (current == current.parent.right) 
                current.parent.right = current.left;
            
            if (null != current.left) 
                current.left.parent = current.parent;
            
            current.parent = node.parent;
            current.left = node.left;
            current.right = node.right;

            if (null != node.left) 
                node.left.parent = current;
            
            if (null != node.right) 
                node.right.parent = current;
            

            if (null == node.parent) 
                this.root = current;
             else if (node == node.parent.left) 
                node.parent.left = current;
             else if (node == node.parent.right) 
                node.parent.right = current;
            

            // 清理被删除节点的关联引用
            node.left = null;
            node.right = null;
            node.parent = null;
        
    

    /**
     * 计算map的键值对数量。
     * @return map的键值对数量。
     */
    public int size() 
        return this.keyList().size();
    

    /**
     * 清空map,删除所有的键值对。
     */
    public void clear() 
        List<K> keyList = this.keyList();
        if (null != keyList && !keyList.isEmpty()) 
            for (K key : keyList) 
                this.remove(key);
            
        
    

    private void showTree(BstTreeMapNode node, int level, String prefix) 
        if (null == node) 
            return;
        
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < level; i++) 
            sb.append("  ");
        
        sb.append(prefix);
        sb.append(node.key).append("         ");
        if (node.parent != null) 
            sb.append(node.parent.key);
        
        System.out.println(sb);
        level++;
        showTree(node.left, level, "left : ");
        showTree(node.right, level, "right: ");
    

    /**
     * 打印树形结构。
     */
    public void showTree() 
        if (null == root) 
            System.out.println("null");
        
        showTree(root, 0, "root: ");
    




测试例子

TestBST

package zhangchao.bst;

import java.util.Comparator;
import java.util.List;

public class TestBST 
    public static void test1() 
        BstTreeMap<Integer, String> map = new BstTreeMap<>( (o1, o2) -> (o1 - o2) );
        int[] arr = new int[]8,3,6,1,2,98,2,6;
        for (int i : arr) 
            map.put(i, "__" + String.valueOf(i));
        

        System.out.println(map.get(3));
        System.out.println(map.get(6));
        System.out.println(map.get(98));

        List<Integer> keyList = map.keyList();
        for (Integer key : keyList) 
            String value = map.get(key);
            System.out.println(key + " : " + value);
        
        System.out.println();
        map.showTree();

        map.remove(2);
        System.out.println(map.get(2));
    


    public static void test2() 
        BstTreeMap<String, String> map = new BstTreeMap(new Comparator<String>() 
            @Override
            public int compare(String o1, String o2) 
                if (null == o1 && null == o2) 
                    return 0;
                
                if (null == o1 && null != o2) 
                    return -1;
                
                if (null != o1 && null == o2) 
                    return 1;
                
                return o1.compareTo(o2);
            
        );

        String[] arr = "j", "h", 以上是关于182Java8利用二叉查找树实现Map的主要内容,如果未能解决你的问题,请参考以下文章

TreeMap和TreeSet即Java中利用二叉搜索树实现的Map和Set

容器————unordered_map

二叉查找树python实现

平衡二叉查找树AVL

平衡二叉树插入操作的详细过程图解

二叉搜索树(BST)---python实现