搜索二叉树是一种具有良好排序和查找性能的二叉树数据结构,包括多种操作,本篇只介绍插入,排序(遍历),和删除操作,重点是删除操作比较复杂,用到的例子也是本人亲自画的

用到的测试图数据例子

第一、构建节点

 template <typename T> class BST;
template <typename T> class BSTNode {
public:
friend class BST<T>;
BSTNode() {
lChild = rChild = parent = NULL;
data = NULL;
}
BSTNode(T d) {
lChild = rChild = parent = NULL;
data = d;
}
private:
BSTNode<T> *lChild, *rChild, *parent;
T data;
};

第二、二叉树头文件定义

 template<typename T> class BST {
public:
BST() { } //插入操作
void insert(BSTNode<T>*node); //二叉查找树的中序遍历,就相当于排序了
void inSort(BSTNode<T>*node); //按节点删除
void deleteNode(BSTNode<T>* node); //按数值删除
void deleteNode(const T& t); BSTNode<T>* search(T key);
BSTNode<T>* root=NULL; private:
int count;
};

第三、搜索二叉树的插入

1)如果二叉树查找树为空节点,则插入节点就为根节点

2)如果二叉查找树为非空节点,就需要先找到待插入节点,查找原则就是从根节点开始,如果大于根就右边走,小于根就左边走,直到找到合适节点,

下面代码中的最终找到的temp 就是待插入节点.

 template<typename T>
void BST<T>::insert(BSTNode<T>* node)
{
BSTNode<T>* curr, *temp = NULL;
curr = root;
while (NULL!= curr) //遍历二叉树,找到应该插入的父节点
{
temp = curr;
if (node->data>curr->data)
{
curr = curr->rChild;
}
else {
curr = curr->lChild;
}
}
node->parent = temp;//temp 代码当前最后遍历的node,设置node->parent为该节点
if (temp==NULL)
{
root = node;
count++;
}
else {
if (node->data<temp->data)
{
temp->lChild = node;
count++;
}
else {
temp->rChild = node;
count++;
}
}
}

第四、搜索二叉树的删除

删除包含多种情况,

1. 如果节点没有子女,修改其父节点指针为NULL,删除即可

2. 如果该节点有左孩子情况,修改其父亲节点的指针和其左孩子的parent指针即可

3. 如果该节点有右孩子情况,修改其父亲节点的指针和其右孩子的parent指针即可

4.如果同时有左右孩子的情况,情况比较复杂,一般有2种方法处理

1) 用节点右边孩子的最小值替换该节点,其他节点位置保持不变(本篇用这种方法)

2)用节点左边孩子的最大值替换该节点,其他节点位置保持不变

后面测试例子是删除18 node,通过程序找到右边最小值20,用20 替换18,其他节点位置保持不动。

 template<typename T>
inline void BST<T>::deleteNode(BSTNode<T>* node)
{
BSTNode<T>*p = node->parent;//获取node的父节点,这里很重要
if (node->lChild==NULL && node->rChild==NULL) //叶子节点直接删除
{
if (node==node->parent->lChild)
{
node->parent->lChild = NULL;
}
else {
node->parent->rChild = NULL;
}
delete node;
count--;
}
else if (node->rChild != NULL && node->lChild == NULL) {//存在右孩子
if (p==NULL)//说明节点为根节点
{
root = node->rChild;
count--;
}
else {
node->rChild->parent = p;
if (p->lChild==node) //判断是父节点的左孩子还是右孩子
{
p->lChild = node->rChild;
}
else {
p->rChild = node->rChild;
}
delete node;
count--;
}
}
else if (node->lChild!=NULL && node->rChild==NULL)//存在左孩子
{
if (p==NULL)
{
root = root->lChild;
count--;
}
else {
node->lChild->parent = p;
if (p->lChild==node)
{
p->lChild = node->lChild;
}
else {
p->rChild = node->lChild;
}
delete node;
count--;
}
}
else {
BSTNode<T>*left, *curp=NULL;
left = node->rChild; //本方案是找右侧最小值,替换node节点,其他节点保持不动即可
while (left!=NULL)
{
curp = left;
left = left->lChild;
} if (curp->rChild!=NULL)
{
if (curp->lChild==curp)
{
curp->parent->lChild = curp->rChild;
}
else {
curp->parent->rChild = curp->rChild;
}
}
else {
if (curp->parent->lChild==curp)
{
curp->parent->lChild = NULL;
}
else {
curp->parent->rChild = NULL;
}
//curp->parent->lChild = NULL;
}
//替curp 替换 node
curp->parent = p;
curp->lChild = node->lChild;
curp->rChild = node->rChild; if (p->lChild==node)//判断node 是p 的左孩子还是右孩
{
p->lChild = curp;
}
else {
p->rChild = curp;
}
delete node;
count--;
}
}

