【手撕STL】二叉搜索树

【手撕STL】二叉搜索树这里写目录标题二叉搜索树二叉搜索树操作二叉搜索树的插入二叉搜索树的查找二叉搜索树的删除二叉搜索树的实现二叉搜索树二叉搜索树又称二叉排序树 它或者是一棵空树 或者是具有以下性质的二叉树 若它的左子树不为空 则左子树上所有节点的值都小于根节点的值若它的右子树不为空 则右子树上所有节点的值都大于根节点的值它的左右子树也分别为二叉搜索树注 二叉搜索树查找一个值最多查找高度次二叉搜索树操作二叉搜索树的插入 a 树为空 则直接插入 b 树不空 按二叉搜索树性质查找插入位置 插入新节点

二叉搜索树

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

在这里插入图片描述
注:

  • 二叉搜索树查找一个值最多查找高度次
  • 二叉搜索树按中序遍历,值可以从小到大打印出来

二叉搜索树操作

二叉搜索树的插入

  • 根节点为空,直接插入
  • 根节点不为空:
    1. 如果该节点key==要插入的key ,返回false
    1. 如果该节点key>要插入的key ,则向该节点的左子树查找(若该节点的左子树为空,则直接插入)
    1. 如果该节点key
      <要插入的key ,则向该节点的右子树查找(若该节点的右子树为空,则直接插入)<="" li="">

二叉搜索树的查找

在这里插入图片描述

  • 如果根节点key==查找key,返回true
  • 如果根节点key>查找key,在其左子树查找
  • 如果根节点key
    <查找key,在其右子树查找
    否则返回false

若根节点为空,返回false

二叉搜索树的删除

二叉搜索树的实现(递归及非递归)

