小橙书阅读指南(十)——二叉查找树
算法描述:二叉查找树时一种能够将链表插入的灵活性和有序数组查找的高效性结合起来的符号表(SymbolTable)实现。具体来说,就是使用每个节点含有两个链接的二叉树来高效地实现符号表。一颗二叉查找树时一颗二叉树,其中每个节点都含有一个Comparable的键且每个节点的键都大于其左子树中的任意节点的键而小于右子树的任意节点的键。
一、查找
一般来说,在符号表中查找一个键只可能出现命中和未命中两种情况。一般通过递归算法在二叉树中查找,如果树时空的则查找未命中;如果被查找的键和根节点相等,查找命中,否则就在适当的子树中继续查找。
代码示例:
/** * 根据给定键获取值 * * @param key * @return */ public Value get(Key key) { return get(root, key); } private Value get(Node root, Key key) { if (root == null) { return null; } int cmp = key.compareTo(root.key); if (cmp < 0) { return get(root.left, key); } if (cmp > 0) { return get(root.right, key); } return root.val; }
二、插入
插入的特性和查找难度差不多。当查找一个不存在于树中的节点并结束于一条空链接时,我们需要做的就是将空链接指向一个含有被查找的键的新节点。如果查找不为空则该表当前节点的值。插入新的节点后需要沿搜索路径向上更新链接并增加节点计数器的值。
代码示例:
/** * 插入键值对 * * @param key * @param val */ public void put(Key key, Value val) { root = put(root, key, val); } /** * 插入操作调用的内部方法 * * @param root * @param key * @param val * @return */ private Node put(Node root, Key key, Value val) { // 如果是空节点则创建一个节点 if (root == null) { return new Node(key, val, 1); } // 如果节点非空则递归判断 int cmp = key.compareTo(root.key); if (cmp < 0) { root.left = put(root.left, key, val); } else if (cmp > 0) { root.right = put(root.right, key, val); } else { root.val = val; } root.size = size(root.left) + size(root.right) + 1; return root; }
三、遍历
二叉查找树的遍历通常使用中序遍历,中序遍历的顺序是:先遍历左子树,再遍历根节点,最后遍历右节点。
代码示例:
/** * 中序遍历方法 * * @return */ public List<Key> inOrder() { List<Key> keyList = new ArrayList<>(); inOrder(root, keyList); return keyList; } private void inOrder(Node root, List<Key> keyList) { if (root != null) { inOrder(root.left, keyList); keyList.add(root.key); inOrder(root.right, keyList); } }
算法总结:查找二叉树是一个补充结构,理解起来相对简单。BST是红黑树的基础。
相关链接: