二叉查找树(Binary Search Tree)

是一种树形的存储数据的结构

如图所示,它具有的特点是:

1、具有一个根节点

2、每个节点可能有0、1、2个分支

3、对于某个节点,他的左分支小于自身,自身小于右分支

接下来我们用c++来实现BST的封装

首先我们编写每个节点的类结构,分析可以知道我们每一个节点需要存储一个数据(data),左分支(left指向一个节点),右分支(right指向另一个节点)

因此我们建立

bstNode.h

#ifndef TEST1_BSTNODE_H
#define TEST1_BSTNODE_H
template <typename T> //这里使用模板类,以放入多种类型的数据,值得一提的是模板类不能讲声明和实现放在两个文件中
class bstNode{
public:
T data;
bstNode* left;
bstNode* right;
bstNode(){ //默认构造函数
data = ;
left = nullptr;
right = nullptr;
}
bstNode(T val){ //赋值构造函数
data = val;
left = nullptr;
right = nullptr;
}
};
#endif //TEST1_BSTNODE_H

接下来我们创建封装了各种方法的树形结构类:

myBST.h

这个头文件的设计思路如下:

1、先包含bstNode* root作为根节点,在通过根节点的左右指针延伸出整棵树;

2、封装了一些会用到的方法:搜索指定值(Search)、找出一颗子树中的最小值(treeMin)、插入指定值(Insert)、删除指定值(Delete)、判断是否是叶子结点(isLeaf)、判断是否有两个孩子(isNodeWithTwoChild)、

三种遍历方式(前序PreorderTraversal、中序InorderTraversal、后序Postodertraversal)、删除所有节点(DeleteAllNodes)、广度搜索进行周游(BFTraversal)、横着画图(Graph)、返回根节点(getRoot)、判断树空(isEmpty)

默认构造函数、vector为参数的构造函数、数组和长度为参数的构造函数、析构函数。

注意在这里为了防止公有方法直接调用私有数据,采用了创建以"__"开头的私有方法,让公有方法先来调用该私有方法,再让私有方法来调用私有数据,以确保其安全性。