#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include 
     using namespace std; template<class K> struct BSTreeNode { 
    BSTreeNode(const K& key) :_left(nullptr) ,_right(nullptr) ,_key(key) { 
   } BSTreeNode<K>* _left; BSTreeNode<K>* _right; K _key; }; template<class K> class BSTree { 
    typedef BSTreeNode<K> Node; public: // BSTree() = default; 强制编译器自动生成默认构造函数 BSTree() :_root(nullptr) { 
   } //也可写成 BSTree(const BSTree& t) BSTree(const BSTree<K>& t) { 
    _root = _Copy(t._root); } //BSTree 
   
     & operator=(BSTree t) 
    BSTree<K>& operator=(BSTree<K> t) { 
    swap(_root, t._root); return *this; } ~BSTree() { 
    _Destroy(_root); } bool Insert(const K& key) { 
    if (_root == nullptr) { 
    _root = new Node(key); return true; } //找出要插入的位置 Node* parent = nullptr; Node* cur = _root; while (cur) { 
    if (cur->_key > key) { 
    parent = cur; cur = cur->_left; } else if (cur->_key < key) { 
    parent = cur; cur = cur->_right; } else { 
    return false; } } cur = new Node(key); if (parent->_key > key) { 
    parent->_left = cur; } else { 
    parent->_right = cur; } return true; } void InOrder() { 
    _InOrder(_root); cout << endl; } Node* Find(const K& key) { 
    Node* cur = _root; while (cur) { 
    if (cur->_key > key) { 
    cur = cur->_left; } else if (cur->_key < key) { 
    cur = cur->_right; } else { 
    return cur; } } return nullptr; } bool Erase(const K& key) { 
    Node* cur = _root; Node* parent = nullptr; while (cur) { 
    if (cur->_key > key) { 
    parent = cur; cur = cur->_left; } else if (cur->_key < key) { 
    parent = cur; cur = cur->_right; } else { 
    if (cur->_left == nullptr) { 
    if (cur == _root) { 
    _root = cur->_right; } else { 
    if (parent->_left == cur) { 
    parent->_left = cur->_right; } else { 
    parent->_right = cur->_right; } } delete cur; } else if (cur->_right == nullptr) { 
    if (cur == _root) { 
    _root = cur->_left; } else { 
    if (parent->_left == cur) { 
    parent->_left = cur->_left; } else { 
    parent->_right = cur->_left; } } delete cur; } else { 
    //找右树最小节点去替代删除 Node* minrightparent = cur; Node* minright = cur->_right; while (minright->_left) { 
    minrightparent = minright; minright = minright->_left; } cur->_key = minright->_key; if (minrightparent->_left == minright) { 
    minrightparent->_left = minright->_right; } else { 
    minrightparent->_right = minright->_right; } delete minright; } return true; } } return false; } //递归版本 bool InsertR(const K& key) { 
    return _InsertR(_root, key); } Node* FindR(const K& key) { 
    return _FindR(_root, key); } bool EraseR(const K& key) { 
    return _EraseR(_root, key); } private: Node* _Copy(Node* root) { 
    if (root == nullptr) return nullptr; Node* newnode = new Node(root->_key); newnode->_left = _Copy(root->_left); newnode->_right = _Copy(root->_right); return newnode; } void _Destroy(Node* root) { 
    if (root == nullptr) { 
    return; } _Destroy(root->_left); _Destroy(root->_right); delete root; } bool _EraseR(Node*& root, const K& key) { 
    if (root == nullptr) { 
    return false; } else { 
    if (root->_key > key) { 
    return _EraseR(root->_left, key); } else if (root->_key < key) { 
    return _EraseR(root->_right, key); } else { 
    Node* del = root; if (root->_left == nullptr) { 
    root = root->_right; } else if (root->_right == nullptr) { 
    root = root->_left; } else { 
    //替代法删除 Node* minright = root->_right; while (minright->_left) { 
    minright = minright->_left; } root->_key = minright->_key; //转换成递归在右子树中删除最小节点 return _EraseR(root->_right, minright->_key); //注意:转换在递归删除右子树中minright如果右子树越大 //付出的代价就越大相当于重新查找了一遍 } delete del; return true; } } } Node* _FindR(Node* root, const K& key) { 
    if (root == nullptr) { 
    return nullptr; } else { 
    if (root->_key > key) { 
    return _FindR(root->_left, key); } else if (root->_key < key) { 
    return _FindR(root->_right, key); } else { 
    return root; } } } bool _InsertR(Node*& root, const K& key) { 
    if (root == nullptr) { 
    root = new Node(key); return true; } else { 
    if (root->_key > key) { 
    return _InsertR(root->_left, key); } else if (root->_key < key) { 
    return _InsertR(root->_right, key); } else { 
    return false; } } } void _InOrder(Node* root) { 
    if (root == nullptr) { 
    return; } _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } Node* _root=nullptr; }; 

注:尽量使用循环来写,不要用递归。因为递归一方面每次调用函数都要建立栈帧,另一方面递归深度太深会导致栈溢出

二叉搜索树的应用

  1. K模型:K模型即只有key作为关键码,结构中只需要存储Key即可,关键码即为需要搜索到的值。
    比如:给一个单词word,判断该单词是否拼写正确,具体方式如下:

  • 以单词集合中的每个单词作为key,构建一棵二叉搜索树
  • 在二叉搜索树中检索该单词是否存在,存在则拼写正确,不存在则拼写错误。
  1. KV模型:每一个关键码key,都有与之对应的值Value,即

    的键值对。该种方式在现实生活中非常常见:比如英汉词典就是英文与中文的对应关系,通过英文可以快速找到与其对应的中文,英文单词与其对应的中文

    就构成一种键值对;再比如统计单词次数,统计成功后,给定单词就可快速找到其出现的次数,单词与其出现次数就是

    就构成一种键值对。比如:实现一个简单的英汉词典dict,可以通过英文找到与其对应的中文,具体实现方式如下:


  • <单词,中文含义>
    为键值对构造二叉搜索树,注意:二叉搜索树需要比较,键值对比较时只比较Key
  • 查询英文单词时,只需给出英文单词,就可快速找到与其对应的key

K模型:

#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include 
     using namespace std; //确定一个只是不是在集合中 namespace KEY { 
    template<class K> struct BSTreeNode { 
    BSTreeNode(const K& key) :_left(nullptr) , _right(nullptr) , _key(key) { 
   } BSTreeNode<K>* _left; BSTreeNode<K>* _right; K _key; }; template<class K> class BSTree { 
    typedef BSTreeNode<K> Node; public: // BSTree() = default; 强制编译器自动生成默认构造函数 BSTree() :_root(nullptr) { 
   } //也可写成 BSTree(const BSTree& t) BSTree(const BSTree<K>& t) { 
    _root = _Copy(t._root); } //BSTree 
   
     & operator=(BSTree t) 
    BSTree<K>& operator=(BSTree<K> t) { 
    swap(_root, t._root); return *this; } ~BSTree() { 
    _Destroy(_root); } bool Insert(const K& key) { 
    if (_root == nullptr) { 
    _root = new Node(key); return true; } //找出要插入的位置 Node* parent = nullptr; Node* cur = _root; while (cur) { 
    if (cur->_key > key) { 
    parent = cur; cur = cur->_left; } else if (cur->_key < key) { 
    parent = cur; cur = cur->_right; } else { 
    return false; } } cur = new Node(key); if (parent->_key > key) { 
    parent->_left = cur; } else { 
    parent->_right = cur; } return true; } void InOrder() { 
    _InOrder(_root); cout << endl; } Node* Find(const K& key) { 
    Node* cur = _root; while (cur) { 
    if (cur->_key > key) { 
    cur = cur->_left; } else if (cur->_key < key) { 
    cur = cur->_right; } else { 
    return cur; } } return nullptr; } bool Erase(const K& key) { 
    Node* cur = _root; Node* parent = nullptr; while (cur) { 
    if (cur->_key > key) { 
    parent = cur; cur = cur->_left; } else if (cur->_key < key) { 
    parent = cur; cur = cur->_right; } else { 
    if (cur->_left == nullptr) { 
    if (cur == _root) { 
    _root = cur->_right; } else { 
    if (parent->_left == cur) { 
    parent->_left = cur->_right; } else { 
    parent->_right = cur->_right; } } delete cur; } else if (cur->_right == nullptr) { 
    if (cur == _root) { 
    _root = cur->_left; } else { 
    if (parent->_left == cur) { 
    parent->_left = cur->_left; } else { 
    parent->_right = cur->_left; } } delete cur; } else { 
    //找右树最小节点去替代删除 Node* minrightparent = cur; Node* minright = cur->_right; while (minright->_left) { 
    minrightparent = minright; minright = minright->_left; } cur->_key = minright->_key; if (minrightparent->_left == minright) { 
    minrightparent->_left = minright->_right; } else { 
    minrightparent->_right = minright->_right; } delete minright; } return true; } } return false; } private: Node* _Copy(Node* root) { 
    if (root == nullptr) return nullptr; Node* newnode = new Node(root->_key); newnode->_left = _Copy(root->_left); newnode->_right = _Copy(root->_right); return newnode; } void _Destroy(Node* root) { 
    if (root == nullptr) { 
    return; } _Destroy(root->_left); _Destroy(root->_right); delete root; } void _InOrder(Node* root) { 
    if (root == nullptr) { 
    return; } _InOrder(root->_left); cout << root->_key << " "; _InOrder(root->_right); } Node* _root = nullptr; }; } 

