热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

数据结构-二叉查找树(BST)

二叉查找树是一种比较特殊的二叉树,表现为任意节点的值都比左孩子的值要大,而且小于等于右孩子的值,采用中序遍历BST(BinarySearchTree

   二叉查找树是一种比较特殊的二叉树,表现为任意节点的值都比左孩子的值要大,而且小于等于右孩子的值,采用中序遍历BST(Binary Search Tree)就可以的到排序好的元素集合,而且插入删除的时间消耗也比较合理,但是有一个缺点就是内存开销有点大,下面简单介绍BST。


下面就是两棵二叉查找树


BST实现主要采用递归来实现,所以在学习实现的过程中也可以加深对递归的理解和掌握。具体代码的意思在注释中均有明确的说明,下面看具体的实现


首先是定义一个节点的类Node,文件名为”Node.h“,由于存储的参数类型具体不了解,所以此处采用了模板的实现方法,实现了节点的一些常用操作。

#ifndef NODE_H
#define NODE_H

/*
*二叉树节点Node,实现了一些简单地节点操作,
*比如,获取左右子节点,修改左右子节点等,
*含有三个参数
*由于节点元素数据类型未知,故采用模板实现
*/

template
class Node{
private:
//节点的元素值
Elem value;
//节点的左指针
Node * leftPtr;
//节点的右指针
Node * rightPtr;

public:
Node(Elem e, Node * lp = NULL, Node * rp = NULL){
value = e;
leftPtr = lp;
rightPtr = rp;
}

//判断是否为叶子节点
bool isLeaf() const{
return (leftPtr == NULL && rightPtr == NULL);
}

//获取节点的value值
Elem getValue() const{
return value;
}

//修改节点的value值
void setValue(Elem e){
value = e;
}

//获取左节点指针
Node * getLeft() const{
return leftPtr;
}

//设置左子节点
void setLeft(Node * left){
leftPtr = left;
}

//获取右节点指针
Node * getRight() const{
return rightPtr;
}

//设置右节点
void setRight(Node * right){
rightPtr = right;
}
};
#endif

有了节点之后,我们就可以考虑具体的BST实现了


#ifndef BST_H
#define BST_H

#include
#include
#include"Node.h"

using namespace std;

template
class BST{

public:
BST(){
rootNode = NULL;
nodeCount = 0;
}

~BST(){
delete[] rootNode;
}

//插入一个元素e
bool insert(const Elem& e){
rootNode = insertHelp(rootNode, e);
++nodeCount;
return true;
}

//移除一个元素e
bool remove(const Elem & e){
//mark标记删除元素是否在BST中
Node * mark = NULL;
rootNode = removeHelp(rootNode, e, mark);
if (mark == NULL){
cout <<"Error: 所要删除的元素 " <return false;
}
else{
nodeCount--;
delete [] mark;
return true;
}
}

//中序遍历打印BST
void show(){
showHelper(rootNode);
cout <}

private:
//指向整个BST的指针
Node * rootNode;
//BST节点个数
int nodeCount;

//实现在bst中正确位置插入元素
Node * insertHelp(Node * subroot, const Elem & e){
//当递归到空位置时,即找到了合适的插入位置,
//此时返回一个新节点作为上次递归调用subroot的孩子节点
if (subroot == NULL){
return new Node(e);
}
//当前节点值大于要插入值时,说明插入位置在当前位置的左边,递归调用
if (subroot->getValue() > e){
subroot->setLeft(insertHelp(subroot->getLeft(), e));
}
//当前节点值小于要插入值时,说明插入位置在当前位置的右边,递归调用
else{
subroot->setRight(insertHelp(subroot->getRight(), e));
}
return subroot;
}

//删除最小值,返回删除后的树的根节点指针
Node * deleteMin(Node * subroot, Node * & min){
//当左节点为空时,表示已经找到最小元素,此时把最小元素赋值min
if (subroot->getLeft() == NULL){
min = subroot;
return subroot->getRight();
}
else{ //当左节点不是空节点的时候,递归调用
subroot->setLeft(deleteMin(subroot->getLeft(), min));
return subroot;
}
}


//删除操作的帮助实现函数
//当元素e不在树中是mark值为NULL,当e在树中时,mark值为e元素对应的节点指针
Node * removeHelp(Node * subroot, const Elem e, Node * & mark){
//当subroot为NULL时表示找不到删除元素对应节点
if (subroot == NULL){
return NULL;
}

//当前元素值大于要删除的元素值,表示删除当前元素在元素的左边
else if (subroot->getValue() > e){
subroot->setLeft(removeHelp(subroot->getLeft(), e, mark));
}

//当前元素值小于要删除的元素值,表示删除当前元素在元素的右边
else if (subroot->getValue() subroot->setRight(removeHelp(subroot->getRight(), e, mark));
}

//找到删除元素对应节点
else{
//删除节点左孩子为空
//标记mark,表示找到删除元素
//直接让subroot指针指向subroot的右子节点
if (subroot->getLeft() == NULL){
mark = subroot;
subroot = subroot->getRight();
}
//删除节点右孩子为空
//标记mark,表示找到删除元素
//直接让subroot指针指向subroot的左子节点
else if (subroot->getRight() == NULL){
mark = subroot;
subroot = subroot->getLeft();
}
//删除两个子节点均不为空
else{
//删除subroot右子树最小节点temp,然后把subroot值赋为temp的值
//标记mark,表示找到删除元素
Node * temp;
subroot->setRight(deleteMin(subroot->getRight(), temp));
Elem te = subroot->getValue();
subroot->setValue(temp->getValue());
temp->setValue(te);
mark = temp;
}
}
return subroot;
}

//中序遍历BST
Node * showHelper(Node * subroot){
if (subroot == NULL){
return NULL;
}
showHelper(subroot->getLeft());
cout <getValue();
showHelper(subroot->getRight());
}

};
#endif


上面的程序实现了BST基本的功能,下面就来简单总结一下BST的特点吧。

  在BST中,insert,remove,find操作的时间消耗平均都是(log n),但在最坏情况下都是(n),所以说保持树的平衡是很重要的,就是保持节点左右两边元素个数基本相同。





推荐阅读
  • 二叉树的链表实现
    本文介绍了一种使用链表结构表示二叉树的方法。通过定义节点结构和相关操作函数,可以方便地创建、插入和遍历二叉树。 ... [详细]
  • 在编译BSP包过程中,遇到了一个与 'gets' 函数相关的编译错误。该问题通常发生在较新的编译环境中,由于 'gets' 函数已被弃用并视为安全漏洞。本文将详细介绍如何通过修改源代码和配置文件来解决这一问题。 ... [详细]
  • Python自动化测试入门:Selenium环境搭建
    本文详细介绍如何在Python环境中安装和配置Selenium,包括开发工具PyCharm的安装、Python环境的设置以及Selenium包的安装方法。此外,还提供了编写和运行第一个自动化测试脚本的步骤。 ... [详细]
  • 优化SQL Server批量数据插入存储过程的实现
    本文介绍了一种改进的SQL Server存储过程,用于生成批量插入语句。该方法不仅提高了性能,还支持单行和多行模式,适用于SQL Server 2005及以上版本。 ... [详细]
  • 主调|大侠_重温C++ ... [详细]
  • Python3 中使用 lxml 模块解析 XPath 数据详解
    XPath 是一种用于在 XML 文档中查找信息的路径语言,同样适用于 HTML 文件的搜索。本文将详细介绍如何利用 Python 的 lxml 模块通过 XPath 技术高效地解析和抓取网页数据。 ... [详细]
  • 本文介绍了一种根据目标检测结果,从原始XML文件中提取并分析特定类别的方法。通过解析XML文件,筛选出特定类别的图像和标注信息,并保存到新的文件夹中,以便进一步分析和处理。 ... [详细]
  • Google排名优化-面向Google(Search Engine Friendly)的URL设计 ... [详细]
  • 在Java应用程序开发过程中,FTP协议被广泛用于文件的上传和下载操作。本文通过Jakarta Commons Net库中的FTPClient类,详细介绍如何实现文件的上传和下载功能。 ... [详细]
  • 在MFC开发中,TreeCtrl控件因其强大的层次结构展示能力而被广泛应用,例如在资源管理器视图中。本文将详细介绍如何高效地利用TreeCtrl控件,包括设置属性、添加项目以及使用图像列表等技巧。 ... [详细]
  • 本文详细介绍了Linux操作系统中的cp和scp命令,包括它们的基本使用方法、常见选项以及如何通过scp命令安全地在不同主机之间传输文件。 ... [详细]
  • 详解 | 日志系统ViseLog的基本使用与功能
    本文详细介绍了日志系统ViseLog的使用方法及其核心功能,旨在帮助开发者更好地理解和利用这一工具,提高开发效率。 ... [详细]
  • 本文介绍了一道来自《紫书》的编程题目——UVa11212 编辑书稿。该问题通过迭代加深搜索(IDA*)算法解决,旨在找到将给定排列转换为升序排列所需的最少步骤。文章提供了详细的解题思路和代码实现。 ... [详细]
  • 本文详细介绍了在 Ubuntu 16.04 系统中使用 APT-GET 包管理器安装 MySQL 5.7 数据库的过程,并对安装后的文件和目录结构进行了说明,包括重要的配置文件及其功能。 ... [详细]
  • 本文探讨如何使用 PHP 进行字符串处理,特别是如何检测一个字符串是否存在于另一个字符串中,并确定其具体位置。通过实例代码展示,帮助读者掌握这一常用功能。 ... [详细]
author-avatar
kaining_huang_750
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有