#ifndef TEST1_MYBST_H
#define TEST1_MYBST_H #include <iomanip>
#include "bstNode.h"
#include <vector>
#include <deque>
#include <iostream>
using namespace std; template <typename T>
class myBST{
private:
bstNode<T> * root = nullptr;
bstNode<T> * __search(bstNode<T> * root , const T &key){
if (nullptr == root)
return nullptr;
if (key == root->data)
return root;
else if (key < root->data)
return __search(root->left, key);
else
return __search(root->right, key);
} //查找关键字是否存在
bstNode<T> * __treeMin(bstNode<T> * root , bstNode<T> * &parent){
bstNode<T> * curr = root;
while(curr->left!= nullptr){
parent = curr;
curr = curr->left;
}
return curr;
} //返回最小节点(一路向左)
bool __Insert(const T &key){
bstNode<T> * temp = new bstNode<T>(key);
bstNode<T> * parent = nullptr;
if(isEmpty()){
root=temp;
return true;
}
else{
bstNode<T> * curr;
curr = root;
while(curr){
parent = curr;
if(temp->data>curr->data) curr=curr->right;
else curr = curr->left;
}
if(temp->data<parent->data){
parent->left=temp;
return true;
}
else {
parent->right = temp;
return true;
}
}
return false;
} //插入指定值
bool __Delete(const T &key){
bool found = false;//存储有没有找到key的变量
if(isEmpty()){
cerr<<"BST为空"<<endl;
return false;
}
bstNode<T> * curr = root;
bstNode<T> * parrent = nullptr;
while(curr!= nullptr) {
if (key == curr->data) {
found = true;
break;
} else {
parrent = curr;
if (key < curr->data) curr = curr->left;
else curr = curr->right;
}
}
if(!found){
cerr<<"未找到key!"<<endl;
return false;
}
if (parrent == nullptr){//删除根节点
root = nullptr;
delete(curr);
return true;
}
/*
删除的节点有三种可能:
1、叶子结点
2、一个孩子的节点
3、两个孩子的节点
*/
if (__isLeaf(curr)){ //删除的点是叶子结点
if(parrent->left==curr) parrent->left= nullptr;
else parrent->right= nullptr;
delete(curr);
return true;
}
else if(__isNodeWithTwoChild(curr)){ //是两个孩子的节点
//以当前右子树中的最小值取代他
bstNode<T> * parrent = curr;
bstNode<T> * tmp = __treeMin(curr->right,parrent);
curr->data = tmp->data;
if(parrent->right==tmp)
parrent->right== nullptr;
else parrent->left== nullptr;
delete(tmp);
return true;
}
else{ //只有一个孩子的节点
if(curr->left!= nullptr){
if(curr->left == curr){
parrent->left=curr->left;
delete(curr);
return true;
}
else{
parrent->right=curr->right;
delete(curr);
return true;
}
}
if(curr->right!= nullptr){
if(curr->left == curr){
parrent->left=curr->left;
delete(curr);
return true;
}
else{
parrent->right=curr->right;
delete(curr);
return true;
}
}
}
return false;
} //删除指定值
bool __isLeaf(bstNode<T> * const & root){
if(root->left== nullptr && root->right== nullptr) return true;
else return false;
}//判断是否是叶子节点
bool __isNodeWithTwoChild(bstNode<T> * const & root){
if(root->left!= nullptr && root->right!= nullptr) return true;
else return false;
}//判断是否有两个孩子
void __InorderTraversal(bstNode<T> *root,std::vector<int>&result){
if(nullptr == root) return;
__InorderTraversal(root->left,result);
cout<<root->data<<" ";
result.push_back(root->data);
__InorderTraversal(root->right,result);
}//中序遍历
void __PreorderTraversal(bstNode<T> *root,std::vector<int>&result){
if(nullptr == root) return;
cout<<root->data<<" ";
result.push_back(root->data);
__InorderTraversal(root->left,result);
__InorderTraversal(root->right,result);
}//前序遍历
void __PostorderTraversal(bstNode<T> *root,std::vector<int>&result){
if(nullptr == root) return;
__InorderTraversal(root->left,result);
__InorderTraversal(root->right,result);
cout<<root->data<<" ";
result.push_back(root->data);
}//后序遍历
void __DeleteAllNodes(bstNode<T> *root){
if (root == nullptr) return;
__DeleteAllNodes(root->left);
__DeleteAllNodes(root->right);
__Delete(root->data);
}//删除所有节点
void __BFTraversal(vector<T>&result) {
deque<bstNode<T> *> TQueue;
bstNode<T> *pointer = root;
if (pointer != nullptr) {
TQueue.push_back(pointer);
}
while (!TQueue.empty()) {
pointer = TQueue.front();
TQueue.pop_front();
cout << pointer->data << " ";
result.push_back(pointer->data);
if (pointer->left != nullptr) TQueue.push_back(pointer->left);
if (pointer->right != nullptr) TQueue.push_back(pointer->right);
}
} //广度搜索来进行周游
void __Graph(int indent,bstNode<T>* root){
if(root != ){
__Graph(indent + , root->right);
cout<<setw(indent)<<" "<<root->data<<endl;
__Graph(indent + , root->left);
}
} //横着画图的内部接口
bstNode<T> * __GetRoot(){
return root;
} //返回根节点的内部接口
public:
myBST(){
root = nullptr;
} //默认构造
myBST(vector<T> arr){
root = nullptr;
for(int i =;i<(int)arr.size();i++){
__Insert(arr[i]);
}
}
myBST(T * arr,int len){
root = nullptr;
for(int i =;i<len;i++){
__Insert(*(arr+i));
}
}
~myBST(){
bstNode<T> * curr = root;
__DeleteAllNodes(curr);
}//析构
bool isEmpty() const{
return root == nullptr;
}//判断树空
bool search(const T &key){
bstNode<T> * temp = __search(root, key);
return (temp == nullptr) ? false : true;
}//查找关键字是否存在的对外接口
bool Insert(const T &key){
return __Insert(key);
}//插入节点的外部接口
bool Delete(const T &key){
return __Delete(key);
}//删除节点的外部接口
void InorderTraversal(vector<T>&result){
__InorderTraversal(root, result);
}//中序遍历的外部接口
void PreorderTraversal(vector<T>&result){
__PreorderTraversal(root, result);
}//前序遍历的外部接口
void PostorderTraversal(vector<T>&result){
__PostorderTraversal(root, result);
}//后序遍历的外部接口
void BFTraversal(vector<T>&result){
return __BFTraversal(result);
} //广度搜索外部接口
void Graph(int indent,bstNode<T>* root){
return __Graph(indent,root);
} //横着画图的外部接口
bstNode<T> * GetRoot(){
return __GetRoot();
} //返回根节点的外部接口
}; #endif //TEST1_MYBST_H

