2019-12-02

Data Structure 之 二叉排序树

二叉排序树是给定一个节点后,接下来插入的数如果比它大就会放到它的右孩子那边,比它小就会放到它的左孩子那边。

所以对于相同的一个节点下的左右孩子,左孩子 < 根节点 < 右孩子。

节点

由简单的左孩子和右孩子指针加上数据就可以构成一个节点。

//BST节点
struct BSTNode{
int data;
BSTNode *RightChild;
BSTNode *LeftChild;
BSTNode(){
RightChild = NULL;
LeftChild = NULL;
}
};

二叉排序树的类

多的功能不会只需要有一个root的根节点。

插入

插入操作是一个基本,写好后在建树的时候直接调用插入函数就可以将所有元素插入到树里面。

在这里有一个递归的思想但是没有用到函数递归调用的方法。

对于要插入的数,从根节点开始比较,如果比当前节点大就往当前节点右孩子方向走,否则相反。

void Insert(int num){

            BSTNode *temp = root;//记录头结点位置

            while(1){//模拟递归的遍历
if(num>temp->data){
if(temp->RightChild!=NULL){
temp=temp->RightChild;
}
else{//如果当前节点右孩子为NULL,则新建一个空间储存插入的数据
temp->RightChild = new BSTNode();
temp->RightChild->data = num;
break;
}
}
else{
if(temp->LeftChild!=NULL){
temp=temp->LeftChild;
}
else{
temp->LeftChild = new BSTNode();
temp->LeftChild->data = num;
break;
}
}
}
}

建树

写好了插入函数后建树就简单了,用数组num和数组大小当参数传递给creatBST函数。

将root节点的data赋值为num【0】,也就是数组第一个元素。

其他的元素用插入函数完成插入即可。

void creatBST(int num[],int n){    

            root = new BSTNode();
root->data = num[0]; for(int i=1;i<n;i++)
this->Insert(num[i]);
}

查找

查找的思路其实很简单,就是遍历一遍,这里下标采用中序遍历的计数。

int Find(int num){

            BSTNode *temp = root;

            int sum=0;

            while(1){
if(temp->RightChild==NULL&&temp->LeftChild==NULL&&num!=temp->data){
return -1;
}
sum++;
if(num==temp->data){
return sum;
}
else if(num>temp->data&&temp->RightChild!=NULL){
temp=temp->RightChild;
}
else if(num<temp->data&&temp->LeftChild!=NULL)
temp = temp->LeftChild;
}
}

删除

今天写删除花了特别多时间,最后还是面向CSDN编程,研究一波后发现了别人很多bug,自己又改动了下。

这里我参考那篇文章的dl就是删除第一个节点的时候会有bug,删除这个函数真的很虚,感觉写的贼菜...

总觉得有很多思路,很多方法,但是写出来就很难看...

void Delete(int num){

        BSTNode *temp, *previous;
temp = root;
previous = root;
//获得现在要删除的节点和它前一个节点
while (temp != NULL){ if (temp->data == num)
break;
else if (temp->data > num){
previous = temp;
temp = temp->LeftChild;
}
else{
previous = temp;
temp = temp->RightChild;
}
} if (temp != NULL){ if (temp->LeftChild == NULL){ //要删的结点的左孩子为空的情况 if (temp->RightChild==NULL){//右孩子也为空
if(previous==root) root = NULL; //如果是头结点只需把roor设为NULL
else{
previous->LeftChild==temp? previous->LeftChild = NULL: previous->RightChild = NULL;
delete temp;
}
}
else{//有右孩子,判断该节点是不是根节点或者是上一个节点的什么孩子 if(temp==root) root=root->RightChild;
else previous->LeftChild==temp ? previous->LeftChild=temp->RightChild :previous->RightChild=temp->RightChild;
delete temp;
}
}
else if (temp->RightChild == NULL){ //要删的结点的右孩子为空的情况,但是有左孩子 if(temp=root) root = root->LeftChild;
else previous->LeftChild == temp ? previous->LeftChild=temp->LeftChild :previous->RightChild=temp->LeftChild;
delete temp;
}
else{ //要删的结点的左、右孩子都不为空的情况
//把右子树最小节点的值赋给当前节点,删去右子树最小节点 ,右子树最小节点的右节点顶替原最小节点位置
BSTNode *right_min = temp->RightChild;
previous = right_min; while (right_min->LeftChild != NULL){ //找到右子树最小结点 previous = right_min;
right_min = right_min->LeftChild;
} temp->data = right_min->data; //最小结点的值赋给要删除的结点 if(right_min == previous){
temp->RightChild=right_min->RightChild;
}
else{
previous->LeftChild = right_min->RightChild;
}
delete right_min; //删除右子树的最小结点
}
}
}