KV模型:

#pragma once #define _CRT_SECURE_NO_WARNINGS 1 #include 
     using namespace std; namespace KEY_VALUE { 
    template<class K, class V> struct BSTreeNode { 
    BSTreeNode(const K& key, const V& value) :_left(nullptr) , _right(nullptr) , _key(key) , _value(value) { 
   } BSTreeNode<K,V>* _left; BSTreeNode<K,V>* _right; K _key; V _value; }; template<class K, class V> class BSTree { 
    typedef BSTreeNode<K, V> Node; public: // BSTree() = default; 强制编译器自动生成默认构造函数 BSTree() :_root(nullptr) { 
   } BSTree(const BSTree<K, V>& t) { 
    _root = _Copy(t._root); } BSTree<K,V>& operator=(BSTree<K, V> t) { 
    swap(_root, t._root); return *this; } ~BSTree() { 
    _Destroy(_root); } bool Insert(const K& key, const V& value) { 
    if (_root == nullptr) { 
    _root = new Node(key, value); return true; } //找出要插入的位置 Node* parent = nullptr; Node* cur = _root; while (cur) { 
    if (cur->_key > key) { 
    parent = cur; cur = cur->_left; } else if (cur->_key < key) { 
    parent = cur; cur = cur->_right; } else { 
    return false; } } cur = new Node(key, value); if (parent->_key > key) { 
    parent->_left = cur; } else { 
    parent->_right = cur; } return true; } void InOrder() { 
    _InOrder(_root); cout << endl; } Node* Find(const K& key) { 
    Node* cur = _root; while (cur) { 
    if (cur->_key > key) { 
    cur = cur->_left; } else if (cur->_key < key) { 
    cur = cur->_right; } else { 
    return cur; } } return nullptr; } bool Erase(const K& key) { 
    Node* cur = _root; Node* parent = nullptr; while (cur) { 
    if (cur->_key > key) { 
    parent = cur; cur = cur->_left; } else if (cur->_key < key) { 
    parent = cur; cur = cur->_right; } else { 
    if (cur->_left == nullptr) { 
    if (cur == _root) { 
    _root = cur->_right; } else { 
    if (parent->_left == cur) { 
    parent->_left = cur->_right; } else { 
    parent->_right = cur->_right; } } delete cur; } else if (cur->_right == nullptr) { 
    if (cur == _root) { 
    _root = cur->_left; } else { 
    if (parent->_left == cur) { 
    parent->_left = cur->_left; } else { 
    parent->_right = cur->_left; } } delete cur; } else { 
    //找右树最小节点去替代删除 Node* minrightparent = cur; Node* minright = cur->_right; while (minright->_left) { 
    minrightparent = minright; minright = minright->_left; } cur->_key = minright->_key; if (minrightparent->_left == minright) { 
    minrightparent->_left = minright->_right; } else { 
    minrightparent->_right = minright->_right; } delete minright; } return true; } } return false; } private: Node* _Copy(Node* root) { 
    if (root == nullptr) return nullptr; Node* newnode = new Node(root->_key, root->_value); newnode->_left = _Copy(root->_left); newnode->_right = _Copy(root->_right); return newnode; } void _Destroy(Node* root) { 
    if (root == nullptr) { 
    return; } _Destroy(root->_left); _Destroy(root->_right); delete root; } void _InOrder(Node* root) { 
    if (root == nullptr) { 
    return; } _InOrder(root->_left); cout << root->_key << ":" << root->_value << endl; _InOrder(root->_right); } Node* _root = nullptr; }; } 

