二叉查找树

二叉查找树定义

二叉查找树(Binary Search Tree), 也称为二叉搜索树, 有序二叉树(ordered binary tree), 排序二叉树(sorted binary tree), 是指一颗空树或具有以下性质的二叉树:
1. 任意节点的左子树不空, 则左子树上所有节点的值均小于它的根节点的值
2. 任意节点的右子树不空, 则右子树上所有节点均大于它的根节点的值
3. 任意节点的左,右子树也分别为二叉查找树
4. 没有键值相等的节点

二叉查找树通常采用二叉链表作为二叉查找树的存储结构, 相比于其他数据结构的优势在于查找,插入时间复杂度较低, 为O(log n). 它是基础的数据结构, 用于构建 红黑数, B-Tree, B+Tree, B*Tree等.

二叉查找树的Java实现
1. 二叉查找树节点定义
public class BSTNode<T extends Comparable<T>> {
    T key;                // 关键字(键值)
    BSTNode<T> left;    // 左孩子
    BSTNode<T> right;    // 右孩子
    BSTNode<T> parent;    // 父结点

    public BSTNode(T key, BSTNode<T> parent, BSTNode<T> left, BSTNode<T> right) {
        this.key = key;
        this.parent = parent;
        this.left = left;
        this.right = right;
    }

    public T getKey() {
        return key;
    }

    public String toString() {
        return "key:"+key;
    }
}

BSTNode是二叉查找树的内部节点, 它包含以下信息:

  1. key 对二叉树进行排序的依据
  2. left 左边子节点
  3. right 右边子节点
  4. parent 当前节点的父节点
2. 二叉查找树的查找
/*
 * (递归实现)查找"二叉树x"中键值为key的节点
 */
private BSTNode<T> search(BSTNode<T> x, T key) {
    if (x==null)
        return x;

    int cmp = key.compareTo(x.key);
    if (cmp < 0)
        return search(x.left, key);
    else if (cmp > 0)
        return search(x.right, key);
    else
        return x;
}

public BSTNode<T> search(T key) {
    return search(mRoot, key);
}

search 的过程比较简单, 从根节点开始, 根据给定的key与节点的key值进行比较, 直到 "cmp" = 0 或节点x = 0.

3. 查找最大值, 最小值

最大值

/*
 * 查找最大结点:返回tree为根结点的二叉树的最大结点。
 */
private BSTNode<T> maximum(BSTNode<T> tree) {
    if (tree == null)
        return null;

    while(tree.right != null)
        tree = tree.right;
    return tree;
}

public T maximum() {
    BSTNode<T> p = maximum(mRoot);
    if (p != null)
        return p.key;

    return null;
}

最小值

/*
 * 查找最小结点:返回tree为根结点的二叉树的最小结点。
 */
private BSTNode<T> minimum(BSTNode<T> tree) {
    if (tree == null)
        return null;

    while(tree.left != null)
        tree = tree.left;
    return tree;
}

public T minimum() {
    BSTNode<T> p = minimum(mRoot);
    if (p != null)
        return p.key;

    return null;
}
4. 查找前继节点(predecessor) 后继节点(successor)

查找前继节点

/*
 * 找结点(x)的前继结点。即,查找"二叉树中数据值小于该结点"的"最大结点"。
 */
public BSTNode<T> predecessor(BSTNode<T> x) {
    // 如果x存在左孩子,则"x的前继结点"为 "以其左孩子为根的子树的最大结点"。
    if (x.left != null)
        return maximum(x.left);

    // 如果x没有左孩子。则x由分以下两种情况讨论:
    // (01) x是"一个右孩子",则"x的前驱结点"为 "它的父结点"。
    // (01) x是"一个左孩子",则查找"x的最低的父结点,并且x在该父结点右子树上孩子或是其又子节点",找到的这个"最低的父结点"就是"x的前继结点"。
    BSTNode<T> y = x.parent;
    while ((y!=null) && (x==y.left)) {
        x = y;
        y = y.parent;
    }

    return y;
}

