[数据结构]P2.1 二叉搜索树
二叉树就是每个节点最多有两个分叉的树。这里我们写一写一个典型的例子二叉搜索树,它存在的实际意义是什么呢?
在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.左子树都比根节点小 3.右子树都比根节点大 (一)编程实现 1.查找 2.插入:递归实现 4.删除 #include <iostream> #i ...
- 【数据结构】二叉查找树/二叉搜索树BST(附相关C++代码)
文章目录 BST相关概念 BST如何添加节点 BST如何遍历 BST如何求最值 BST如何删除节点 BST如何查找节点 如何验证一棵树是BST 本文内容将主要介绍二叉查找树的相关概念,与关于二叉查找树 ...
- 高级数据结构与算法 | 二叉搜索树(Binary Search Tree)
文章目录 二叉搜索树的概念 二叉搜索树的作用 排序 查找 实现思路 查找 插入 删除 删除.拷贝等 代码实现 K模型 KV模型 二叉搜索树的概念 二叉搜索树又叫做二叉排序树,他是一个具有以下特性的二叉 ...
- 数据结构:将二叉搜索树转换成一个排序的双向链表
1.将二叉搜索树转换成一个排序的双向链表.提示:要求不能创建任何新的结点,只能调整树中结点指针的指向,也就是left当prev,right当next.--中序线索化的变型. Node* BSTreeT ...
- Python 数据结构与算法——二叉搜索树的实现
class Tree:本身自然需要维护根节点(root),用于指向树的第一个节点 class Tree:root = None class Node:每一个节点都要维护左子树.右子树 class No ...
- 数据结构 --- c语言二叉搜索树(有序的树)
二叉搜索树基础 左边的孩子节点 < 父节点的值,右边孩子节点 > 父节点的值 每棵二叉搜索树的子树也是一棵二叉搜索树 10 充当根节点 18 > 根节点,应该放在根节点的右边:3 & ...
- 浙大数据结构——4.1二叉搜索树
什么是二叉搜索树 一棵二叉树,可以为空也可以不为空.满足以下性质: 1.非空左子树的所有键值都小于其根节点的键值. 2.非空右子树的所有键值都大于其根节点的键值. 3.左.右子树都是二叉搜索树. 二叉 ...
- 数据结构与算法 / 二叉搜索树(Binary Search Tree)
目录 一.定义 二.性质 三.时间复杂度分析 四.遍历方式 五.源码 一.定义 若左子树不空,则左子树上的所有的节点都小于它的根节点. 若右子树不空,则右子树上的所有的节点都大于它的根节点. 左右子树 ...
最新文章
- Batch Normalization 与Dropout 的冲突
- 用HTML和CSS和JS构建跨平台桌面应用程序的开源库Electron的介绍以及搭建HelloWorld
- jenkins Publish over SSH 的配置与使用
- 【NLP】选择目标序列:贪心搜索和Beam search
- jQuery基本语法
- 【概率论】对弈输光模型,ruin model
- 关于使用_bstr_t的一个坑
- EXTJS4自学手册——EXT基本方法、属性(mixins多继承、statics、require)
- Mybatis 项目开发实际常用SQL笔记总结
- 如何群发邮件?教你发邮件时文件怎么命名、如何设置邮件格式,一文解决你的疑惑
- drop_caches释放哪些内存
- 星球大战7:原力觉醒[Star Wars Episode VII:The Force Awakens]
- theisle服务器信息设置,theisle服务器diy
- Spark—15分钟教程
- python 中文转带音调的拼音
- New Bing新必应内测资格申请教程,无需科学上网,一分钟搞定!
- 数据分析报告怎么写(五)
- 【图形学】04 数学部分(四、放射变换)
- 啤酒游戏及其牛鞭效应的模拟之二级模式
- java支付接口(支付宝、微信、QQ)