一直对AVL这个英文缩写比较困惑,原来一直以为是平衡二叉树的首字母缩写,但是又想不明白,哈!前段时间才明白原来是种这课树的三个人的名字的首字母的,哎,生活处处有惊喜,无知不可怕,现在我也知道了。废话不多说,下面我们说说,树形结构中的那些平衡二叉树。

二叉排序树

树的遍历顺序有3种,二叉排序树,顾名思义,就是一颗有序的二叉树,是一种按照中序遍历树中节点,而输出有序队列的一种树形结构,一种特殊的树形结构。


定义

对于二叉树,假设x为二叉树中的任意一个结点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个结点,则key[y] <= key[x];如果y是x的右子树的一个结点,则key[y] >= key[x]。那么,这棵树就是二叉排序树


二叉查找树是可以不平衡的!!!

杂谈:大多数人都称之为二叉查找树或者* 二叉搜索树*,从这一点,可以看出,其实并没有人用这种方式来进行数据的排序,而是在做查找或者是搜索的时候,常常使用,这也是它最为常见的应用场景。


性质

(01) 若任意节点的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
(02) 任意节点的右子树不空,则右子树上所有结点的值均大于它的根结点的值;
(03) 任意节点的左、右子树也分别为二叉查找树;
(04) 没有键值相等的节点(no duplicate nodes);


建立

建立二叉查找树,就是要定义树形的结构,本文中的树形结构包括左右子树,父指针,节点权值,详细请见后面代码。


查找

按照左小右大的规则进行查找。

/** (递归实现)查找"二叉树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);elsereturn x;
}public BSTNode<T> search(T key) {return search(mRoot, key);
}
/** (非递归实现)查找"二叉树x"中键值为key的节点*/
private BSTNode<T> iterativeSearch(BSTNode<T> x, T key) {while (x!=null) {int cmp = key.compareTo(x.key);if (cmp < 0) x = x.left;else if (cmp > 0) x = x.right;elsereturn x;}return x;
}public BSTNode<T> iterativeSearch(T key) {return iterativeSearch(mRoot, key);
}

插入

整个插入的过程如上图所示,简单的一句话就是,先来的就是根节点,比根节点小的在左子树,比根节点大的在右子树,所以也就注定了,这种方式形成的树不是一颗二叉平衡树。

/* * 将结点插入到二叉树中** 参数说明:*     tree 二叉树的*     z 插入的结点*/
private void insert(BSTree<T> bst, BSTNode<T> z) {int cmp;BSTNode<T> y = null;BSTNode<T> x = bst.mRoot;// 查找z的插入位置while (x != null) {y = x;cmp = z.key.compareTo(x.key);if (cmp < 0)x = x.left;elsex = x.right;}z.parent = y;if (y==null)bst.mRoot = z;else {cmp = z.key.compareTo(y.key);if (cmp < 0)y.left = z;elsey.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);
}

删除


上图中,是比较简单的一种删除节点的情况,在二叉查找树中,删除的情况总共分为三种:
1、删除节点的左子树为null,直接用右子树进行替换删除节点;
2、删除节点的右子树为null,直接用左子树进行替换;
3、删除节点 z 的左右子树都不为null,则查找要删除节点右子树的最小元素,调整取走最小元素 y 的局部结构,用 y 节点的右节点代替y(其实右节点就是空,都是最小了,哪还有右节点),局部结构调整完毕;然后用 y 来代替 z 节点,完毕。需要注意的一点是,在这个操作中,会涉及到父指针的操作,千万不要忘记

/* * 删除结点(z),并返回被删除的结点** 参数说明:*     bst 二叉树*     z 删除的结点*/
private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) {BSTNode<T> x=null;BSTNode<T> y=null;if ((z.left == null) || (z.right == null) )y = z;elsey = successor(z);if (y.left != null)x = y.left;elsex = y.right;if (x != null)x.parent = y.parent;if (y.parent == null)bst.mRoot = x;else if (y == y.parent.left)y.parent.left = x;elsey.parent.right = x;if (y != z) z.key = y.key;return y;
}/* * 删除结点(z),并返回被删除的结点** 参数说明:*     tree 二叉树的根结点*     z 删除的结点*/
public void remove(T key) {BSTNode<T> z, node; if ((z = search(mRoot, key)) != null)if ( (node = remove(this, z)) != null)node = null;
}

完整的二叉搜索树代码如下 :

