二叉搜索树:数据结构之美

news/2024/9/18 13:34:03/ 标签: 算法, 开发语言

目录

  1. 引言
  2. 基础知识
    • 定义
    • 性质
  3. 操作详解
    • 插入节点
    • 删除节点
    • 查找节点
    • 遍历
      • 前序遍历
      • 中序遍历
      • 后序遍历
  4. 高级主题
    • 平衡问题
    • AVL树简介
  5. 应用案例
  6. 总结

引言

二叉搜索树(Binary Search Tree, BST)是一种特殊的二叉树,它的每个节点具有以下性质:左子树上的所有节点的键值均小于它的根节点的键值;右子树上所有节点的键值均大于它的根节点的键值。这种结构使得二叉搜索树成为了高效查找、插入和删除数据的理想选择。

基础知识

定义

二叉搜索树是一种二叉树,其中每个节点包含一个键值、一个指向左子树的引用以及一个指向右子树的引用。左子树中的所有节点的键值小于该节点的键值,而右子树中的所有节点的键值大于该节点的键值。

性质

  • 唯一性:给定一组键值,存在唯一的二叉搜索树。
  • 中序遍历:对二叉搜索树进行中序遍历时,返回的键值序列是递增排序的。
  • 查找效率:在理想情况下,查找、插入和删除操作的时间复杂度为O(log n),其中n是树中节点的数量。

操作详解

插入节点

插入操作涉及比较新键值与树中节点的键值,并沿着树向下移动,直到找到合适的位置。

TreeNode* BinarySearchTree::_insert(TreeNode* node, int key) {if (node == nullptr) {return new TreeNode(key);}if (key < node->key) {node->left = _insert(node->left, key);} else if (key > node->key) {node->right = _insert(node->right, key);}return node;
}void BinarySearchTree::insert(int key) {root = _insert(root, key);
}

删除节点

删除操作分为三种情况:

  1. 节点没有子节点(叶节点)。
  2. 节点有一个子节点。
  3. 节点有两个子节点。
TreeNode* BinarySearchTree::_minValueNode(TreeNode* node) {TreeNode* current = node;while (current && current->left != nullptr) {current = current->left;}return current;
}TreeNode* BinarySearchTree::_remove(TreeNode* node, int key) {if (node == nullptr) {return node;}if (key < node->key) {node->left = _remove(node->left, key);} else if (key > node->key) {node->right = _remove(node->right, key);} else {if (node->left == nullptr) {TreeNode* temp = node->right;delete node;return temp;} else if (node->right == nullptr) {TreeNode* temp = node->left;delete node;return temp;}TreeNode* temp = _minValueNode(node->right);node->key = temp->key;node->right = _remove(node->right, temp->key);}return node;
}void BinarySearchTree::remove(int key) {root = _remove(root, key);
}

查找节点

查找操作用于确定树中是否存在某个键值。

bool BinarySearchTree::_find(TreeNode* node, int key) const {if (node == nullptr) {return false;}if (key == node->key) {return true;} else if (key < node->key) {return _find(node->left, key);} else {return _find(node->right, key);}
}bool BinarySearchTree::find(int key) const {return _find(root, key);
}

遍历

前序遍历

前序遍历的顺序是根节点、左子树、右子树。

void BinarySearchTree::_preorderTraversal(TreeNode* node) const {if (node != nullptr) {std::cout << node->key << " ";_preorderTraversal(node->left);_preorderTraversal(node->right);}
}void BinarySearchTree::preorderTraversal() const {_preorderTraversal(root);
}
中序遍历

中序遍历的顺序是左子树、根节点、右子树。对于二叉搜索树,这将返回一个升序的键值序列。

void BinarySearchTree::_inorderTraversal(TreeNode* node) const {if (node != nullptr) {_inorderTraversal(node->left);std::cout << node->key << " ";_inorderTraversal(node->right);}
}void BinarySearchTree::inorderTraversal() const {_inorderTraversal(root);
}
后序遍历

后序遍历的顺序是左子树、右子树、根节点。

void BinarySearchTree::_postorderTraversal(TreeNode* node) const {if (node != nullptr) {_postorderTraversal(node->left);_postorderTraversal(node->right);std::cout << node->key << " ";}
}void BinarySearchTree::postorderTraversal() const {_postorderTraversal(root);
}

高级主题

平衡问题

二叉搜索树虽然提供了快速的查找、插入和删除操作,但其性能高度依赖于树的高度。最坏的情况下,树可能变得非常不平衡,导致时间复杂度退化至O(n)。为了保持树的平衡,一些变种被提出,例如AVL树和红黑树。