第五、二叉树的搜索查找

由于搜索二叉树本身是已经排序好的,查找过程相对简单,从根节点,逐个排查,大于根向右,小于根向左,直到叶子节点.

template<typename T>
inline BSTNode<T>* BST<T>::search(T k)
{
BSTNode<T>*node = root;
while (node!=NULL)
{
if (k<node->data)
{
node = node->lChild;
}
else if (k> node->data)
{
node = node->rChild;
}
else {
break;
}
}
return node;
}

第六、二叉搜索树的排序

根据二叉所有树的特性,这里所谓排序,其实就是二叉树的中序遍历,其他的几种遍历不在这里赘述,知识调整下结构即可

template<typename T>
void BST<T>::inSort(BSTNode<T>* node)
{
if (node!=NULL)
{
inSort(node->lChild);
std::cout << node->data<<",";
inSort(node->rChild);
}
}

第七、测试程序

 #include "pch.h"
#include <iostream>
#include "BSTree.h"
using namespace std; int main()
{
// 树结构示意
// 30
// / \
// 15 25
// / \
//9 18
// / \
// 16 25
// / \
// 20 26
BST<int> sbt;
sbt.insert(new BSTNode<int>());
sbt.insert(new BSTNode<int>());
sbt.insert(new BSTNode<int>());
sbt.insert(new BSTNode<int>());
sbt.insert(new BSTNode<int>());
sbt.insert(new BSTNode<int>());
sbt.insert(new BSTNode<int>());
sbt.insert(new BSTNode<int>());
sbt.insert(new BSTNode<int>()); cout << "搜索树排序后:";
sbt.inSort(sbt.root); sbt.deleteNode(); cout << endl << "删除18 后排序:"; sbt.inSort(sbt.root);
}

测试结果

所有完整程序代码

 #pragma once
