一、二叉排序树的定义 二叉排序树(Binary Sort Tree)又称二叉查找(搜索)树(Binary Search Tree)。其定义为:二叉排序树或者是空树,或者是知足以下性质的二叉树: ①若它的左子树非空,则左子树上全部结点的值均小于根结点的值; ②若它的右子树非空,则右子树上全部结点的值均大于根结点的值; ③左、右子树自己又各是一棵二叉排序树。 上述性质简称二叉排序树性质(BST性质),故二叉排序树其实是知足BST性质的二叉树。 二、二叉排序树的特色 由BST性质可得: (1) 二叉排序树中任一结点x,其左(右)子树中任一结点y(若存在)的关键字必小(大)于x的关键字。 (2) 二叉排序树中,各结点关键字是唯一的。 注意: 实际应用中,不能保证被查找的数据集中各元素的关键字互不相同,因此可将二叉排序树定义中BST性质(1)里的"小于"改成"大于等于",或将BST性质(2)里的"大于"改成"小于等于",甚至可同时修改这两个性质。 (3) 按中序遍历该树所获得的中序序列是一个递增有序序列。 ①二叉排序树插入新结点的过程 在二叉排序树中插入新结点,要保证插入后仍知足BST性质。其插入过程是: (a)若二叉排序树T为空,则为待插入的关键字key申请一个新结点,并令其为根; (b)若二叉排序树T不为空,则将key和根的关键字比较: (i)若两者相等,则说明树中已有此关键字key,无须插入。 (ii)若key<T→key,则将key插入根的左子树中。 (iii)若key>T→key,则将它插入根的右子树中。 子树中的插入过程与上述的树中插入过程相同。如此进行下去,直到将key做为一个新的叶结点的关键字插入到二叉排序树中,或者直到发现树中已有此关键字为止。 注意: 输入序列决定了二叉排序树的形态。 二叉排序树的中序序列是一个有序序列。因此对于一个任意的关键字序列构造一棵二叉排序树,其实质是对此关键字序列进行排序,使其变为有序序列。"排序 树"的名称也由此而来。一般将这种排序称为树排序(Tree Sort),能够证实这种排序的平均执行时间亦为O(nlgn)。 对相同的输入实例,树排序的执行时间约为堆排序的2至3倍。所以在通常状况下,构造二叉排序树的目的并不是为了排序,而是用它来加速查找,这是由于在一 个有序的集合上查找一般比在无序集合上查找更快。所以,人们又经常将二叉排序树称为二叉查找树。 public class BinarySortTree { private int data; private BinarySortTree lChild; private BinarySortTree rChild; public BinarySortTree(int data){ this.data = data; lChild = null; rChild = null; } public BinarySortTree(){ this.data = 0; lChild = null; rChild = null; } /** * 方法名称:createTree() * 方法描述:根据数组中的数据信息生成一个二叉查找树 * @param * @return String * @Exception */ public BinarySortTree createTree(int[] datas){ BinarySortTree root = new BinarySortTree(datas[0]); for(int i=1;i<datas.length;i++){ insertTree(root, datas[i]); } return root; } /** * 方法名称:insertTree() * 方法描述:向二叉排序树种插入数据 * @param * @return String * @Exception */ private void insertTree(BinarySortTree root, int data) { // TODO Auto-generated method stub BinarySortTree child = null; if(root != null){ if(data < root.data){ if(root.lChild == null){ child = new BinarySortTree(data); root.lChild = child; }else{ insertTree(root.lChild, data); } }else if(data > root.data){ if(root.rChild == null){ child = new BinarySortTree(data); root.rChild = child; }else{ insertTree(root.rChild, data); } }else{ return ; } } } /** * 方法名称:inOrder() * 方法描述:中序遍历 * @param * @return String * @Exception */ public void inOrder(BinarySortTree root){ if(root != null){ inOrder(root.lChild); System.out.print(root.data + " "); inOrder(root.rChild); } } /** * 方法名称:search() * 方法描述:查找元素 * @param * @return String * @Exception */ public boolean search(BinarySortTree root, int data){ if(root != null){ if(root.data == data){ return true; }else if(root.data < data){ return search(root.rChild, data); }else { return search(root.lChild, data); } } return false; } /** * 方法名称:delete() * 方法描述:删除节点 * @param 采用递归的方式进行删除 * @return String * @Exception */ public void delete(BinarySortTree root, int data){ if(root != null){ if(root.data < data){ //查找右孩子 delete(root.rChild,data); }else if(root.data > data){ delete(root.lChild,data); }else{ deleteNode(root); } } } /** * 方法名称:deleteNode() * 方法描述:执行具体的删除操做 * @param * @return String * @Exception */ private void deleteNode(BinarySortTree p) { // TODO Auto-generated method stub if(p != null){ //若是节点有左子树 /*1。若p有左子树,找到其左子树的最右边的叶子结点r,用该叶子结点r来替代p,把r的左孩子 做为r的父亲的右孩子。 2。若p没有左子树,直接用p的右孩子取代它。*/ if(p.lChild != null){ BinarySortTree r = p.lChild; BinarySortTree prev = p.lChild; while(r.rChild != null){ prev = r; r = r.rChild; } p.data = r.data; //若r不是p的左子树,p的左子树不变,r的左子树做为r的父节点的右孩子节点 if(prev != r){ prev.rChild = r.lChild; }else{ //若r是p的左子树,则p的左子树只想r的左子树 p.lChild = r.lChild; } }else{ p = p.rChild; } } } public static void main(String[] args){ BinarySortTree root = new BinarySortTree(); int[] datas = {14,9,17,16};//{63,90,70,55,67,42,98,83,10,45,58}; root = root.createTree(datas); root.inOrder(root); System.out.println(); System.out.println(root.search(root, 98)); root.delete(root, 17); root.inOrder(root); } }
其中删除部分思想参考该文:blog.csdn.net/arcsinsin/article/details/10238505 java
文字部分的引用文章为:http://sjjp.tjuci.edu.cn/sjjg/DataStructure/DS/web/chazhao/chazhao9.1.1.htm web