二叉查找树

二叉查找(搜索)树(Binary Search Tree)又称二叉排序树(Binary Sort Tree),是基于二叉树,BST具有下列性质:
1、若左子树不空,则其左子树上的所有结点的值均小于根结点的值;
2、若右子树不空,则其右子树上的所有结点的值均大于根结点的值;
3、左、右子树也分别为二叉查找树。

结点类

public class BinaryNode {  
    Integer data;  
    BinaryNode leftChild;  
    BinaryNode rightChild;  
  
    public BinaryNode() {  
    }  
  
    public BinaryNode(int data) {  
        leftChild = null;  
        rightChild = null;  
        this.data = data;  
    }  
  
    public BinaryNode(Integer data, BinaryNode leftChild, BinaryNode rightChild) {  
        this.data = data;  
        this.leftChild = leftChild;  
        this.rightChild = rightChild;  
    }  
}

二叉查找树实现类

public class BinarySearchTree {  
    private BinaryNode root;  
    List<BinaryNode> nodeList = new LinkedList<BinaryNode>();  
  
    //相关方法 。。。。  
}

1、插入操作

/** 
 * 非递归插入操作x的过程如下: 
 * 1、若b是空树,则直接将插入的结点作为根结点插入。 
 * 2、x等于b的根结点的数据的值,则直接返回,否则。 
 * 3、若x小于b的根结点的数据的值,则将x要插入的结点的位置改变为b的左子树,否则。 
 * 4、将x要出入的结点的位置改变为b的右子树。 
 */  
public boolean insert(Integer value) {  
    if (root == null) {  
        root = new BinaryNode(value);   //新构造一个二叉查找树  
        nodeList.add(root);  
  
    } else {  
        BinaryNode parent = null;  
        BinaryNode current = root;  
  
        while (current != null) {  
            //compareTo就是比较两个值,如果前者大于后者,返回1,等于返回0,小于返回-1  
            if (value.compareTo(current.data) == -1) {  
                parent = current;  
                current = current.leftChild;  
  
            } else if (value.compareTo(current.data) == 1) {  
                parent = current;  
                current = current.rightChild;  
                  
            } else  
                return false;  
        }  
  
        if (value.compareTo(parent.data) == -1)  
            parent.leftChild = new BinaryNode(value);  
        else  
            parent.rightChild = new BinaryNode(value);  
  
        nodeList.add(parent);  
    }  
    return true;  
}

递归插入:

/** 
 * 递归插入: 得到的nodeList的size不是插入数据的大小!!! 
 */  
public BinaryNode recursiveInsert(Integer value) {  
    return recursiveInsert(value, this.root);  
}  
  
private BinaryNode recursiveInsert(Integer value, BinaryNode node) {  
    if (root == null)  
        root = new BinaryNode(value);   //新构造一个二叉查找树  
  
    if (node == null)  //如果是叶节点,则没有孩子  
        return new BinaryNode(value, null, null);  
  
    int result = value.compareTo(node.data);  
  
    /alue小于node.data返回-1  
    if (result == -1) {  
        node.leftChild = recursiveInsert(value, node.leftChild);  
  
    } else if (result == 1) {  
        node.rightChild = recursiveInsert(value, node.rightChild);  
    }  
  
    nodeList.add(node);  
    return node;  
}

测试:

@Test  
public void test() {  
    BinarySearchTree tree = new BinarySearchTree();  
    BinarySearchTree tree1 = new BinarySearchTree();  
    int[] keys = new int[] { 8, 3, 10, 1, 6, 14, 4, 7, 13 };  
  
    for (int key:keys){  
        tree.insert(key);  
        tree1.recursiveInsert(key);  
    }  
  
    List<BinaryNode> list = tree.getBinarySearchTree();  
    List<BinaryNode> list1 = tree1.getBinarySearchTree();  
  
    System.out.println("非递归插入节点后,树的大小:"+ list.size());  
    System.out.println("递归插入节点后,树的大小:" + list1.size());  
}

非递归插入节点后,树的大小:9
递归插入节点后,树的大小:17

2、删除操作

对于二叉查找树的删除操作(这里根据值删除,而非结点)分三种情况:
不过在此之前,我们应该确保根据给定的值找到了要删除的结点,如若没找到该结点不会执行删除操作!这里暂时没有考虑
下面三种情况假设已经找到了要删除的结点。
1、如果结点为叶子结点(没有左、右子树),此时删除该结点不会玻化树的结构直接删除即可,并修改其父结点指向它的引用为null.如下图:

