算法系列(八)数据结构之二叉查找树

来源:互联网 发布:linux使用 编辑:程序博客网 时间:2024/05/01 16:26
在算法系列(七)数据结构之树的基本结构和二叉树的遍历 中介绍了基本的树结构,二叉树的实现和遍历。
这篇文章重点学习一下二叉查找树。

概述

二叉排序树(Binary Sort Tree)又称二叉查找树(Binary Search Tree)二叉搜索树。
二叉查找树(BST)是二叉树的一个重要的应用,它在二叉树的基础上加上了这样的一个性质:对于树中的每一个节点来说,如果有左儿子的话,它的左儿子的值一定小于它本身的值,如果有右儿子的话,它的右儿子的值一定大于它本身的值。二叉查找树的操作一般有插入、删除和查找,这几个操作的平均时间复杂度都为O(logn),插入和查找操作很简单,删除操作会复杂一点。

由于树的递归定义,通常用递归实现一些操作,二叉查找树平均深度是O(logN),不必担心栈溢出。

定义

二叉查找树是一棵空树,或者是具有下列性质的二叉树:
(1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(3)左、右子树也分别为二叉查找树
(4)没有键值相等的结点。

代码实现基础

继承了上一篇文章中的树结构,增加了比较器。必须有明确的节点比较方法,否则无法进行基本操作。

package com.algorithm.tree;import java.util.Comparator;/** * 左子树小于右子树的二叉查找树 *  * @author chao * * @param <T> */public class BinarySeachTree<T> extends BinaryTree<T> {private Comparator<T> comparator;public BinarySeachTree(BinarySeachTree.BinaryTreeNode<T> root) {this(root, null);}public BinarySeachTree(BinarySeachTree.BinaryTreeNode<T> root, Comparator<T> comparator) {super(root);this.comparator = comparator;}private int compare(BinarySeachTree.BinaryTreeNode<T> a, BinarySeachTree.BinaryTreeNode<T> b) {if (comparator != null) {return comparator.compare(a.element, b.element);} else if (a.element instanceof Comparable && b.element instanceof Comparable) {return ((Comparable) a.element).compareTo(b.element);} else {throw new RuntimeException("can't compare " + a.element.getClass());}}}

插入操作

步骤:将X节点插入到树T中,当前比较节点为cur,插入节点为x,r。默认从根节点为初始节点开始比较,cur初始值为root,如果根节点为空,将x直接作为根节点。否则比较cur与x的大小,如果x比cur大,说明x在cur的右子树上,以cur.right为初始节点,继续做相同的操作。如果cur比x大,说明x在cur的左子树上,以cur.left为初始节点,继续做相同操作。
代码实现
/** * 从根节点插入一个新数据 *  * @param x * @return */public BinaryTreeNode<T> insert(BinaryTreeNode<T> x) {return insert(root, x);}/** * 从某一个节点插入新数据 *  * @param cur * @param x * @return */protected BinaryTreeNode<T> insert(BinaryTreeNode<T> cur, BinaryTreeNode<T> x) {if (cur == null) {return x;}int compareresult = compare(cur, x);if (compareresult < 0) {cur.right = insert(cur.right, x);} else if (compareresult > 0) {cur.left = insert(cur.left, x);}return cur;}

查找最大值与最小值

根据定义可以知道,最小值位于最左侧的叶子节点。最大值位于最右侧的叶子节点。
代码实现
/** * 查找最小节点 *  * @return */public BinaryTreeNode<T> findMin() {return findMin(root);}/** * 以node为根节点的最小节点 *  * @param node * @return */public BinaryTreeNode<T> findMin(BinaryTreeNode<T> node) {if (node == null) {return null;} else if (node.left == null) {return node;}return findMin(node.left);}/** * 查找最大节点 *  * @return */public BinaryTreeNode<T> findMax() {return findMax(root);}/** * 以node为根节点的最大节点 *  * @param node * @return */public BinaryTreeNode<T> findMax(BinaryTreeNode<T> node) {if (node == null) {return null;} else if (node.right == null) {return node;}return findMax(node.right);}


查找是否包含一个节点的操作

有点二分查找的意思。只是二分查找是线性的,查找树的查找是树形结构上的查找。
代码实现:
/** * 判断是否包含x *  * @param x * @return */public boolean contains(BinaryTreeNode<T> x) {return contains(root, x);}/** * 以某个节点为根节点判断是否包含x *  * @param cur * @param x * @return */public boolean contains(BinaryTreeNode<T> cur, BinaryTreeNode<T> x) {if (x == null || cur == null) {return false;}int compareresult = compare(cur, x);if (compareresult == 0) {return true;} else if (compareresult < 0) {return contains(cur.right, x);} else {return contains(cur.left, x);}}



删除操作

删除操作需要分情况讨论:
如果是叶子节点,可以直接删除。
如果只有一个孩子的话,就让它的父亲指向它的儿子,然后删除这个节点。

如果有两个孩子的话,一般的删除策略是用右子树最小的数据代替该节点的数据,递归删除那个节点。
代码实现
/** * 删除节点x *  * @param x * @return */public BinaryTreeNode<T> remove(BinaryTreeNode<T> x) {return remove(root, x);}/** * 删除子树中的节点x *  * @param cur * @param x * @return */public BinaryTreeNode<T> remove(BinaryTreeNode<T> cur, BinaryTreeNode<T> x) {if (cur == null || x == null) {return cur;}int compareresult = compare(cur, x);if (compareresult > 0) {cur.left = remove(cur.left, x);} else if (compareresult < 0) {cur.right = remove(cur.right, x);} else if (cur.left != null && cur.right != null) {BinaryTreeNode<T> minnode = findMin(cur.right);cur.right = remove(cur.right, minnode);cur.element = minnode.element;minnode = null;} else {cur = (cur.left == null) ? cur.right : cur.left;}return cur;}



删除的过程比较复杂,如果删除次数不多,通常使用的策略是惰性删除,即对删除的节点进行标记。特别是有重复项时非常有用,删除只是项的频率减1。暂时不做



代码实现可以看github,地址https://github.com/robertjc/simplealgorithm
github代码也在不断完善中,有些地方可能有问题,还请多指教

欢迎扫描二维码,关注公众账号


0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 荒野行动画面中间有条横怎么办 荒野行动pc闪退怎么办 幽灵行动荒野子弹没了怎么办 看门狗2枪没子弹怎么办 爱奇艺不小心删除了本地视频怎么办 80岁老太太就爱闹肚子怎么办? 皇牌空战5弹药不够怎么办 辐射4玩着头晕怎么办 官司打赢了法院不给钱怎么办 电脑玩dnf太卡怎么办 soul被禁止私聊怎么办 刺激战场空投挂树上怎么办 由于经济原因心态不好怎么办 公司经济不好不裁员怎么办 家里经济不好没有钱怎么办 银行柜员找不到工作怎么办 在球队中打替补怎么办 大学生毕业后找不到工作怎么办 30岁不敢换工作怎么办 投完简历没回复怎么办 工业废气一年总量超标怎么办 安监局行政处罚没能力交怎么办 被社会淘汰的人怎么办 宝宝吐奶的时候怎么办 网友要我发红包怎么办 电脑久了很慢怎么办 影驰显卡花屏怎么办 反恐精英全球攻势加载地图慢怎么办 老滚5视角锁死了怎么办 苹果描述文件没有了怎么办 苹果6s发热严重怎么办 苹果6s发烫严重怎么办 手机型号不适配全军出击怎么办? 苹果5版本过低怎么办 在泰国买到假货怎么办 在泰国旅游遇到危险该怎么办? 拾到小米手环怎么办 苹果充电打游戏触点怎么办 衣服上金属锈了怎么办 光之子门锁住了怎么办 挖到金矿石了该怎么办