/*** Java 语言: 二叉查找树** @author skywang* @date 2013/11/07*/public class BSTree<T extends Comparable<T>> {private BSTNode<T> mRoot;    // 根结点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;}}public BSTree() {mRoot=null;}/** 前序遍历"二叉树"*/private void preOrder(BSTNode<T> tree) {if(tree != null) {System.out.print(tree.key+" ");preOrder(tree.left);preOrder(tree.right);}}public void preOrder() {preOrder(mRoot);}/** 中序遍历"二叉树"*/private void inOrder(BSTNode<T> tree) {if(tree != null) {inOrder(tree.left);System.out.print(tree.key+" ");inOrder(tree.right);}}public void inOrder() {inOrder(mRoot);}/** 后序遍历"二叉树"*/private void postOrder(BSTNode<T> tree) {if(tree != null){postOrder(tree.left);postOrder(tree.right);System.out.print(tree.key+" ");}}public void postOrder() {postOrder(mRoot);}/** (递归实现)查找"二叉树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);elsereturn x;}public BSTNode<T> search(T key) {return search(mRoot, key);}/** (非递归实现)查找"二叉树x"中键值为key的节点*/private BSTNode<T> iterativeSearch(BSTNode<T> x, T key) {while (x!=null) {int cmp = key.compareTo(x.key);if (cmp < 0) x = x.left;else if (cmp > 0) x = x.right;elsereturn x;}return x;}public BSTNode<T> iterativeSearch(T key) {return iterativeSearch(mRoot, key);}/* * 查找最小结点:返回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;}/* * 查找最大结点:返回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;}/* * 找结点(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的后继结点"。BSTNode<T> y = x.parent;while ((y!=null) && (x==y.right)) {x = y;y = y.parent;}return y;}/* * 找结点(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的前驱结点"。BSTNode<T> y = x.parent;while ((y!=null) && (x==y.left)) {x = y;y = y.parent;}return y;}/* * 将结点插入到二叉树中** 参数说明:*     tree 二叉树的*     z 插入的结点*/private void insert(BSTree<T> bst, BSTNode<T> z) {int cmp;BSTNode<T> y = null;BSTNode<T> x = bst.mRoot;// 查找z的插入位置while (x != null) {y = x;cmp = z.key.compareTo(x.key);if (cmp < 0)x = x.left;elsex = x.right;}z.parent = y;if (y==null)bst.mRoot = z;else {cmp = z.key.compareTo(y.key);if (cmp < 0)y.left = z;elsey.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);}/* * 删除结点(z),并返回被删除的结点** 参数说明:*     bst 二叉树*     z 删除的结点*/private BSTNode<T> remove(BSTree<T> bst, BSTNode<T> z) {BSTNode<T> x=null;BSTNode<T> y=null;if ((z.left == null) || (z.right == null) )y = z;elsey = successor(z);if (y.left != null)x = y.left;elsex = y.right;if (x != null)x.parent = y.parent;if (y.parent == null)bst.mRoot = x;else if (y == y.parent.left)y.parent.left = x;elsey.parent.right = x;if (y != z) z.key = y.key;return y;}/* * 删除结点(z),并返回被删除的结点** 参数说明:*     tree 二叉树的根结点*     z 删除的结点*/public void remove(T key) {BSTNode<T> z, node; if ((z = search(mRoot, key)) != null)if ( (node = remove(this, z)) != null)node = null;}/** 销毁二叉树*/private void destroy(BSTNode<T> tree) {if (tree==null)return ;if (tree.left != null)destroy(tree.left);if (tree.right != null)destroy(tree.right);tree=null;}public void clear() {destroy(mRoot);mRoot = null;}/** 打印"二叉查找树"** key        -- 节点的键值 * direction  --  0,表示该节点是根节点;*               -1,表示该节点是它的父结点的左孩子;*                1,表示该节点是它的父结点的右孩子。*/private void print(BSTNode<T> tree, T key, int direction) {if(tree != null) {if(direction==0)    // tree是根节点System.out.printf("%2d is root\n", tree.key);else                // tree是分支节点System.out.printf("%2d is %2d's %6s child\n", tree.key, key, direction==1?"right" : "left");print(tree.left, tree.key, -1);print(tree.right,tree.key,  1);}}public void print() {if (mRoot != null)print(mRoot, mRoot.key, 0);}
}

文中代码和图参考自如果天空不死