插入、查找、删除样例如下:

/*
1
6
22 33 55 66 11 44
3
77
50
10
*/
/*1
6
22 33 55 66 11 44
7
11
22
33
44
55
66
77
*/
/*
1
6
22 33 55 66 11 44
3
66
22
77
*/

最后全部代码如下:

#include<iostream>
using namespace std;
//BST节点
struct BSTNode{
int data;
BSTNode *RightChild;
BSTNode *LeftChild;
BSTNode(){
RightChild = NULL;
LeftChild = NULL;
}
}; class BST{ private:
BSTNode *root;//根节点
void InOrder(BSTNode *t){//中序遍历
if(t!=NULL){
InOrder(t->LeftChild);
cout<<t->data<<" ";
InOrder(t->RightChild);
}
}
public: BST(){
} ~BST(){
} void creatBST(int num[],int n){ root = new BSTNode();
root->data = num[0]; for(int i=1;i<n;i++)
this->Insert(num[i]);
} void InOrder(){
if(root){
InOrder(root);
cout<<endl;
}
else
cout<<"No elements"<<endl;
} void Insert(int num){ BSTNode *temp = root; while(1){
if(num>temp->data){
if(temp->RightChild!=NULL){
temp=temp->RightChild;
}
else{
temp->RightChild = new BSTNode();
temp->RightChild->data = num;
break;
}
}
else{
if(temp->LeftChild!=NULL){
temp=temp->LeftChild;
}
else{
temp->LeftChild = new BSTNode();
temp->LeftChild->data = num;
break;
}
}
}
} int Find(int num){ BSTNode *temp = root; int sum=0; while(1){
if(temp->RightChild==NULL&&temp->LeftChild==NULL&&num!=temp->data){
return -1;
}
sum++;
if(num==temp->data){
return sum;
}
else if(num>temp->data&&temp->RightChild!=NULL){
temp=temp->RightChild;
}
else if(num<temp->data&&temp->LeftChild!=NULL)
temp = temp->LeftChild;
}
} void Delete(int num){ BSTNode *temp, *previous;
temp = root;
previous = root;
//获得现在要删除的节点和它前一个节点
while (temp != NULL){ if (temp->data == num)
break;
else if (temp->data > num){
previous = temp;
temp = temp->LeftChild;
}
else{
previous = temp;
temp = temp->RightChild;
}
} if (temp != NULL){ if (temp->LeftChild == NULL){ //要删的结点的左孩子为空的情况 if (temp->RightChild==NULL){//右孩子也为空
if(previous==root) root = NULL; //如果是头结点只需把roor设为NULL
else{
previous->LeftChild==temp? previous->LeftChild = NULL: previous->RightChild = NULL;
delete temp;
}
}
else{//有右孩子,判断该节点是不是根节点或者是上一个节点的什么孩子 if(temp==root) root=root->RightChild;
else previous->LeftChild==temp ? previous->LeftChild=temp->RightChild :previous->RightChild=temp->RightChild;
delete temp;
}
}
else if (temp->RightChild == NULL){ //要删的结点的右孩子为空的情况,但是有左孩子 if(temp=root) root = root->LeftChild;
else previous->LeftChild == temp ? previous->LeftChild=temp->LeftChild :previous->RightChild=temp->LeftChild;
delete temp;
}
else{ //要删的结点的左、右孩子都不为空的情况
//把右子树最小节点的值赋给当前节点,删去右子树最小节点 ,右子树最小节点的右节点顶替原最小节点位置
BSTNode *right_min = temp->RightChild;
previous = right_min; while (right_min->LeftChild != NULL){ //找到右子树最小结点 previous = right_min;
right_min = right_min->LeftChild;
} temp->data = right_min->data; //最小结点的值赋给要删除的结点 if(right_min == previous){
temp->RightChild=right_min->RightChild;
}
else{
previous->LeftChild = right_min->RightChild;
}
delete right_min; //删除右子树的最小结点
}
}
}
}; int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int num[100];
for(int i=0;i<n;i++)
cin>>num[i]; BST *bst = new BST();
bst->creatBST(num,n);
bst->InOrder(); int m;
cin>>m;
int b[100];
for(int i=0;i<m;i++){
cin>>b[i];
//bst->Insert(b[i]);
//cout<<bst->Find(b[i])<<endl;
bst->Delete(b[i]);
bst->InOrder(); }
}
}