最后来进行测试:

main.cpp

#include <iostream>
#include <vector>
#include "myBST.h"
#include "bstNode.h"
using namespace std;
int main() {
vector<int> in = {,,,,,,,,,};
myBST<int> bst(in);
bst.Delete();
bst.Insert();
bool found = bst.search();
if(!found)
cout<<"not found!"<<endl;
else
cout<<"found!"<<endl;
vector<int> result;
cout<<"InorderTravelsal: ";
bst.InorderTraversal(result);
cout<<endl<<"PreorderTravelsal: ";
bst.PreorderTraversal(result);
cout<<endl<<"PostorderTraversal: ";
bst.PostorderTraversal(result);
cout<<endl<<"BFTraversal: ";
bst.BFTraversal(result);
cout<<endl<<"Graph:"<<endl;
bstNode<int>* pointer = bst.GetRoot();
bst.Graph(,pointer);
return ;
}

得到图示结果:

参考:https://blog.csdn.net/zhangxiao93/article/details/51444972

数据结构学习-BST二叉查找树 : 插入、删除、中序遍历、前序遍历、后序遍历、广度遍历、绘图的更多相关文章

  1. 已知前序(后序)遍历序列和中序遍历序列构建二叉树(Leetcode相关题目)

    1.文字描述: 已知一颗二叉树的前序(后序)遍历序列和中序遍历序列,如何构建这棵二叉树? 以前序为例子: 前序遍历序列:ABCDEF 中序遍历序列:CBDAEF 前序遍历先访问根节点,因此前序遍历序列 ...

  2. TZOJ 3209 后序遍历(已知中序前序求后序)

    描述 在数据结构中,遍历是二叉树最重要的操作之一.所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问. 这里给出三种遍历算法. 1.中序遍历的递归算法定义:  ...

  3. PAT甲题题解-1119. Pre- and Post-order Traversals (30)-(根据前序、后序求中序)

    (先说一句,题目还不错,很值得动手思考并且去实现.) 题意:根据前序遍历和后序遍历建树,输出中序遍历序列,序列可能不唯一,输出其中一个即可. 已知前序遍历和后序遍历序列,是无法确定一棵二叉树的,原因在 ...

  4. PTA L2-006 树的遍历-二叉树的后序遍历+中序遍历,输出层序遍历 团体程序设计天梯赛-练习集

    L2-006 树的遍历(25 分)   给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出一个正整数N(≤),是二叉树中结点的 ...

  5. 剑指offer面试题:输入某二叉树的前序遍历和中序遍历,输出后序遍历

    二叉树的先序,中序,后序如何遍历,不在此多说了.直接看题目描述吧(题目摘自九度oj剑指offer面试题6): 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结 ...

  6. 笔试算法题(36):寻找一棵二叉树中最远节点的距离 & 根据二叉树的前序和后序遍历重建二叉树

    出题:求二叉树中距离最远的两个节点之间的距离,此处的距离定义为节点之间相隔的边数: 分析: 最远距离maxDis可能并不经过树的root节点,而树中的每一个节点都可能成为最远距离经过的子树的根节点:所 ...

  7. [Swift]LeetCode889. 根据前序和后序遍历构造二叉树 | Construct Binary Tree from Preorder and Postorder Traversal

    Return any binary tree that matches the given preorder and postorder traversals. Values in the trave ...

  8. [二叉树建树]1119. Pre- and Post-order Traversals (30) (前序和后序遍历建立二叉树)

    1119. Pre- and Post-order Traversals (30) Suppose that all the keys in a binary tree are distinct po ...

  9. 数据结构学习:二叉查找树的概念和C语言实现

    什么是二叉查找树? 二叉查找树又叫二叉排序树,缩写为BST,全称Binary Sort Tree或者Binary Search Tree. 以下定义来自百度百科: 二叉排序树或者是一棵空树,或者是具有 ...