查找后继节点

/*
 * 找结点(x)的后继结点。即,查找"二叉树中数据值大于该结点"的"最小结点"。
 */
public BSTNode<T> successor(BSTNode<T> x) {
    // 如果x存在右孩子,则"x的后继结点"为 "以其右孩子为根的子树的最小结点"。
    if (x.right != null)
        return minimum(x.right);

    // 如果x没有右孩子。则x分以下两种情况进行讨论:
    // (01) x是"一个左孩子",则"x的后继结点"为 "它的父结点"。
    // (02) x是"一个右孩子",则查找"x的最低的父结点,并且x是该父结点左子树上的孩子节点或直接是左子节点",找到的这个"最低的父结点"就是"x的后继结点"。
    BSTNode<T> y = x.parent;
    while ((y!=null) && (x==y.right)) {
        x = y;
        y = y.parent;
    }

    return y;
}
5. 插入节点

/*
 * 将结点插入到二叉树中
 *
 * 参数说明:
 *     tree 二叉树的
 *     z 插入的结点
 */
private void insert(BSTree<T> bst, BSTNode<T> z) {
    int cmp;
    BSTNode<T> y = null;
    BSTNode<T> x = bst.mRoot;

    // 1. 查找z的插入位置
    while (x != null) {
        y = x;
        cmp = z.key.compareTo(x.key);
        if (cmp < 0)
            x = x.left;
        else
            x = x.right;
    }

    //2. 根据位置决定放在root节点, y的左/右边
    z.parent = y;
    if (y==null) // y是null
        bst.mRoot = z;
    else {
        cmp = z.key.compareTo(y.key);
        if (cmp < 0)
            y.left = z;
        else
            y.right = z;
    }
}

/*
 * 新建结点(key),并将其插入到二叉树中
 *
 * 参数说明:
 *     tree 二叉树的根结点
 *     key 插入结点的键值
 */
public void insert(T key) {
    BSTNode<T> z=new BSTNode<T>(key,null,null,null);

    // 如果新建结点失败,则返回。
    if (z != null)
        insert(this, z);
}
5. 删除节点
/*
 * 删除结点(z),并返回被删除的结点
 *
 * 参数说明:
 *     bst 二叉树
 *     z 删除的结点
 */
private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) {
    BSTNode<T> x=null;
    BSTNode<T> y=null;
    /** 1. 待删除节点情况
     * 1) 节点z最多一个子节点, 则删除z后将对应子节点代替原来的位置
     * 2) 节点有两个子节点, 调用 successor方法获取其后继节点, 后继节点代替原来的那个节点
     */
    if ((z.left == null) || (z.right == null) )
        y = z; // 节点z最多有一个子节点
    else{
        // 这里有个知识点, 既然y是后继节点, 则 y 必定没有两个子节点
        y = successor(z); // 节点z有两个子节点, 则调用 successor 查询z对应的子节点
    }

    // 2. 将待删除节点的子节点赋值给x
    if (y.left != null)
        x = y.left;
    else
        x = y.right;
    /**
     * x 情况
     * 1. x是被删除节点的子节点
     * 2. x是被删除节点的后继节点的子节点
     */
    if (x != null) {
        x.parent = y.parent;
    }

    // y.parent == null, 则说明y是mRoot节点
    if (y.parent == null)
        bst.mRoot = x;
    else if (y == y.parent.left)
        y.parent.left = x;
    else
        y.parent.right = x;

    // 若y是z的后继节点
    if (y != z) {
        z.key = y.key;
    }

    return y;
}
6. 二叉查找树完整实现代码

二叉查找树Java实现 BSTree.java

总结

二叉查找树总体实现比较简单, 但这是学习 RBTree, B-Tree, B+Tree 等数据结构的基础

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容