template <typename T> class BST;
template <typename T> class BSTNode {
public:
friend class BST<T>;
BSTNode() {
lChild = rChild = parent = NULL;
data = NULL;
}
BSTNode(T d) {
lChild = rChild = parent = NULL;
data = d;
}
private:
BSTNode<T> *lChild, *rChild, *parent;
T data;
}; template<typename T> class BST {
public:
BST() { } //插入操作
void insert(BSTNode<T>*node); //二叉查找树的中序遍历,就相当于排序了
void inSort(BSTNode<T>*node); //按节点删除
void deleteNode(BSTNode<T>* node); //按数值删除
void deleteNode(const T& t); BSTNode<T>* search(T key);
BSTNode<T>* root=NULL; private:
int count;
}; template<typename T>
void BST<T>::insert(BSTNode<T>* node)
{
BSTNode<T>* curr, *temp = NULL;
curr = root;
while (NULL!= curr) //遍历二叉树,找到应该插入的父节点
{
temp = curr;
if (node->data>curr->data)
{
curr = curr->rChild;
}
else {
curr = curr->lChild;
}
}
node->parent = temp;//temp 代码当前最后遍历的node,设置node->parent为该节点
if (temp==NULL)
{
root = node;
count++;
}
else {
if (node->data<temp->data)
{
temp->lChild = node;
count++;
}
else {
temp->rChild = node;
count++;
}
}
} template<typename T>
void BST<T>::inSort(BSTNode<T>* node)
{
if (node!=NULL)
{
inSort(node->lChild);
std::cout << node->data<<",";
inSort(node->rChild);
}
} template<typename T>
inline void BST<T>::deleteNode(BSTNode<T>* node)
{
BSTNode<T>*p = node->parent;//获取node的父节点,这里很重要
if (node->lChild==NULL && node->rChild==NULL) //叶子节点直接删除
{
if (node==node->parent->lChild)
{
node->parent->lChild = NULL;
}
else {
node->parent->rChild = NULL;
}
delete node;
count--;
}
else if (node->rChild != NULL && node->lChild == NULL) {//存在右孩子
if (p==NULL)//说明节点为根节点
{
root = node->rChild;
count--;
}
else {
node->rChild->parent = p;
if (p->lChild==node) //判断是父节点的左孩子还是右孩子
{
p->lChild = node->rChild;
}
else {
p->rChild = node->rChild;
}
delete node;
count--;
}
}
else if (node->lChild!=NULL && node->rChild==NULL)//存在左孩子
{
if (p==NULL)
{
root = root->lChild;
count--;
}
else {
node->lChild->parent = p;
if (p->lChild==node)
{
p->lChild = node->lChild;
}
else {
p->rChild = node->lChild;
}
delete node;
count--;
}
}
else {
BSTNode<T>*left, *curp=NULL;
left = node->rChild; //本方案是找右侧最小值,替换node节点,其他节点保持不动即可
while (left!=NULL)
{
curp = left;
left = left->lChild;
} if (curp->rChild!=NULL)
{
if (curp->lChild==curp)
{
curp->parent->lChild = curp->rChild;
}
else {
curp->parent->rChild = curp->rChild;
}
}
else {
if (curp->parent->lChild==curp)
{
curp->parent->lChild = NULL;
}
else {
curp->parent->rChild = NULL;
}
//curp->parent->lChild = NULL;
}
//替curp 替换 node
curp->parent = p;
curp->lChild = node->lChild;
curp->rChild = node->rChild; if (p->lChild==node)//判断node 是p 的左孩子还是右孩
{
p->lChild = curp;
}
else {
p->rChild = curp;
}
delete node;
count--;
}
} template<typename T>
inline void BST<T>::deleteNode(const T & k)
{
BSTNode<T>*node = search(k);
if (node!=NULL)
{
deleteNode(node);
}
} template<typename T>
inline BSTNode<T>* BST<T>::search(T k)
{
BSTNode<T>*node = root;
while (node!=NULL)
{
if (k<node->data)
{
node = node->lChild;
}
else if (k> node->data)
{
node = node->rChild;
}
else {
break;
}
}
return node;
}

BSTree.h