二叉树--二叉搜索树相关推荐

  1. C++数据结构和算法2 栈 双端/队列 冒泡选择插入归并快排 二三分查找 二叉树 二叉搜索树 贪婪 分治 动态规划

    C++数据结构和算法2 栈 双端/队列 冒泡选择插入归并快排 二三分查找 二叉树 二叉搜索树 贪婪 分治 动态规划 博文末尾支持二维码赞赏哦 _ github 章3 Stack栈 和 队列Queue= ...

  2. [二叉树]二叉搜索树转换为双向链表(剑指Offer26)

    [试题描述] 将二叉搜索树转换为双向链表 对于二叉搜索树,可以将其转换为双向链表,其中,节点的左子树指针在链表中指向前一个节点,右子树指针在链表中指向后一个节点. 思路一: 采用递归思想,对于二叉搜索 ...

  3. 【学透二叉树-二叉搜索树(二叉树)的最近公共祖先】

    示例: 代码实现: class Solution {public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q ...

  4. LeetCode刷题笔记 二叉树 二叉搜索树的操作

    669 修剪二叉搜索树 ​ 给定一个二叉查找树和两个整数 L 和 R,且 L < R,试修剪此二叉查找树,使得修剪后所有节点的值都在 [L, R] 的范围内. ​ 输入是一个二叉查找树和两个整数 ...

  5. 五.树,二叉树,二叉搜索树(BST)和自平衡二叉搜索树(AVL)

    1.树 树是一种数据结构 比如:目录结构 树是一种可以递归定义的数据结构 树是由n个节点组成的集合: 如果 n=0, 那这是一颗空树 如果 n>0, 那存在1个节点作为树的根节点,其他节点可以分 ...

  6. 二叉搜索树的简明实现(ES5 ES6)

    二叉树 & 二叉搜索树 二叉树(Binary Tree)是 n(n >= 0)个节点的有限集合,集合为空集时,叫作空二叉树:不为空时,由根节点及左子树.右子树组成,左子树.右子树也都是二 ...

  7. 二叉搜索树的深度与搜索效率图解

    二叉搜索树的深度与搜索效率 二叉搜索树也可称为二叉查找树,它的常用方法可以参考:二叉查找树 我们在树, 二叉树, 二叉搜索树中提到,一个有n个节点的二叉树,它的最小深度为log(n),最大深度为n.比 ...

  8. 二叉树:二叉搜索树实现 逆序数问题

    关于逆序数的问题描述如下: 已知数组nums,求新数组count,count[i]代表了在nums[i]右侧且比 nums[i]小的元素个数. 例如: nums = [5, 2, 6, 1], cou ...

  9. 二叉树:二叉搜索树的编码和解码

    二叉搜索树的编码和解码描述: 编码:即将一个二叉搜索树编码,节点数值转换为字符串 解码:即将一个字符串解码,数值转换为对应的二叉搜索树的节点 过程导图如下: 针对性编码实现如下: /*数字转字符串*/ ...

最新文章

  1. php创建类用什么关键字,PHP面向对象开发之类的常用关键字
  2. 前端基础之设计一个个人工作室介绍界面
  3. QT的QFileDialog类的使用
  4. php性能优化分析工具XDebug 大型网站调试工具
  5. 使用CSS3属性aspect-ratio做横屏检测优化用户体验,附demo完整代码
  6. 神经网络中的病态曲率-Pathological Curve-举例
  7. jdbc java数据库连接 3)Statement接口之执行DDL和DML语句的简化
  8. oracle symonym_Oracle的同义词(synonyms)
  9. 【CodeForces - 574D】Bear and Blocks (dp,思维)
  10. qt android程序联网死机,Qt for Android(九) ——APP 崩溃卡死拉起保活实战
  11. 1433 mssql 安全_mssqlsql2008安全配置又一给力教程
  12. LINUX 软件安装。
  13. worldwind java 教程,如何脱机使用World Wind Java SDK
  14. C# winform excel根据当前选中内容,自动插入/编辑批注
  15. JAVA WEB开发技术作业 HTML国家奖学金申请审批表
  16. Redhat、Fedora、CentOS、OEL之间的关系与不同。
  17. php yi ju hua,汉音对照 这句话应该如何翻译? zhe ju hua ying gai ru he fan yi ? - 王朝网络 - wangchao.net.cn...
  18. linux 6.5光驱是什么意思,linux 6和5有什么不同
  19. CentOS8 KVM USB设备直通虚拟机并实现热插拨
  20. ProGuard入门

热门文章

  1. 微信卡片分享链接制作工具静态模板
  2. 【逗老师的无线电】MMDVM串口屏相关开发
  3. 常用坐标系及坐标系之间的变换
  4. 不同坐标系之间的转换
  5. 爆款app们是如何做主动拉新和被动拉新的?
  6. 2022年全球市场单相交流变频器总体规模、主要生产商、主要地区、产品和应用细分研究报告
  7. JS--文章置顶功能
  8. nginx设置图片跨域访问
  9. Ubuntu安装破解版MATLAB及问题解决
  10. 基于STM32F429的SDRAM使用