AVL树简介

AVL树是一种自平衡二叉搜索树,它保证任何节点的两个子树的高度差不超过1。AVL树通过旋转操作来维持平衡,在插入或删除节点后可能需要进行旋转以恢复平衡。

插入操作

当插入一个节点后,AVL树可能会变得不平衡。需要通过以下四种类型的旋转来恢复平衡:

  • 单旋转:右旋或左旋。
  • 双旋转:右旋+左旋或左旋+右旋。
删除操作

删除节点后也需要考虑树的平衡性,可能的操作与插入类似,包括单旋转和双旋转。


应用案例

二叉搜索树在多种场景下都有广泛的应用:

  1. 数据库索引:许多数据库系统使用类似二叉搜索树的数据结构来加速查询过程。
  2. 符号表:编程语言解释器和编译器使用二叉搜索树来管理符号表。
  3. 文件系统:某些文件系统使用二叉搜索树来管理文件和目录的结构。
  4. 优先队列:二叉搜索树可以用来实现优先队列,特别是当使用自平衡变种如AVL树时。

总结

本文介绍了二叉搜索树的基本概念、主要操作以及一些高级主题。通过学习这些内容,您不仅能够理解二叉搜索树的工作原理,还能够掌握如何有效地使用它们来解决实际问题。此外,本文还探讨了自平衡二叉搜索树的概念,这是处理大规模数据集时的一个重要工具。


http://www.ppmy.cn/news/1516879.html

相关文章

Android开发语言Kotlin简介

官方认可&#xff1a;自 2017 年 Google 正式宣布 Kotlin 成为 Android 开发的官方语言后&#xff0c;它在 Android 开发中的流行度就有了显著提升。 与 Java 的兼容性&#xff1a;Kotlin 在设计时就考虑到了与 Java 的互操作性&#xff0c;这让开发者能够在 Android 项目中轻…

Postman接口自动化测试:从入门到实践!

前言 在软件开发过程中&#xff0c;接口测试是确保软件各组件之间正确交互的关键环节。Postman作为一款强大的API开发工具&#xff0c;不仅支持接口请求的发送与调试&#xff0c;还提供了丰富的自动化测试功能&#xff0c;使得接口自动化测试变得更加高效和便捷。本文将从Post…

机器人走路问题优化解法

