博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【数据结构】5.2 二叉搜索树的创建查找以及插入操作
阅读量:4841 次
发布时间:2019-06-11

本文共 7897 字,大约阅读时间需要 26 分钟。

首先何为二叉搜索树?

二叉查找树(Binary Search Tree),(又:二叉搜索树,二叉排序树)它或者是一棵空树,或者是具有下列性质的二叉树: 若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。

二叉排序树的查找过程和次优二叉树类似,通常采取二叉链表作为二叉排序树的存储结构。中序遍历二叉排序树可得到一个关键字的有序序列,一个无序序列可以通过构造一棵二叉排序树变成一个有序序列,构造树的过程即为对无序序列进行排序的过程。每次插入的新的结点都是二叉排序树上新的叶子结点,在进行插入操作时,不必移动其它结点,只需改动某个结点的指针,由空变为非空即可。搜索,插入,删除的复杂度等于树高,O(log(n)).

结构体定义,为了方便起见,data用int型,读者可以自己更改成模板

 

struct BTNode {    int data;    BTNode *lchild,*rchild;};

 

这个没啥好解释的,就是树的结点标准定义,一个数据域,两个孩子指针

类定义

class BTree {private:    BTNode *root;                    //二叉搜索树的根结点    void creat(int loc, BTNode *p); //创建二叉搜索树,递归形式创建,私有函数    void travel(BTNode *p);            //用来遍历(中序),输出时候需要调用的    int *data, number;                //这个是用来存储输入的数组,估计不需要了,下一个版本会删除    void search(int key, BTNode *p, bool &flag);    //查找,其实这个查找方法和二分法类似    void insert(BTNode *p, int x);        //插入函数public:    BTree(int a[], int n);    void Creat();    void Insert(int x);    void Search(int key);    void Print();};

本代码采用封装方式,即具体对于root的操作全是由私有函数来进行的,一方面是安全另一方面是代码看起来很整洁

构造函数

BTree::BTree(int a[], int n){    int mid = a[0];        //把第一个数据作为二叉树的根结点的数值    root = new BTNode();    root->data = mid;    root->lchild = root->rchild = NULL;    number = n;    data = new int[number];    for (int i = 0; i < number; i++)    {        data[i] = a[i];           }}

构造函数只有两个功能,一是创建根结点还有给类中自带的数组拷贝复制

数组有点多余,因为我当时是先写creat函数的,感觉creat调用的参数有点太多了所以就在类中添加了一个

完全没必要,直接删掉以后在构造函数中调用creat就行

查找函数

void BTree::search(int key, BTNode *p, bool &flag){    while (p)    {        if (p->data == key)        //找到        {            flag = true;            break;        }        else if (p->data > key)    //比结点的值小就向左找        {            p = p->lchild;        }        else                    //比结点的值小就向左找        {            p = p->rchild;        }    }}

和二分法查找类似,不再赘述

只不过因为查找这里不像前面静态查找中可以直接返回第几个,这里只加了一个flag来进行表示是否查找成功

可以把函数返回值该成BTNode* 即可返回地址

插入函数

void BTree::insert(BTNode *p, int x){    /*if (p==NULL)    {        p = new BTNode();        p->data = x;        p->rchild = p->lchild = NULL;        cout << "p->data" <
data<< endl; } else if (x > p->data) { insert(p->rchild, x); } else if (x < p->data) { insert(p->lchild, x); }*/ //这个错误的原因很明显 if (x > p->data) { if (p->rchild == NULL) { p->rchild = new BTNode(); p->rchild->data = x; p->rchild->rchild = p->rchild->lchild = NULL; cout << p->rchild->data << "插入成功!" << endl; } else insert(p->rchild, x); } else if (x < p->data) { if (p->lchild == NULL) { p->lchild = new BTNode(); p->lchild->data = x; p->lchild->rchild = p->lchild->lchild = NULL; cout << p->lchild->data << "插入成功!" << endl; } else insert(p->lchild, x); } else { cout << "不可以插入已经存在于二叉搜索树中的元素!" << endl; }}

注释那一段可以想一想为什么添加失败/(ㄒoㄒ)/~~

调了半天才发现原来当p为空的时候再创建已经找不到它的双亲了(孤儿···)

所以虽然是添加成功了但是在打印族谱 啊 呸 二叉树的时候肯定找不到它了

因此要么你把双亲的地址提前记下来然后创建好再连接上去,要么就直接用p->lchild/p->rchild来创建

此处@陈总~感谢提供

删除功能

由于实验指导书中并没有要求删除这个功能,因此这里只给出思想,感兴趣的可以自行回去完善。

 二叉查找树的删除,分三种情况进行处理:

  1.p为叶子节点,直接删除该节点,再修改其父节点的指针(注意分是根节点和不是根节点)

  2.p为单支节点(即只有左子树或右子树)。让p的子树与p的父亲节点相连,删除p即可;(注意分是根节点和不是根节点)

  3.p的左子树和右子树均不空。找到p的后继y,因为y一定没有左子树,所以可以删除y,并让y的父亲节点成为y的右子树的父亲节点,并用y的值代替p的值;或者方法二是找到p的前驱x,x一定没有右子树,所以可以删除x,并让x的父亲节点成为y的左子树的父亲节点

   具体可以参考:

完整代码(头文件自己选择添加或者把这个放在头文件里都行)

struct BTNode {    int data;    BTNode *lchild,*rchild;};class BTree {private:    BTNode *root;                    //二叉搜索树的根结点    void creat(int loc, BTNode *p); //创建二叉搜索树,递归形式创建,私有函数    void travel(BTNode *p);            //用来遍历(中序),输出时候需要调用的    int *data, number;                //这个是用来存储输入的数组,估计不需要了,下一个版本会删除    void search(int key, BTNode *p, bool &flag);    //查找,其实这个查找方法和二分法类似    void insert(BTNode *p, int x);        //插入函数public:    BTree(int a[], int n);    void Creat();    void Insert(int x);    void Search(int key);    void Print();};void BTree::creat(int loc, BTNode * p){    if (data[loc] > p->data)    //判断要输入的值是比结点值大还是小,大向右,小向左    {        if (p->rchild == NULL)//然后再判断,如果比结点值大且右孩子为空就创建        {            p->rchild = new BTNode();            p->rchild->data = data[loc];            p->rchild->lchild = p->rchild->rchild = NULL;        }        else                  //不为空就继续进行判断比较,递归        {            creat(loc, p->rchild);        }    }    else if (data[loc] < p->data)//同理    {        if (p->lchild == NULL)        {            p->lchild = new BTNode();            p->lchild->data = data[loc];            p->lchild->lchild = p->lchild->rchild = NULL;        }        else        {            creat(loc, p->lchild);        }    }}void BTree::travel(BTNode * p){        //中序遍历,左根右    if (p != NULL)    {        travel(p->lchild);//先左        cout << p->data << " ";//根        travel(p->rchild);//后右    }}void BTree::search(int key, BTNode *p, bool &flag){    while (p)    {        if (p->data == key)        //找到        {            flag = true;            break;        }        else if (p->data > key)    //比结点的值小就向左找        {            p = p->lchild;        }        else                    //比结点的值小就向左找        {            p = p->rchild;        }    }}void BTree::insert(BTNode *p, int x){    /*if (p==NULL)    {        p = new BTNode();        p->data = x;        p->rchild = p->lchild = NULL;        cout << "p->data" <
data<< endl; } else if (x > p->data) { insert(p->rchild, x); } else if (x < p->data) { insert(p->lchild, x); }*/ //这个错误的原因很明显 if (x > p->data) { if (p->rchild == NULL) { p->rchild = new BTNode(); p->rchild->data = x; p->rchild->rchild = p->rchild->lchild = NULL; cout << p->rchild->data << "插入成功!" << endl; } else insert(p->rchild, x); } else if (x < p->data) { if (p->lchild == NULL) { p->lchild = new BTNode(); p->lchild->data = x; p->lchild->rchild = p->lchild->lchild = NULL; cout << p->lchild->data << "插入成功!" << endl; } else insert(p->lchild, x); } else { cout << "不可以插入已经存在于二叉搜索树中的元素!" << endl; }}BTree::BTree(int a[], int n){ int mid = a[0]; //把第一个数据作为二叉树的根结点的数值 root = new BTNode(); root->data = mid; root->lchild = root->rchild = NULL; number = n; data = new int[number]; for (int i = 0; i < number; i++) { data[i] = a[i]; //创建这个数组个人觉得有点多余,其实可以直接在构造函数里完成 //自己改一下吧,直接在构造函数里调用creat,参数需要调整一下 }}void BTree::Insert(int x){ BTNode *p = root; insert(p, x); //这里可以把insert函数增加一个参数bool类型来判断是否真的是插入成功了 //插入成功会有提示,失败不会打印插入成功的消息}void BTree::Search(int key){ //此函数对应私有函数没有返回值,可以自己更改,把地址取出来(目前没有用所以我只是做了一个简单的判断) BTNode *p = root; bool flag = false; search(key, p, flag); if (flag) { cout << "搜索到" << key << "在二叉树中" << endl; } else { cout << "未查找到指定数据!" << endl; }}void BTree::Print(){ BTNode *p = root; travel(p); cout << endl;}void BTree::Creat(){ BTNode *p = root; for (int i = 1; i < number; i++) //从1开始是因为root在构造函数中已经被赋值了 { creat(i, p); } cout << "二叉搜索树创建成功了。。。吧" << endl; }
View Code

主函数代码

int main(){    cout << "请输入二叉搜索树的元素个数:";    int number, *a, key, x;    cin >> number;    a = new int[number];    cout << "请分别为这些元素赋值:" << endl;    for (int i = 0; i < number; i++)    {        cin >> a[i];    }    BTree test(a, number);    test.Creat();    test.Print();    cout << "请输入要查找的数值" << endl;    cin >> key;    test.Search(key);    cout << "请输入要插入的数值" << endl;    cin >> x;    test.Insert(x);    test.Print();    system("pause");    return 0;}
View Code

测试截图

 

转载于:https://www.cnblogs.com/robotpaul/p/10152476.html

你可能感兴趣的文章
poj 1961 Period
查看>>
BZOJ1560: [JSOI2009]火星藏宝图
查看>>
play framework 相关
查看>>
cf1008 codeforces round #535(div3) E1. Array and Segments (Easy version)
查看>>
React 学习笔记
查看>>
LeetCode_Combinations
查看>>
快手第一题
查看>>
有向图强连通分量的Tarjan算法及模板
查看>>
MEAN教程3-NPM安装
查看>>
leetcode| Count Numbers with Unique Digits
查看>>
flask 模版语言及信息传递
查看>>
Ubuntu14.04下安装Hadoop2.4.0 (单机模式)
查看>>
c++ throw异常(学习)
查看>>
IDEA中Git的使用
查看>>
docker 下mysql 和postgresql 数据库的搭建以及数据文件的迁移和备份
查看>>
Java 常用对象-Math类
查看>>
Java 集合-Map接口和三个子类实现
查看>>
人工神经网络 Artificial Neural Network
查看>>
N/A version is not installed yet 解决办法
查看>>
软考错题合集之14-11-AM
查看>>