2、如果其结点只包含左子树,或者右子树的话,此时直接删除该结点,并将其左子树或者右子树设置为其父结点的左子树或者右子树即可,此操作不会破坏树结构。

3、当结点的左右子树都不空的时候,一般的删除策略是用其右子树的最小数据(容易找到)代替要删除的结点数据并递归删除该结点(此时为null),因为右子树的最小结点不可能有左孩子,所以第二次删除较为容易。z的左子树和右子树均不空。找到z的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替z的值.如图:

实现代码:

public void remove(Integer value) {  
    this.root = remove(value,root);  
}  
  
/** 
 * 递归删除: 
 * 
 * eg:添加的节点顺序为8,3,9.删除根结点,返回值则为3 
 * @return 返回值始终是最新的根节点!!! 
 */  
private BinaryNode remove(Integer value, BinaryNode node) {  
    if (node == null)  
        return null;  
  
    int result = value.compareTo(node.data);  
  
    //result<0:表示需要删除的节点在左子树  
    if (result == -1) {  
        node.leftChild = remove(value, node.leftChild);  
  
    } else if (result == 1) {//在右子树  
        node.rightChild = remove(value, node.rightChild);  
  
    } else if (node.leftChild != null && node.rightChild != null) { //结点的左右子树都不时候  
        //先找到需要删除的节点下,右子树中最小的节点并将它的值赋给需要删除的节点。  
        node.data = findMin(node.rightChild).data;  //找出右子树最小值(因为右子树中的节点的值一定大于根节点)  
        //删除前面找到的最小的节点  
        node.rightChild = remove(node.data, node.rightChild);  
  
    }else {  
        //找到需要删除的节点且节点下有一个子节点(左或者右)  
        node = (node.leftChild != null) ? node.leftChild : node.rightChild;  
    }  
  
    return node;  
}

3、查找

/** 
 * 在二叉查找树中查找x的过程如下: 
 * 1、若二叉树是空树,则查找失败。 
 * 2、若x等于根结点的数据,则查找成功,否则。 
 * 3、若x小于根结点的数据,则递归查找其左子树,否则。 
 * 4、递归查找其右子树。 
 */  
public boolean find(Integer value) {  
    return contains(value, this.root);  
}  
  
private boolean contains(Integer value, BinaryNode node) {  
    if (node == null)  
        return false;  
  
    int result = value.compareTo(node.data); //-1,0,1  
    if (result == -1) {  
        return contains(value, node.leftChild); //递归查询左子树  
  
    }else if (result == 1) {  
        return contains(value, node.rightChild); //递归查询右子树  
  
    } else {  
        return true;  
    }  
}

4、其它相关方法

//获取二叉查找树  
public List<BinaryNode> getBinarySearchTree() {  
    return nodeList;  
}  
  
/** 
 * 找出最小的值 
 * @return 返回最小值 
 */  
public Integer findMin() {  
    return findMin(root).data;  
}  
private BinaryNode findMin(BinaryNode node) {  
    if (node == null)  
        return null;  
    else if (node.leftChild == null) //如果左孩子没有,只返回根结点  
        return node;  
  
    return findMin(node.leftChild);  
}  
  
/** 
 * 找出最大的值 
 */  
public Integer findMax() {  
    return findMax(root).data;  
}  
private BinaryNode findMax(BinaryNode node) {  
    if (node ==null)  
        return null;  
    else if (node.rightChild == null)  
        return node;  
    else  
        return findMax(node.rightChild);  
}  
  
  
public void inOrderTraverse() {  
    inOrderTraverse(root);  
}  
  
/** 
 * 递归中序排序: 
 * 二叉查找树中序排序后的二叉查找树是有序的 
 */  
public void inOrderTraverse(BinaryNode node) {  
    if (node != null) {  
        inOrderTraverse(node.leftChild);  
        System.out.print(node.data + " ");  
        inOrderTraverse(node.rightChild);  
    }  
}

时间: 2024-10-14 05:01:19

二叉查找树的相关文章

C语言实现二叉查找树

#include<stdio.h> #include<stdlib.h> /* * 数据结构:二叉查找树,即左孩子<父节点<右孩子 * C语言实现 * 2015-9-13 */ typedef struct TreeNode *PtrToNode; typedef PtrToNode Tree; typedef PtrToNode Position; struct TreeNode { int Element; Tree Left; //节点左孩子 Tree Right

按层遍历二叉查找树