public class Test53 {//假设有N个位置&#xff0c;记为1-N&#xff0c;N大于或等于2//开始机器人在M位置上&#xff08;M为1-N中的一个&#xff09;//如果机器人来到1位置&#xff0c;那么下一步只能向右来到2位置//如果机器人来到N位置&#xff0c;那么下一步只能向左来到N-1…

【算法题】找到任意一个峰值数字 要求时间复杂度为logn

在数组中找到一个峰值数字&#xff0c;‌其中峰值定义为比其相邻元素大的元素&#xff0c;‌可以使用二分查找算法来实现时间复杂度为O(log n)。‌ 以下是一个Java示例&#xff0c;‌演示如何在一个整数数组中找到任意一个峰值数字&#xff1a;‌ public class PeakFinder {p…

读取FTP中不同文件格式的文件流后导出到浏览器

序言 有一个新的需求&#xff0c;前端提供下载的入口&#xff0c;后端能将指定了全路径的各种文件格式的文件下载到浏览器。 对于压缩的zip文件格式需要解析后写入到txt文件格式的文件中&#xff0c;其他的写入原本的文件格式的文件中。 1、连接ftp <!-- jsch-sftp连接…

项目策划书六度自由双足机器人

一、项目的简要介绍 双足机器人的机构是所有部件的载体,也是设计双足机器人最基本的和首要的工作。本文根据项目规划和控制任务要求&#xff0c;按照从总体到部分、由主到次的原则&#xff0c;设计了一种适合仿人双足机器人控制的机构.文章首先从机构的设计目标出发&#xff0c…

【通俗理解】混合专家模型中的导诊与流程处理

【通俗理解】混合专家模型中的导诊与流程处理 关键词提炼 #混合专家模型 #导诊系统 #流程处理 #router #expert #token处理 第一节&#xff1a;混合专家模型中的导诊与流程处理类比 1.1 导诊与流程处理的类比 在混合专家模型中&#xff0c;导诊系统&#xff08;router&…

Android12 显示框架之Transaction----server端

目录&#xff1a;Android显示终极宝典 上篇讲完了在client端Transaction的内容&#xff0c;最后调用setTransactionState()把所有的参数都交给了surfaceflinger&#xff0c;那么任务就交给server来完成了。本节我们一起接着看看下面的内容。 setTransactionState() //framew…

学懂C++(四十五 ):深入详解C++ STL 容器:从基础到进阶

目录 1. 向量&#xff08;Vector&#xff09; 概念 特点 核心点 实现 适用场景 代码解析 2. 双端队列&#xff08;Deque&#xff09; 概念 特点 核心点 实现 适用场景 代码解析 3. 列表&#xff08;List&#xff09; 概念 特点 核心点 实现 适用场景 代码…

大模型备案重难点最详细说明【评估测试题+附件】

2024年3月1日&#xff0c;我国通过了《生成式人工智能服务安全基本要求》&#xff08;以下简称《AIGC安全要求》&#xff09;&#xff0c;这是目前我国第一部有关AIGC服务安全性方面的技术性指导文件&#xff0c;对语料安全、模型安全、安全措施、词库/题库要求、安全评估等方面…

设计模式(二):工厂模式

一&#xff0c;什么是工厂模式 工厂模式&#xff08;Factory Pattern&#xff09; 是一种创建型设计模式&#xff0c;它定义了一个用于创建对象的接口&#xff0c;而不需要显式地指定对象所属的具体类。换句话说&#xff0c;工厂模式将对象的实例化过程延迟到子类或其他工厂方…

【论文阅读】NGD-SLAM: Towards Real-Time SLAM for Dynamic Environments without GPU

arxiv上一篇很新的视觉SLAM论文&#xff0c;能够在不使用GPU的情况下进行语义分割的辅助运算。 一、跟踪流程 作为一个语义结合的视觉SLAM&#xff0c;其基本的思路和以前看过的DynaSLAM基本类似&#xff0c;都是依赖语义分割模型对场景中动态的特征点进行剔除&#xff0c;这…

【jvm】栈是否存在垃圾回收

目录 一、栈的特点1.1 栈内存分配1.2 栈的生命周期1.3 垃圾回收不直接涉及 二、堆与栈的区别三、总结 一、栈的特点 1.1 栈内存分配 1.栈内存分配是自动的&#xff0c;不需要程序员手动分配和释放。 2.每当一个方法被调用时&#xff0c;JVM就会在这个线程的栈上创建一个新的栈…

C++ | Leetcode C++题解之第355题设计推特

题目&#xff1a; 题解&#xff1a; class Twitter {struct Node {// 哈希表存储关注人的 Idunordered_set<int> followee;// 用链表存储 tweetIdlist<int> tweet;};// getNewsFeed 检索的推文的上限以及 tweetId 的时间戳int recentMax, time;// tweetId 对应发送…

使用GDIView工具排查GDI对象泄漏案例的若干细节总结

目录 1、查看任务管理器,发现程序中有明显的GDI对象泄漏 2、使用GDIView工具查看发生泄漏的是哪一种GDI对象 3、尝试找到复现问题的方法,缩小排查范围,逐步地找到GDI对象的泄漏点 4、本案例中的相关细节点的思考与总结(有价值的细节点) 4.1、UI界面无法显示的原因分析…

TypeScript 面试题汇总

引言 TypeScript 是一种由微软开发的开源、跨平台的编程语言&#xff0c;它是 JavaScript 的超集&#xff0c;为 JavaScript 添加了静态类型系统和其他高级功能。随着 TypeScript 在前端开发领域的广泛应用&#xff0c;掌握 TypeScript 已经成为很多开发者必备的技能之一。本文…

Clickhouse集群化(六)clickhosue-operator学习

1. Custom Resource元素 apiVersion: "clickhouse.altinity.com/v1" kind: "ClickHouseInstallation" metadata:name: "clickhouse-installation-test" 这是clickhouse operator自定义的资源ClickHouseInstallation 1.1. .spec.defaults spe…

35次8.23(docker02)

#搜索拉取镜像 docker search centos docker pull centos #创建启动容器 docker run -it --namea0 centod:latest echo "abc" #如果容器中没有正在执行的指令&#xff0c;就会exit docker run -it --namea0 cenyos:latest /bin/bash #查看docker进程 docker ps #发现…

SQL,解析 json

Google BigQuery数据库的data表存储了若干多层的Json串&#xff0c;其中一条形如&#xff1a; [{"active":true,"key":"key1","values":[{"active":true,"value":"value1"}]},{"active":tru…

go 系列实现websocket

一、简介 websocket是个二进制协议&#xff0c;需要先通过Http协议进行握手&#xff0c;从而协商完成从Http协议向websocket协议的转换。一旦握手结束&#xff0c;当前的TCP连接后续将采用二进制websocket协议进行双向双工交互&#xff0c;自此与Http协议无关。 二、websocket…