数据结构之二叉搜索树(Binary Search Tree)

ops/2024/12/21 20:20:43/

数据结构之二叉搜索树(Binary Search Tree)

  • 1. ⼆叉搜索树的概念
  • 2. ⼆叉搜索树的性能分析
  • 3.⼆叉搜索树的 查,删,插(没有改,因为没有意义会破坏本质)(源码)

1. ⼆叉搜索树的概念

⼆叉搜索树⼜称⼆叉排序树,它或者是⼀棵空树,或者是具有以下性质的⼆叉树:
• 若它的左⼦树不为空,则左⼦树上所有结点的值都⼩于等于根结点的值
• 若它的右⼦树不为空,则右⼦树上所有结点的值都⼤于等于根结点的值
• 它的左右⼦树也分别为⼆叉搜索树

2. ⼆叉搜索树的性能分析

最优情况下,⼆叉搜索树为完全⼆叉树(或者接近完全⼆叉树),其⾼度为: O(log2 N)
最差情况下,⼆叉搜索树退化为单⽀树(或者类似单⽀),其⾼度为: O( n/2)
所以综合⽽⾔⼆叉搜索树增删查改时间复杂度为: O(N)

在这里插入图片描述

那么这样的效率显然是⽆法满⾜我们需求的,我们后续课程需要继续讲解⼆叉搜索树的变形,平衡⼆叉搜索树AVL树和红⿊树,才能适⽤于我们在内存中存储和搜索数据。另外需要说明的是,⼆分查找也可以实现 O(logN) 级别的查找效率,但是⼆分查找有两⼤缺陷:
1. 需要存储在⽀持下标随机访问的结构中,并且有序。
2. 插⼊和删除数据效率很低,因为存储在下标随机访问的结构中,插⼊和删除数据⼀般需要挪动数据。
这⾥也就体现出了平衡⼆叉搜索树的价值。

3.⼆叉搜索树的 查,删,插(没有改,因为没有意义会破坏本质)(源码)

#pragma once
#include <iostream>
using namespace std;
//bst时间复杂度:最差情况下 :会退化成链表形状 O(N)
//理想状态下:O(logn)
template <class k>
struct bstnode {k _key;bstnode<k>* _left;bstnode<k>* _right;bstnode(const k& key):_key(key), _left(nullptr), _right(nullptr){};
};
template<class k>
class bstree {typedef bstnode<k> node;
public:bool insert(const k& key)//插入-(不支持相等值插入,要想实现,"改"下面判断条件){//先处理空树if (_root == nullptr){_root = new node(key);return true;}node* parent = nullptr;//作用:为了最后连接插入节点node* cur = _root;//把root赋给cur,让key从根节点开始找while (cur){if (cur->_key > key)//往左走{parent = cur;cur = parent->_left;}else if (cur->_key < key)//往右走{parent = cur;cur = parent->_right;}else //相等{return false;}}//循环走完,cur来到空节点//开始插入cur = new node(key);//走到这里不知道key比当前的parent大还是小,所以进行比较if (key > parent->_key)//去右{parent->_right = cur;}else//这里包含 小于 和 等于 两种情况{parent->_left = cur;}}bool find(const k& key)//查找{//查找逻辑较简单:从根节点开始找,找到空就是不存在//找的次数:最多"树的高度"次cout << "你要查找的值 :" << key << endl;cout << "存在(1)|不存在(0): ";node* cur = _root;while (cur){if (cur->_key > key){cur = cur->_left;}else if (cur->_key < key){cur = cur->_right;}else{return true;}}return false;}void inorder(){cout << "中序遍历(递归法): ";_inorder(_root);cout << endl;}//删除,分为四种情况(假设要删除的节点是 n)//1.n的左右孩子都为空--可以归为2,3情况来处理//2.n的左孩子为空--让n的父亲节点指向n的右孩子,直接delete n//3.n的右孩子为空--让n的父亲节点指向n的左孩子,直接delete n//4.n的左右孩子都不为空--只能用 替换法,找n左子树的最大节点(最右节点)//,或者找n的右子树的最小节点(最左节点),和n进行替换,然后delete n//删除的逻辑和查找差不多,都是先找到节点,没找到返回空bool erase(const k& key){node* parent = nullptr;//作用:为了最后连接插入节点node* cur = _root;//把root赋给cur,让key从根节点开始找while (cur){if (cur->_key > key)//往左走{parent = cur;cur = parent->_left;}else if (cur->_key < key)//往右走{parent = cur;cur = parent->_right;}else //相等,开始删除{				if (cur->_left == nullptr)//只有一个孩子或者没有孩子的情况{//这里有个小坑:就是要删除的节点是根节点就会崩,所以得提前判断一下if (parent == nullptr)//要删除根节点的情况,直接改根{_root = cur->_right;}else{//这里不知道cur是parent的左还是右有两种情况会导致结果有偏差,所以要判断一下if (parent->_left == cur) parent->_left = cur->_right;else parent->_right = cur->_right;}delete cur;return true;}else if (cur->_right == nullptr){if (parent == nullptr){_root = cur->_left;}else{if (parent->_left == cur) parent->_left = cur->_left;else parent->_right = cur->_left;}delete cur;return true;}else//有两个孩子的情况{//这里我用的代替节点是n右子树的最左节点node* replaceparent = cur;node* replace = cur->_right;while (replace->_left){replaceparent = replace;replace = replace->_left;						}//这里找到了代替节点,开始替换cur->_key = replace->_key;//这里的情况和上面一样不知道是父亲节点的 左 还是右if (replaceparent->_left == replace) replaceparent->_left = replace->_right;else replaceparent->_right = replace->_right;delete replace;return true;}}}//没找到return false;}
private:void _inorder(node* root)//中序递归{if (root==nullptr){return;}_inorder(root->_left);cout << root->_key << " ";_inorder(root->_right);}
private:node* _root = nullptr;
};
#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>
#include"bst.h"
using namespace std;int main()
{int a[] = { 8, 3, 1, 10, 6, 4, 7, 14, 13 };bstree<int> t;for (auto e : a){t.insert(e);}t.inorder();//cout<<t.find(3)<<endl;////cout<<t.find(122);for (auto e : a){t.erase(e);t.inorder();}return 0;
}

