二叉树就是每个节点最多有两个分叉的树。这里我们写一写一个典型的例子二叉搜索树,它存在的实际意义是什么呢?

在P1.1链表中,我们清楚了链表的优势是善于删除添加节点,但是其取值很慢;数组的优势是善于取值,但是不利于删除添加节点。

而二叉搜索树,正是两者的折中方案。首先,它是树状结构,因此它便于插入和删除节点,需要花费LogN级别的时间,其次,它

在每一个节点上都满足`左子树 <= 当前节点 <= 右子树`,因此便于使用二叉搜索,所以查找数据和取数据也是LogN级别的。

时间比较 链表 二叉搜索树 数组
取值 N LogN C
查找 N LogN 有序数组:LogN 无序数组:N
插入和删除 C LogN N

常见的二叉搜索树操作有:

1.插入新节点

2.按值查找节点

3.删除节点

4.三种遍历方式

5.二叉搜索树的宽度

6.二叉搜索树最大距离

TODO : 待解析

Java代码:

package ds4.binaryTree;import java.util.ArrayDeque;
import java.util.Queue;/*** 二叉搜索树*/
public class BinarySearchTree {static class Node {long data;Node left;Node right;public Node(long data) {this.data = data;}@Overridepublic String toString() {return "N["+data+"]";}}static class Tree{Node root;Tree(){}/*** 添加节点: 时间消耗LogN* @param node*/public void addNode(Node node){if(node == null){return;}if(this.root == null){this.root = node;return;}Node current = root;Node parent = current;while(current != null){parent = current;if(current.data >= node.data){current = current.left;}else{current = current.right;}}if(parent.data >= node.data){parent.left = node;}else{parent.right = node;}}/*** 查找节点* 时间消耗LogN* @param data* @return*/public Node fineNodeByVal(long data){Node result = null;if(this.root == null){return result;}Node current = this.root;while(current != null){if(current.data > data){current = current.left;}else if(current.data < data){current = current.right;}else{result = current;break;}}return result;}/*** 删除某个节点* @param node*/public void removeNode(Node node){if(this.root == null){return;}if(node == null){return;}if(this.root == node){this.root = null;node.left = node.right = null;return;}// 寻找其父节点Node current = root;Node parent = current;while(current != null){if(current == node){break;}parent = current;if(current.data < node.data){current = current.right;}else{current = current.left;}}if(current == null){System.out.println("没有找到这个节点!");return;}if(node.left == null && node.right == null){ //左右都为空// 找到其父节点直接删除即可if(parent.left == null){parent.left = null;}else{parent.right = null;}return;}else if(node.left != null && node.right == null){ // 左子树不为空,而右子树为空// 找到其父节点直接嫁接if(parent.left == null){parent.left = node.left;}else{parent.right = node.left;}}else if(node.right != null && node.left == null){ // 右子树不为空,左子树为空//找到父节点直接嫁接if(parent.right == node){parent.right = node.right;}else{parent.left = node.right;}}else{ // 左右子树都不为空//找到左枝最靠右节点,删除;并找到带删除父节点,将待删除节点用左枝最右节点替代Node current1 = node;Node parent1 = node;while (current1.right != null){parent1 = current1;current1 = current1.right;}if(parent1.right == current1){parent1.right = null;}else{parent1.left = null;}// 到这里current1为最右左节点,parent1为current1的父节点,已经解除了父子关系current1.left = node.left;current1.right = node.right;if(parent.right == current){parent.right = current1;}else{parent.left = current1;}node.left = null;node.right = null;}}/*** 先根遍历*/public void firstRootIndex(Node root){if(root != null){System.out.println(root.data);if(root.left != null){firstRootIndex(root.left);}if(root.right != null){firstRootIndex(root.right);}}}/*** 后根遍历* @param root*/public void lastRootIndex(Node root){if(root != null){if(root.left != null){lastRootIndex(root.left);}if(root.right != null){lastRootIndex(root.right);}System.out.println(root.data);}}/*** 中序遍历* @param root*/public void midRootIndex(Node root){if(root != null){if(root.left != null){lastRootIndex(root.left);}System.out.println(root.data);if(root.right != null){lastRootIndex(root.right);}}}/*** 层序遍历* @param root*/public void layerIndex(Node root){// 1.当前层Queue<Node> currentLayer = new ArrayDeque<Node>();// 2.临时存储下一层节点Queue<Node> sonLayer = new ArrayDeque<Node>();if(this.root == null){return;}else{currentLayer.add(this.root);}while(currentLayer.size() != 0){// 1.当前层节点出队列下一层入队列
                sonLayer.clear();while(currentLayer.size() != 0){Node node = currentLayer.poll();// 2.遍历本层节点
                    System.out.print(node);if(node.left != null){sonLayer.add(node.left);}if(node.right != null){sonLayer.add(node.right);}}System.out.println();// 3.将sonLayer赋给currentLayer,sonLayer重新创建对象currentLayer = sonLayer;sonLayer = new ArrayDeque<Node>();}}/*** 计算树的宽度* 也就是树中节点数最多的层次对应的节点数* 思路1: 进行一次树的遍历,也就是过一遍树的所有节点,将每一层的数据存储在Map数据结构中* 思路2: 设置队列进行层序遍历,将这层的节点数量计算一下,然后出队列,下一层的节点入队列** 思路2提供了除去以上三种遍历方式以外的第三种遍历方式*/public int computeWidth(){int maxSize = 0;// 1.当前层Queue<Node> currentLayer = new ArrayDeque<Node>();// 2.临时存储下一层节点Queue<Node> sonLayer = new ArrayDeque<Node>();if(this.root == null){return maxSize;}else{currentLayer.add(this.root);}while(currentLayer.size() != 0){// 1. 计算当前层sizeint currentSize = currentLayer.size();maxSize = maxSize>currentSize?maxSize:currentSize;// 2.当前层节点出队列下一层入队列
                sonLayer.clear();while(currentLayer.size() != 0){Node node = currentLayer.poll();if(node.left != null){sonLayer.add(node.left);}if(node.right != null){sonLayer.add(node.right);}}// 3.将sonLayer赋给currentLayer,sonLayer重新创建对象currentLayer = sonLayer;sonLayer = new ArrayDeque<Node>();}return maxSize;}/*** 计算二叉树中两点的最大距离* 思路1: 左枝树长 + 右枝树长 算法:节省时间,占空间* 思路2: 迭代 算法:节省空间,占用时间*/public int computeMaxDistance(){if(this.root == null){return 0;}return computeDepth(this.root.left) + computeDepth(this.root.right);}/*** 计算二叉树的深度* 和刚才计算宽度的思路一样,只是用深度来计算* @return*/public int computeDepth(Node root){int depth = 0;// 1.当前层Queue<Node> currentLayer = new ArrayDeque<Node>();// 2.临时存储下一层节点Queue<Node> sonLayer = new ArrayDeque<Node>();if(root == null){return depth;}else{currentLayer.add(root);}while(currentLayer.size() != 0){// 1. 计算当前层depthdepth ++;// 2.当前层节点出队列下一层入队列
                sonLayer.clear();while(currentLayer.size() != 0){Node node = currentLayer.poll();if(node.left != null){sonLayer.add(node.left);}if(node.right != null){sonLayer.add(node.right);}}// 3.将sonLayer赋给currentLayer,sonLayer重新创建对象currentLayer = sonLayer;sonLayer = new ArrayDeque<Node>();}return depth;}}public static void main(String[] args) {Tree tree = new Tree();tree.addNode(new Node(100));tree.addNode(new Node(200));tree.addNode(new Node(20));tree.addNode(new Node(177));Node nodeToRemove = new Node(88);tree.addNode(nodeToRemove);tree.addNode(new Node(90));tree.addNode(new Node(60));// 层序遍历System.out.println("层次遍历");tree.layerIndex(tree.root);// 先根遍历System.out.println("先根遍历");tree.firstRootIndex(tree.root);// 计算宽度与深度tree.addNode(new Node(188));System.out.println("width:"+tree.computeWidth());System.out.println("depth:"+tree.computeDepth(tree.root));// 删除节点
        tree.removeNode(nodeToRemove);// 层序遍历System.out.println("层序遍历");tree.layerIndex(tree.root);// 后根遍历System.out.println("后根遍历");tree.lastRootIndex(tree.root);System.out.println("最大距离:"+tree.computeMaxDistance());}
}

result:

层次遍历
N[100]
N[20]N[200]
N[88]N[177]
N[60]N[90]
先根遍历
100
20
88
60
90
200
177
width:3
depth:4
层序遍历
N[100]
N[20]N[200]
N[90]N[177]
N[60]N[188]
后根遍历
60
90
20
188
177
200
100
最大距离:6

转载于:https://www.cnblogs.com/yosql473/p/10731818.html

[数据结构]P2.1 二叉搜索树相关推荐