二叉搜索树的性能分析

  • 插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
  • 对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。
  • 但对于同一个关键码集合,如果各关键码插入的次序不同,可能得到不同结构的二叉搜索树:

在这里插入图片描述

最优情况下,二叉搜索树查找次数是logN;最差情况下,二叉搜索树查找次数是N

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/213712.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午5:49
下一篇 2026年3月18日 下午5:49


相关推荐

  • python 内置函数详解

    python 内置函数详解

    2021年7月5日
    82
  • JQuery delegate的使用心得

    JQuery delegate的使用心得delegate 函数用于为指定元素的一个或多个事件绑定事件处理函数 事实上 绑定事件类似的方法同样还有 on 函数 那 delegate 有什么特殊的地方呢 语法首先来看下其语法 selector delegate childSelecto event data function 其中 data 是可选的 规定传递到函数的额外数据 demo 下面看个例子

    2026年3月26日
    1
  • 从拥抱到警惕:OpenClaw这个“AI龙虾”是怎么回事?一文读懂

    从拥抱到警惕:OpenClaw这个“AI龙虾”是怎么回事?一文读懂

    2026年3月13日
    2
  • android rsa加密工具类,GitHub – Lerist/encrypt: Android 加密解密工具包。「建议收藏」

    android rsa加密工具类,GitHub – Lerist/encrypt: Android 加密解密工具包。「建议收藏」Encrypt(加密工具)字符串,byte[],文件等对象的加密和解密工具集合,包含了多种加密方案。加密类型摘要相关方法简单加密换一种编码格式Base64Util单向加密只能加密,不能解密MD5Util、SHAUtil对称加密使用相同的秘钥加密和解密AESUtil、DESUtil非对称加密分公钥和私钥,一个加密,另一个解密RSAUtil使用方法Base64util方法摘要Stringbase6…

    2022年5月17日
    42
  • sessionStorage 使用方法

    sessionStorage 使用方法作为 html5 中 WebStorage 的一种存储方式 localStorage 和 sessionStora 一样都是用来存储客户端临时信息的对象 这两者区别在于前者用于持久化的本地存储 除非主动删除数据 否则数据是永远不会过期的 而 sessionStora 存储的数据只有在同一个会话中的页面才能访问并且当会话结束后数据也随之销毁 因此 sessionStora 不是一种持久化的本地存储

    2025年9月6日
    7
  • sap安装配置_sapgui730安装指南

    sap安装配置_sapgui730安装指南一.下载和安装    WEBIDE是免安装的,下载完解压就行。       下载地址  Developerguid在线文档  在线文档打开会比较慢,可以下载下来观看。二.配置ABAP链接 在IDE的解压文件的配置文件夹中新建文件ER1(没有后缀名)  编辑新建文件添加如下内容:  Description=

    2022年10月18日
    6

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号