随机推荐

  1. 粗看ES6之字符串

    标签: javascript es6 字符串新增特性 新增二个方法 - startsWith/endsWith 字符串模板 - 反单引号的应用 startsWith 判断字符串以是否以某某开头,返回一 ...

  2. Django实战-用户注册和登陆系统

    1.环境搭建和创建项目 1.环境搭建 每当我们开始一个新项目的时候,通常都会搭建一个全新.独立.隔离的项目环境,这样做的好处自然不必多说.有很多种建立项目虚拟环境的工具,使用比较普遍的是Python中 ...

  3. WebAPI示例

    一.新建项目 二. 代码: Models.Products实体类 public class Product { /// <summary> /// 产品编号 /// </summar ...

  4. System.Data.SqlClient.SqlException: 从 datetime2 数据类型到 datetime 数据类型的转换产生一个超出范围的值

    System.Data.SqlClient.SqlException: 从 datetime2 数据类型到 datetime 数据类型的转换产生一个超出范围的值.解决办法是: 而这位大哥提出的解决办法 ...

  5. Azure 5 月新公布(二)

    Azure 5 月新发布(二):CDN 图片处理功能, CDN Restful API, 新版 CDN 管理门户, 计量名称变更延期  Azure CDN 图片处理功能开放公共预览版 Azure CD ...

  6. springboot项目搭建:结构和入门程序

    Spring Boot 推荐目录结构 代码层的结构 根目录:com.springboot 1.工程启动类(ApplicationServer.java)置于com.springboot.build包下 ...

  7. IIS 发表web 之后,访问注册表项失败得问题

    错误: 对注册表项“HKEY_LOCAL_MACHINE\SOFTWARE\xx\xxxx\xxxxx”的访问被拒绝. 解决办法: 打开IIS,找到应用程序池,然后找到自己web使用得程序池,右键高级 ...

  8. mysql语句的相关操作整理

    事实证明,如果不经常跟代码,语句打交道,人家可是会翻脸不认人的,大脑也会觉得一脸懵逼,不知道做错了啥,这次长点记性了,把语句整理出来,不仅加强对sql语句的记忆,还能有个笔记,以后大脑懵逼了还能回来看 ...

  9. CentOS7 设置开机自启

    [root@master-1 ~]# systemctl enable mariadb ln -s '/usr/lib/systemd/system/mariadb.service' '/etc/sy ...

  10. (python)剑指Offer:数组中重复的数字

    问题描述 在长度为n的数组中,所有的元素都是0到n-1的范围内. 数组中的某些数字是重复的,但不知道有几个重复的数字,也不知道重复了几次,请找出任意重复的数字. 例如,输入长度为7的数组{2,3,1, ...