DS-二叉排序树的插入、查找和删除的更多相关文章

  1. Java实现二叉排序树的插入、查找、删除

    import java.util.Random; /** * 二叉排序树(又称二叉查找树) * (1)能够是一颗空树 * (2)若左子树不空,则左子树上全部的结点的值均小于她的根节点的值 * (3)若 ...

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

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

  3. 数据结构系列之2-3-4树的插入、查找、删除和遍历完整版源代码实现与分析(dart语言实现)

    本文属于原创,转载请注明来源. 在上一篇博文中,详细介绍了2-3树的操作(具体地址:https://www.cnblogs.com/outerspace/p/10861488.html),那么对于更多 ...

  4. jQuery中的查找节点、创建节点、插入节点、删除节点、替换节点、复制节点操作方法

    jQuery操作节点我们可以分六点来讲,查找节点.创建节点.插入节点.删除节点.替换节点.复制节点. 一.查找节点 text() - 设置或返回所选元素的文本内容   ,html() - 设置或返回所 ...

  5. mysql插入数据与删除重复记录的几个例子(收藏)

    mysql插入数据与删除重复记录的几个例子 12-26shell脚本实现mysql数据的批量插入 12-26mysql循环语句插入数据的例子 12-26mysql批量插入数据(insert into ...

  6. SQL重复记录处理(查找,过滤,删除)

    SQL重复记录处理(查找,过滤,删除)     ID int    Title nvarchar(50)    AddDate datetime    数据  www.2cto.com     ID ...

  7. 有关文件夹与文件的查找,删除等功能 在 os 模块中实现

    最近在写的程序频繁地与文件操作打交道,这块比较弱,还好在百度上找到一篇不错的文章,这是原文传送门,我对原文稍做了些改动. 有关文件夹与文件的查找,删除等功能 在 os 模块中实现.使用时需先导入这个模 ...

  8. STL中vector的赋值,遍历,查找,删除,自定义排序——sort,push_back,find,erase

    今天学习网络编程,那个程序中利用了STL中的sort,push_back,erase,自己没有接触过,今天学习一下,写了一个简单的学习程序.编译环境是VC6.0         这个程序使用了vect ...

  9. Java中数组的几个常用算法:插入算法,删除算法,冒泡排序算法

    前言: 在Java中我们常常会用数组,提到数组就不得不介绍数组中常用到的几个算法. 有插入算法,删除算法,冒泡排序算法等. 在学习这几个数组的算法前,我们先来了解一下关于数组一些基本知识. 数组的基本 ...

随机推荐

  1. 2019 计蒜之道 复赛 D. “星云系统”(单调栈)

    VIPKID 是在线少儿英语教育平台,网络稳定是在线教育课程质量的红线,VIPKID 为此推出了全球最稳定的教育网络系统 -- "星云系统".星云系统目前建立了覆盖全球 3535 ...

  2. Dinic最大流 || Luogu P3376 【模板】网络最大流

    题面:[模板]网络最大流 代码: #include<cstring> #include<cstdio> #include<iostream> #define min ...

  3. MySQL常见的三种存储引擎

    原文链接:https://www.cnblogs.com/yuxiuyan/p/6511837.html 简单来说,存储引擎就是指表的类型以及表在计算机上的存储方式. 存储引擎的概念是MySQL的特点 ...

  4. Linux为程序员添加了行为准则

    假如你是开发人员,如果您密切关注Linux开发,您就会知道Linux内核讨论会非常热烈.最近,LinusTorvalds承认Linux内核邮件列表(LKML)和其他Linux开发空间对许多人都是敌对的 ...

  5. JVM内存结构之本地方法栈

    Native Method Stacks(本地方法栈) 本地方法:指不是用Java语言编写的方法,因为Java语言是有一定限制的,有些情况下它是不能直接和操作系统打交道的.这时就需要调用一些用C或C+ ...

  6. 【BZOJ1488】[HNOI2009]图的同构计数

    题目链接 题意 求 n 个点的同构意义下不同的图的数量.\((n\leq 60)\) Sol \(Polya\) 定理的练手题. 我们这里先把边的存在与否变成对边进行黑白染色,白色代表不存在,这样就变 ...

  7. RMI实现方案

  8. UE4 质心相关

    Add force 始终给质心施加力,即使手动偏移了质心(Center of mass)也不例外. Add force at location local 相对于物体的原始质心位置增加一个偏移值后的位 ...

  9. [django]上下文管理器

    上下文管理器django提取context中的数据去供模板调用 需求: 所有的页面都需要一个特定的变量 本质: python函数 , 接收一个HttpRequest对象的参数 , 且返回的必须是一个字 ...

  10. Linux驱动开发3——devfs udev procfs sysfs debugfs傻傻地分不清楚

    Linux调试文件系统 1.1.procfs 早期的Linux内核中,内核通过procfs输出调试信息,可以在用户态通过读写procfs节点与内核进行交互,用来获取处理器.内存.设备驱动.进程等各种信 ...