  1. 数据结构与算法:二叉搜索树

    ✨数据结构与算法:二叉搜索树

  2. 数据结构与算法-二叉搜索树

    二叉搜索树 1.左右子树都是二叉搜索树 2.左子树都比根节点小 3.右子树都比根节点大 (一)编程实现 1.查找 2.插入:递归实现 4.删除 #include <iostream> #i ...

  3. 【数据结构】二叉查找树/二叉搜索树BST(附相关C++代码)

    文章目录 BST相关概念 BST如何添加节点 BST如何遍历 BST如何求最值 BST如何删除节点 BST如何查找节点 如何验证一棵树是BST 本文内容将主要介绍二叉查找树的相关概念,与关于二叉查找树 ...

  4. 高级数据结构与算法 | 二叉搜索树(Binary Search Tree)

    文章目录 二叉搜索树的概念 二叉搜索树的作用 排序 查找 实现思路 查找 插入 删除 删除.拷贝等 代码实现 K模型 KV模型 二叉搜索树的概念 二叉搜索树又叫做二叉排序树,他是一个具有以下特性的二叉 ...

  5. 数据结构:将二叉搜索树转换成一个排序的双向链表

    1.将二叉搜索树转换成一个排序的双向链表.提示:要求不能创建任何新的结点,只能调整树中结点指针的指向,也就是left当prev,right当next.--中序线索化的变型. Node* BSTreeT ...