<算法>中二叉查找树一节的习题:按层遍历二叉查找树. 可以使用队列来管理二叉查找树中的节点,节点按照如下方法入队出队: 节点x入队 当队列不为空时使用队列的第一个元素first 如果节点first.left不为空则将fisrt.left入队 如果节点first.right不为空则将first.right入队 将first节点出队 /** * Created by elvalad on 2014/12/5. * 按层遍历二叉查找树 */ import java.util.Iterator; im

二叉查找树BST 模板

二叉查找树BST 就是二叉搜索树 二叉排序树. 就是满足 左儿子<父节点<右儿子 的一颗树,插入和查询复杂度最好情况都是logN的,写起来很简单. 根据BST的性质可以很好的解决这些东西 1.查询值 int Search(int k,int x) { if(x<a[k].key && a[k].l) Search(a[k].l,x); else if(x>a[k].key && a[k].r) Search(a[k].r,x); else retur

平衡树初阶——AVL平衡二叉查找树+三大平衡树(Treap + Splay + SBT)模板【超详解】

平衡树初阶——AVL平衡二叉查找树 一.什么是二叉树 1. 什么是树. 计算机科学里面的树本质是一个树状图.树首先是一个有向无环图,由根节点指向子结点.但是不严格的说,我们也研究无向树.所谓无向树就是将有向树的所有边看成无向边形成的树状图.树是一种递归的数据结构,所以我们研究树也是按照递归的方式去研究的. 2.什么是二叉树. 我们给出二叉树的递归定义如下: (1)空树是一个二叉树. (2)单个节点是一个二叉树. (3)如果一棵树中,以它的左右子节点为根形成的子树都是二叉树,那么这棵树本身也是二叉

java 二叉查找树

//接口+抽象类+实现类package wangChaoPA实习工作练习.com.进阶篇.二叉查找树; import java.util.Iterator;public interface Tree<E extends Comparable<E>>{    // 从树中删除e    boolean delete(E e); // 树的大小    int getSize(); // 中序遍历树    void inorder(); // 把e插入到tree中    boolean i

二叉查找树C++实现

二分查找树特点: (1) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值: (2) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值: (3) 任意节点的左.右子树也分别为二叉查找树. (4) 没有键值相等的节点(no duplicate nodes). 前序遍历:中左右 中序遍历:左中右 序遍历:左右中 二叉查找树的重点在于如何找节点的前驱节点和后继节点 #pragma once #include <iostream> using namespace st

[二叉查找树] 二叉排序树

题目描述 输入一系列整数,建立二叉排序数,并进行前序,中序,后序遍历. 输入 输入第一行包括一个整数n(1<=n<=100).接下来的一行包括n个整数. 输出 可能有多组测试数据,对于每组数据,将题目所给数据建立一个二叉排序树,并对二叉排序树进行前序.中序和后序遍历.每种遍历结果输出一行.每行最后一个数据之后有一个空格. 样例输入 1 2 2 8 15 4 21 10 5 39 样例输出 2 2 2 8 15 8 15 15 8 21 10 5 39 5 10 21 39 5 10 39 21

图解数据结构(7)——二叉查找树及平衡二叉查找树(一共14篇)

这篇将是最有难度和挑战性的一篇,做好心理准备!十.二叉查找树(BST)前一篇介绍了树,却未介绍树有什么用.但就算我不说,你也能想得到,看我们Windows的目录结构,其实就是树形的,一个典型的分类应用.当然除了分类,树还有别的作用,我们可以利用树建立一个非常便于查找取值又非常便于插入删除的数据结构,这就是马上要提到的二叉查找树(Binary Search Tree),这种二叉树有个特点:对任意节点而言,左子(当然了,存在的话)的值总是小于本身,而右子(存在的话)的值总是大于本身. 这种特性使得我

二叉查找树 _ 二叉排序树 _ 二叉搜索树_C++

一.数据结构背景+代码变量介绍 二叉查找树,又名二叉排序树,亦名二叉搜索树 它满足以下定义: 1.任意节点的子树又是一颗二叉查找树,且左子树的每个节点均小于该节点,右子树的每个节点均大于该节点. 2.由1可推出,任意节点的左孩子小于该节点,右孩子大于该节点 以上讨论的是左(右)孩子(子树)存在的情况 它的中序遍历是一个升序的排序 在参考代码中,我们定义有: 主程序中,k代表插入或删除或查找的节点的值 root,根节点位置:a[i],第 i 号节点的值:cl[i],第 i 号节点左孩子的位置:cr