(十三)数据结构动态查找之二叉排序树查找

数据结构之二叉排序树动态查找

1.内容概述

 这篇博客主讲:1.怎么创建排序二叉树 2.怎么实现动态查找(即插入与删除)3.性能如何web

2.算法分析

 算法分析:
1.创建排序二叉树。所谓排序二叉树在咱们上一篇博客中也有提到,实际上能够说排序二叉树就脱胎于折半查找,只是这一章以树的数据结构来存储信息而且也能够给咱们提供动态插入和删除的功能(**折半查找属于静态查找,是没法进行插入或者删除的)
具体的创建方法是递归,实际上与咱们以前写过的二叉树的中序创建有着殊途同归之妙。一开始是空树,那么咱们输入的第一个数就是树根,以后输入的数若比此数大则前往其右子树,若为空则创建节点;若比此数小则前往左子树,重复此过程直到为空,而后申请节点空间,创建成功。
2.动态查找。实际上咱们创建排序二叉树的过程当中就在时刻进行着动态查找,若大于当前树根就前往右子树,若小于当前树根就前往左子树,若等于则返回指向当前节点的指针。
3.性能分析。算法

与折半查找的断定树类似,二叉排序树的查询步数一样不会超过树的最大深度。
虽然都是n个数据元素,可是他们能够组成的二叉排序树能够有很是多种,这里咱们能够看到一种极端状况
是当二叉排序树退化成单支树时(也就是说变成链状),查找效率降低到了和顺序查找相同的量级。
固然最好的状况就是二叉排序树刚好与这些数据元素组成的折半查找断定树相同时,其平均查找长度和log2 ^n成正比编程

3.代码实现

3.1

下面看具体代码。
1. 这是动态查找及创建二叉排序树的具体过程。安全

int mark; //辅助元素
pBTNode BinaryTreeSort_Search(pBTNode *root, int WhichChild, pBTNode pre, int target) { //递归进行
    if (!*root) {if (WhichChild == 1) pre->rchild = new BTNode(target); else if (WhichChild == 0) pre->lchild = new BTNode(target); else *root = new BTNode(target); mark = 0; return *root;} //空树
    if ((*root)->val == target)     {mark = 1; return *root;}
    else if ((*root)->val < target) return BinaryTreeSort_Search(&(*root)->rchild, 1, *root, target);
    else                            return BinaryTreeSort_Search(&(*root)->lchild, 0, *root, target);
    return nullptr; //should never be reached
}

2. 这是动态删除二叉排序树上节点的过程。稍微麻烦一点点数据结构

pBTNode cur, pre_; //删除过程当中,辅助二叉链表连接的辅助指针
int BinaryTreeSort_Search_del(pBTNode root, pBTNode pre, int mark, int target) { //递归进行
    if (!root) return -1; //空树或者不能存在此元素,删除失败,返回-1
    if (root->val < target)      return BinaryTreeSort_Search_del(root->rchild, root, 1, target);
    else if (root->val > target) return BinaryTreeSort_Search_del(root->lchild, root, 0, target);
    else                         {if (!root->lchild && !root->lchild)    {if (mark) pre->rchild = nullptr; else pre->lchild = nullptr;} //叶子节点,直接删除
                                 else if (!root->lchild && root->rchild) {if (mark) pre->rchild = root->rchild; else pre->lchild = root->rchild;} //左子树为空,右子树不为空 
                                 else if (root->lchild && !root->rchild) {if (mark) pre->rchild = root->lchild; else pre->lchild = root->lchild;} //左子树不为空,右子树为空
                                 else {cur = pre_ = root; while(cur->lchild) {pre_ = cur; cur = cur->lchild;}
                                 if (mark) pre->rchild = cur; else pre->lchild = cur; pre_->lchild = nullptr;} //都不为空,找到右子树最左下方的节点 
                                 delete root; //释放要删除节点的内存空间
                                 return 0;} //ok
    return -1; //should never be reached
}

3. 这是主函数部分,负责用户输入以及函数调用svg

int main() {

    pBTNode root = nullptr, pos, tmp;
    int target; char buffer;
    //输入并建造二叉排序树
    while(buffer != '#') { //控制退出循环
        cin >> target >> noskipws >> buffer; //用户输入
        
        tmp = BinaryTreeSort_Search(&root, -1, nullptr, target);
        if (mark == 0) cout << "未查找到该元素,但已插入二叉排序树中!" << endl;
        else           cout << "查找到此元素并返回了指向它的指针!" << endl;
    }
    
    system("pause"); //暂停程序
    return 0; //end
}

3.2运行截图

runtime

4.实际应用

能够想象一下一个年级查询学生成绩的时候进行的处理,刚开始没有录入一个学生成绩,随着咱们的输入,二叉排序树被创建,与此同时咱们还能够进行查找当前已经存在的成绩。这样处理能十分方便咱们的操做。函数

5.须要注意的两个地方

1.从二叉排序树上删除节点的操做须要注意,这里我都写了比较多的代码量来处理。特别是删除的节点左右子树均不为空时的状况!
1)对于左右子树为空的节点(即叶子节点),咱们直接删除便可
2)对于左子树为空,右子树不为空的节点,咱们让当前节点的双亲节点指向当前节点的右子树树根便可
3)对于右子树为空,左子树不为空的节点,咱们让当前节点的双亲节点指向当前节点的左子树树根便可(与2相似)
4)当左右子树均不为空时,咱们能够循环寻找当前节点右子树中最左下角的叶子节点,也就是循环到左子树为空为止,记录下为止而且令当前节点的双亲节点指向此节点便可。(也能够寻找左子树中最右下角的节点,等效)
2.对于二叉排序树的优化。
在前面咱们提到在极端状况下(数据元素的值递增或递减),咱们构造出来的二叉排序树是单支树,这时候效率变得及其的低下,这显然不是咱们但愿看到的。
优化办法:平衡二叉树的横空出世弥补了这一缺点。因为平衡二叉树严格规定任意一个节点的左右子树树深只差不得超过1,这就避免了创建二叉排序树过程当中单支树的出现。(平衡二叉树的内容将会在下一篇博客当中,敬请期待!)性能

6.结束语(一点祝愿)

已是2月13日,武汉以及全国各地传来的严峻疫情形势让每个中国人都深深担心。不只是身在武汉以及确诊病人们的安全,仍是本身的学业问题。虽说在家也可以找到事作可是效率始终是不比在学校的(平心而论),并且对于下学期会开设的编译原理,汇编语言程序设计,算法分析与设计等课程我十分有兴趣!所以我真的好想国家可以赶忙解决肺炎疫情,我也能回学校学我想学的知识!而且呢,因为下学期条件的支持,有机会的话我会参加acm,不求得奖,只要可以提高本身的编程能力,锻炼本身的算法思惟就能够。
最后的最后,祝愿武汉以及全国各地疫情严峻的朋友们平安健康!!咱们一块儿努力,好好生活下去
结尾箴言:蟾宫折桂,不负韶华优化