http://www.ppmy.cn/ops/143848.html

相关文章

界面控件DevExpress v24.2.3全新发布——正式支持.NET 9

DevExpress拥有.NET开发需要的所有平台控件&#xff0c;包含600多个UI控件、报表平台、DevExpress Dashboard eXpressApp 框架、适用于 Visual Studio的CodeRush等一系列辅助工具。 屡获大奖的软件开发平台DevExpress 近期重要版本v24.2已正式发布&#xff0c;该版本拥有众多新…

MFC 应用程序语言切换

在开发多语言支持的 MFC 应用程序时&#xff0c;如何实现动态语言切换是一个常见的问题。在本文中&#xff0c;我们将介绍两种实现语言切换的方式&#xff0c;并讨论其优缺点。同时&#xff0c;我们还会介绍如何通过保存配置文件来记住用户的语言选择&#xff0c;以及如何在程序…

flask-admin+Flask-WTF 实现实现增删改查

背景&#xff1a; flask-adminflask-wtf在网上可以搜索到很多资料&#xff0c;但有价值的很少&#xff0c;或许是太简单&#xff0c;或者是很少人这么用&#xff0c;或者。。。&#xff0c;本文将作者近礼拜摸索到的一点经验分享出来&#xff0c;给自己做个记录。 材料&#…

nginx-虚拟主机配置笔记

目录 nginx的安装可以查看nginx安装https://blog.csdn.net/m0_68472908/article/details/144609023?spm1001.2014.3001.5501 一、 基于域名 二、 基于IP 三、 基于端口 nginx的安装可以查看nginx安装https://blog.csdn.net/m0_68472908/article/details/144609023?spm100…

Flamingo论文介绍:把视觉特征向语言模型看齐

今天介绍一篇经典的多模态论文&#xff0c;来自NeurIPS 2022的《Flamingo: a Visual Language Model for Few-Shot Learning》 &#xff0c;论文地址&#xff1a;https://arxiv.org/pdf/2103.00020 文章目录 一、Motivate二、Method三、模块细节&#xff1a;Perceiver Resampl…

短视频账号矩阵系统源代码-代码分享

PHP8.0 服务器安装准备 在进行抖音短视频矩阵系统源码部署前&#xff0c;安装 PHP8.0 服务器需要做好一些基础准备工作&#xff0c;这能让后续的安装过程更加顺利哦&#xff0c;下面就来给大家详细说一说。 首先&#xff0c;要了解服务器的配置要求呀。一般来说&#xff0c;服…

【集成部署打包】vue3+django集成部署打包成exe 文件

【集成部署打包】vue3django集成部署打包成exe 文件 文章目录 【集成部署打包】vue3django集成部署打包成exe 文件1. vue 打包部署配置2. django 打包部署配置3. 打包操作 总结 1. vue 打包部署配置 import { defineConfig } from vite import vue from vitejs/plugin-vue imp…

[Unity]【图形渲染】【游戏开发】Shader数学基础4-更多矢量运算

在计算机图形学和着色器编程中,矢量运算是核心的数学工具之一。矢量用于描述空间中的位置、方向、速度等各种物理量,并在图形变换、光照计算、纹理映射等方面起着至关重要的作用。本篇文章将详细讲解矢量和标量之间的乘法与除法、矢量的加法与减法、矢量的模与单位矢量、点积…