数据结构学习-BST二叉查找树 : 插入、删除、中序遍历、前序遍历、后序遍历、广度遍历、绘图
二叉查找树(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二叉查找树 : 插入、删除、中序遍历、前序遍历、后序遍历、广度遍历、绘图的更多相关文章
- 已知前序(后序)遍历序列和中序遍历序列构建二叉树(Leetcode相关题目)
1.文字描述: 已知一颗二叉树的前序(后序)遍历序列和中序遍历序列,如何构建这棵二叉树? 以前序为例子: 前序遍历序列:ABCDEF 中序遍历序列:CBDAEF 前序遍历先访问根节点,因此前序遍历序列 ...
- TZOJ 3209 后序遍历(已知中序前序求后序)
描述 在数据结构中,遍历是二叉树最重要的操作之一.所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结点均做一次且仅做一次访问. 这里给出三种遍历算法. 1.中序遍历的递归算法定义: ...
- PAT甲题题解-1119. Pre- and Post-order Traversals (30)-(根据前序、后序求中序)
(先说一句,题目还不错,很值得动手思考并且去实现.) 题意:根据前序遍历和后序遍历建树,输出中序遍历序列,序列可能不唯一,输出其中一个即可. 已知前序遍历和后序遍历序列,是无法确定一棵二叉树的,原因在 ...
- PTA L2-006 树的遍历-二叉树的后序遍历+中序遍历,输出层序遍历 团体程序设计天梯赛-练习集
L2-006 树的遍历(25 分) 给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列.这里假设键值都是互不相等的正整数. 输入格式: 输入第一行给出一个正整数N(≤),是二叉树中结点的 ...
- 剑指offer面试题:输入某二叉树的前序遍历和中序遍历,输出后序遍历
二叉树的先序,中序,后序如何遍历,不在此多说了.直接看题目描述吧(题目摘自九度oj剑指offer面试题6): 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树.假设输入的前序遍历和中序遍历的结 ...
- 笔试算法题(36):寻找一棵二叉树中最远节点的距离 & 根据二叉树的前序和后序遍历重建二叉树
出题:求二叉树中距离最远的两个节点之间的距离,此处的距离定义为节点之间相隔的边数: 分析: 最远距离maxDis可能并不经过树的root节点,而树中的每一个节点都可能成为最远距离经过的子树的根节点:所 ...
- [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 ...
- [二叉树建树]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 ...
- 数据结构学习:二叉查找树的概念和C语言实现
什么是二叉查找树? 二叉查找树又叫二叉排序树,缩写为BST,全称Binary Sort Tree或者Binary Search Tree. 以下定义来自百度百科: 二叉排序树或者是一棵空树,或者是具有 ...
随机推荐
- java并发编程 volatile关键字 精准理解
1.volatile的作用 一个线程共享变量(类的成员变量.类的静态成员变量等)被volatile修饰之后,就具有以下作用: 1)并发中的变量可见性(不同线程对该变量进行操作时的可见性),即一个线程修 ...
- C语言的各种输入情况介绍(ACM中常用到)
1.最简单的输入输出形式: 计算a+b的值: scanf("%d%d",&a,&b); printf("%d\n",a+b);--------- ...
- 微信小程序电商实战-首页(下)
好了,上一期我们把首页搜索.导航栏和广告轮播给做完了,那么接下来会继续完成我们首页的剩余部分,先看我们要实现的效果吧! 本期实现效果图.gif 本期我们要实现首页的实时热销榜.福利专场和左下方个人 ...
- ArcGIS创建要素类
在使用ARCGIS软件进行工作时,免不了要建立地理数据库和要素类之类的.一下是我创建文件地理数据库并在数据库中创建要素类写相关步骤: 1.启动软件,可以使用ARCCatalog直接进行创建也可以使用A ...
- python3绘图示例2(基于matplotlib:柱状图、分布图、三角图等)
#!/usr/bin/env python# -*- coding:utf-8 -*- from matplotlib import pyplot as pltimport numpy as npim ...
- vos优化客户线路数量
问题: 客户A打电话过来说之前给开的300线路不够用了,今天好多电话呼不出去了,线路太挤了! 麻烦增加线路,如何操作? 方法: 登陆VOS——在线对接——(客户A的对接网关ID)——双击 打开网关管理 ...
- C# 安装 Visual Studio IDE
官网: https://visualstudio.microsoft.com/zh-hans/ 下载社区版(免费的) .微软的软件安装都是很nice的.安装过程中选择需要的配置进行安装(比如.net桌 ...
- php通过gbk编码判断 含有连续数字 可用于判断QQ号,手机号等。
有可能有些输入,不希望让用户的评论或者私信中含有类似于QQ号,手机号的文本,比如交友网站.还有些恶意SEO通过,构造恶意检索词,检索词中包含QQ,手机号等,让百度爬取到,增加展现.也需要将这些检索词屏 ...
- IOS GCD(线程的 串行、并发 基本使用)
什么是GCD 全称是Grand Central Dispatch,可译为“牛逼的中枢调度器” 纯C语言,提供了非常多强大的函数 GCD的优势 GCD是苹果公司为多核的并行运算提出的解决方案 GCD会自 ...
- eclips新建Maven Web项目
一.创建项目 1.Eclipse中用Maven创建项目 上图中Next 2.继续Next 3.选maven-archetype-webapp后,next 4.填写相应的信息,Packaged是默认创建 ...