  6. Python 数据结构与算法——二叉搜索树的实现

    class Tree:本身自然需要维护根节点(root),用于指向树的第一个节点 class Tree:root = None class Node:每一个节点都要维护左子树.右子树 class No ...

  7. 数据结构 --- c语言二叉搜索树(有序的树)

    二叉搜索树基础 左边的孩子节点 < 父节点的值,右边孩子节点 > 父节点的值 每棵二叉搜索树的子树也是一棵二叉搜索树 10 充当根节点 18 > 根节点,应该放在根节点的右边:3 & ...

  8. 浙大数据结构——4.1二叉搜索树

    什么是二叉搜索树 一棵二叉树,可以为空也可以不为空.满足以下性质: 1.非空左子树的所有键值都小于其根节点的键值. 2.非空右子树的所有键值都大于其根节点的键值. 3.左.右子树都是二叉搜索树. 二叉 ...

  9. 数据结构与算法 / 二叉搜索树(Binary Search Tree)

    目录 一.定义 二.性质 三.时间复杂度分析 四.遍历方式 五.源码 一.定义 若左子树不空,则左子树上的所有的节点都小于它的根节点. 若右子树不空,则右子树上的所有的节点都大于它的根节点. 左右子树 ...

最新文章

  1. Batch Normalization 与Dropout 的冲突
  2. 用HTML和CSS和JS构建跨平台桌面应用程序的开源库Electron的介绍以及搭建HelloWorld
  3. jenkins Publish over SSH 的配置与使用
  4. 【NLP】选择目标序列:贪心搜索和Beam search
  5. jQuery基本语法
  6. 【概率论】对弈输光模型,ruin model
  7. 关于使用_bstr_t的一个坑
  8. EXTJS4自学手册——EXT基本方法、属性(mixins多继承、statics、require)
  9. Mybatis 项目开发实际常用SQL笔记总结
  10. 如何群发邮件?教你发邮件时文件怎么命名、如何设置邮件格式,一文解决你的疑惑
  11. drop_caches释放哪些内存
  12. 星球大战7:原力觉醒[Star Wars Episode VII:The Force Awakens]
  13. theisle服务器信息设置,theisle服务器diy
  14. Spark—15分钟教程
  15. python 中文转带音调的拼音
  16. New Bing新必应内测资格申请教程,无需科学上网,一分钟搞定!
  17. 数据分析报告怎么写(五)
  18. 【图形学】04 数学部分(四、放射变换)
  19. 啤酒游戏及其牛鞭效应的模拟之二级模式
  20. java支付接口(支付宝、微信、QQ)

热门文章

  1. jdk下没有java源码_openJDK之如何下载各个版本的openJDK源码
  2. 推荐 | 微软SAR近邻协同过滤算法解析(一)
  3. Softmax的推导以及实现
  4. python re 模块
  5. 10 行代码解决漏斗转换计算之性能优化
  6. 饿了么是视障者非常喜欢的APP,你们要加油哦!
  7. Spring学习之AOP
  8. linux下源码安装apache服务
  9. 机器学习入门算法基础视频
  10. 走进 Growth Hacker 的世界