c++ 搜索二叉树 插入,删除,遍历操作的更多相关文章

  1. 【数据结构】——搜索二叉树的插入,查找和删除(递归&非递归)

    一.搜索二叉树的插入,查找,删除 简单说说搜索二叉树概念: 二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值 若它的右 ...

  2. C 线性表的链式存储实现及插入、删除等操作示例

    一.链式存储的优势 线性表的存储可以通过顺序存储或链式存储实现,其中顺序存储基于数组实现(见本人上一篇博客),在进行插入删除等操作时,需对表内某一部分元素逐个移动,效率较低.而链式结构不依赖于地址连续 ...

  3. [LeetCode] Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复

    Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...

  4. [LeetCode] 381. Insert Delete GetRandom O(1) - Duplicates allowed 常数时间内插入删除和获得随机数 - 允许重复

    Design a data structure that supports all following operations in average O(1) time. Note: Duplicate ...

  5. Java创建二叉搜索树,实现搜索,插入,删除操作

    Java实现的二叉搜索树,并实现对该树的搜索,插入,删除操作(合并删除,复制删除) 首先我们要有一个编码的思路,大致如下: 1.查找:根据二叉搜索树的数据特点,我们可以根据节点的值得比较来实现查找,查 ...

  6. 数据结构--Avl树的创建,插入的递归版本和非递归版本,删除等操作

    AVL树本质上还是一棵二叉搜索树,它的特点是: 1.本身首先是一棵二叉搜索树.   2.带有平衡条件:每个结点的左右子树的高度之差的绝对值最多为1(空树的高度为-1).   也就是说,AVL树,本质上 ...

  7. Java实现二叉树的创建和遍历操作(有更新)

    博主强烈建议跳过分割线前面的部分,直接看下文更新的那些即可. 最近在学习二叉树的相关知识,一开始真的是毫无头绪.本来学的是C++二叉树,但苦于编译器老是出故障,于是就转用Java来实现二叉树的操作.但 ...

  8. jQuery---jq操作标签文本(html(),text()),jq操作文档标签(插入,删除,修改),克隆,,jq操作属性,jq操作class属性,jq操作表单value,jq操作css,jq操作盒子(重要),jq操作滚动条

    jQuery---jq操作标签文本(html(),text()),jq操作文档标签(插入,删除,修改),克隆,,jq操作属性,jq操作class属性,jq操作表单value,jq操作css,jq操作盒 ...

  9. c++排序二叉树的出现的私有函数讨论,以及二叉树的删除操作详解

    c++排序二叉树的出现的私有函数讨论, 以及二叉树的删除操作详解 标签(空格分隔): c++ 前言 我在c++学习的过程中, 最近打了一个排序二叉树的题目,题目中出现了私有函数成员,当时没有理解清楚这 ...

随机推荐

  1. 概念:GNU构建系统和Autotool

    经常使用Linux的开发人员或者运维人员,可能对configure->make->make install相当熟悉.事实上,这叫GNU构建系统,利用脚本和make程序在特定平台上构建软件. ...

  2. Faster R-CNN改进篇(二): RFCN ● RON

    @改进1:RFCN 论文:R-FCN: Object Detection via Region-based Fully Convolutional Networks    [点击下载] MXNet代码 ...

  3. EasyDSS流媒体服务器实现RTMP直播同步HLS录像和时移回放

    本文转自EasyDarwin团队成员Alex的博客:http://blog.csdn.net/cai6811376/article/details/74166337 "目前在市面上可以找到的 ...

  4. go语言学习 strings常用函数

    strings包中的函数用法 参考链接http://studygolang.com/articles/88 1.strings.replace() 函数原型 func Replace(str1, ol ...

  5. 20179223《Linux内核原理与分析》第四周学习笔记

    补交第三周作业 完成一个简单的时间片轮转多道程序内核 1.使用实验楼的虚拟机打开shell,用cd LinuxKernel/linux-3.9.4进入linux-3.9.4. 2.执行命令qemu - ...

  6. jdbcTemplate的一些常用方法

    前言 最近的项目中由于只进行查询,所以使用了jdbcTemplate来直接操作sql进行持久层的操作,初次接触jdbcTemplate,从最开始的什么都不知道到现在基本方法都大致知道什么意思,特此记录 ...

  7. 应该抛出什么异常?不应该抛出什么异常?(.NET/C#)

    我在 .NET/C# 建议的异常处理原则 中描述了如何 catch 异常以及重新 throw.然而何时应该 throw 异常,以及应该 throw 什么异常呢? 究竟是谁错了? 代码中从上到下从里到外 ...

  8. CentOS 6.6下安装OpenOffice4.0

    最近由于项目需要,要在公司服务器上安装Openoffice,网上搜了一些资料后成功安装,现分享给大家. 1.首先先下载好需要的rpm包:Apache_OpenOffice_4.0.0_Linux_x8 ...

  9. python第三方库

    autopy autopy是一个自动化操作的python库,可以模拟一些鼠标.键盘事件,还能对屏幕进行访问 pywin32 win32api的python封装 PIL python的图形图像处理框架

  10. ballerina 学习二 ballerina 命令参数

    1.  目前支持的命令 run Run Ballerina program build Compile Ballerina program install Install packages to ho ...