当前位置: 首页 > news >正文

数据结构-二叉搜索树/二叉排序树/二叉查找树

文章目录

  • 概述
  • 1. 二叉搜索树基本概念
      • 1.1 定义
      • 1.2 性质
  • 2. 二叉搜索树相关操作
      • 2.1 二叉搜索树创建
      • 2.2 二叉搜索树查找
          • 2.2.1 查找步骤
          • 2.2.2 查找性能分析
      • 2.3 二叉搜索树插入
      • 2.4 二叉搜索树的删除

概述


本文介绍数据结构–二叉搜索树

1. 二叉搜索树基本概念


1.1 定义

二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。。设x为二叉查找树中的一个节点,x节点包含关键字key,节点x的key值记为key[x]。如果y是x的左子树中的一个节点,则key[y] <= key[x];如果y是x的右子树的一个节点,则key[y] >= key[x]。

1.2 性质

二叉搜索树,可以是一棵空树,或者是具有下列性质的二叉树:

  1. 若左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 左、右子树也分别为二叉排序树;
  4. 没有键值相等的节点。

2. 二叉搜索树相关操作

2.1 二叉搜索树创建

参考- 数据结构与算法——平衡二叉树
现有序列:A = {61, 87, 59, 47, 35, 73, 51, 98, 37, 93}。根据此序列构造二叉搜索树过程如下:
  (1)i = 0,A[0] = 61,节点61作为根节点;
  (2)i = 1,A[1] = 87,87 > 61,且节点61右孩子为空,故81为61节点的右孩子;
  (3)i = 2,A[2] = 59,59 < 61,且节点61左孩子为空,故59为61节点的左孩子;
  (4)i = 3,A[3] = 47,47 < 59,且节点59左孩子为空,故47为59节点的左孩子;
  (5)i = 4,A[4] = 35,35 < 47,且节点47左孩子为空,故35为47节点的左孩子;
  (6)i = 5,A[5] = 73,73 < 87,且节点87左孩子为空,故73为87节点的左孩子;
  (7)i = 6,A[6] = 51,47 < 51,且节点47右孩子为空,故51为47节点的右孩子;
  (8)i = 7,A[7] = 98,98 < 87,且节点87右孩子为空,故98为87节点的右孩子;
  (9)i = 8,A[8] = 93,93 < 98,且节点98左孩子为空,故93为98节点的左孩子;
 创建完毕后如图2.4中的二叉搜索树:
  在这里插入图片描述

2.2 二叉搜索树查找

2.2.1 查找步骤
  1. 如果树是空的,则查找不成功。
  2. 若根结点的关键字值等于查找的关键字,成功。
  3. 否则:
    2.1 若小于根结点的关键字值,递归查左子树。若子树为空,查找不成功。
    2.2 若大于根结点的关键字值,递归查右子树。若子树为空,查找不成功。
2.2.2 查找性能分析

每个结点的 C ( i ) C(i) C(i)为该结点的层次数。

  • 最坏情况下,当先后插入的关键字有序时,构成的二叉排序树蜕变为单支树,树的深度为其平均查找长度 ( n + 1 ) / 2 ^{(n+1)}/_2 (n+1)/2(和顺序查找相同)
  • 最好的情况是二叉排序树的形态和折半查找的判定树相同,其平均查找长度和 l o g 2 ( n ) log_2(n) log2(n)成正比。

查找算法代码:其实与二叉树递归遍历算法的思想是非常相似的。

    /* 递归查找二叉排序树T中是否存在key, *//* 指针f指向T的双亲,其初始调用值为NULL *//* 若查找成功,则指针p指向该数据元素节点,并返回TRUE *//* 否则指针p指向查找路径上访问的最后一个节点并返回FALSE */bool searchBST(BSTNode* T, int key, BSTNode* f, BSTNode **p){  if (!T) /*  查找不成功 */{ *p = f;  return false; }else if (key == T->key) /*  查找成功 */{ *p = T;  return true; } else if (key < T->key) return searchBST(T->lchild, key, T, p);  /*  在左子树中继续查找 */else  return searchBST(T->rchild, key, T, p);  /*  在右子树中继续查找 */}

使用二叉搜索树可以提高查找效率,其平均时间复杂度为 O ( l o g 2 n ) O(log_2n) O(log2n)

2.3 二叉搜索树插入

插入过程:

  1. 先检测该元素是否在树中已经存在。如果已经存在,则不进行插入;
  2. 若元素不存在,则进行查找过程,并将元素插入在查找结束的位置
    在这里插入图片描述
    在这里插入图片描述

插入代码算法

    void insertBST(BSTNode **T,int key) //此处使用二重指针是因为要修改指针的指针{BSTNode *s;if(*T==NULL) //到达查找结束位置,再次位置插入元素{s = (BSTNode*)malloc(sizeof(BSTNode));s->key = key;s->lchild = NULL;s->rchild = NULL;*T=s;}else if(key<(*T)->key)//要插入的值大于当前节点,往左子树搜insertBST(&((*T)->lchild),key);else if(key>(*T)->key)//大于当前节点,往右子树搜insertBST(&((*T)->rchild),key);}

2.4 二叉搜索树的删除

在删除之前,首先需要找到此节点,针对不同的结点类型,进行删除不同的操作.

情况
删除方式
删除的节点为叶子节点删除叶子节点的方式最为简单,只需查找到该节点,直接删除即可。
删除的节点只有左子树删除的节点若只有左子树,将节点的左子树替代该节点位置。
删除的节点只有右子树删除的节点若只有右子树,将节点的右子树替代该节点位置。
删除的节点既有左子树又有右子树其流程如下:
  (1)遍历待删除节点的左子树,找到其左子树中的最大key节点(最右下),即删除节点的前驱节点;
  (2)将最大节点代替被删除节点;
  (3)删除左子树中的最大节点;
  (4)左子树中待删除最大节点一定为叶子节点或者仅有左子树。按照之前情形删除即可。

对于左右子树都有的结点,可以采用中序遍历的方式来得到删除结点的前驱和后继结点。选取前驱结点或者后继结点代替删除结点即可。
在这里插入图片描述
例如要删除上图的47结点,删除后:
在这里插入图片描述

删除算法代码:

	// BSTNode* T是,我们通过前面的查找算法找到的结点,它不一定就是要删除的结点。// 因此,我盟在删除之前需要通过key是否相等,来判断,返回的结点,是不是要删除的结点。//若二叉排序树T中存在关键字等于key的数据元素时,则删除该数据元素节点//并返回TRUE;否则返回FALSE。bool deleteBST(BSTNode* T,int key){ if(!*T) /* 不存在关键字等于key的数据元素 */ return false;else{if (key == (*T)->key) /* 找到关键字等于key的数据元素 */ return deleteBSTNode(T);else if (key<(*T)->key)return deleteBST(&(*T)->lchild,key);elsereturn deleteBST(&(*T)->rchild,key);}}/* 从二叉排序树中删除节点p,并重接它的左或右子树。 */bool deleteBSTNode(BSTNode* p){BSTNode* q,s;if((*p)->rchild==NULL) //右子树空则只需重接它的左子树(待删节点是叶子也走此分支) {q=*p;*p=(*p)->lchild; free(q);}else if((*p)->lchild==NULL) //左子树为空,只需重接它的右子树{q=*p; *p=(*p)->rchild; free(q);}else //左右子树均不空{q=*p; s=(*p)->lchild;while(s->rchild) // 转到左子树,然后向右到尽头(找待删节点的前驱) */{q=s;s=s->rchild;}(*p)->key=s->key; //s指向被删节点的直接前驱(将被删节点前驱的值取代被删节点的值)if(q!=*p)q->rchild=s->lchild; //重接q的右子树elseq->lchild=s->lchild; //重接q的左子树free(s);}return TRUE;}
http://www.xdnf.cn/news/826507.html

相关文章:

  • arm平台下使用bl和ldr跳转应当注意的地方(arm-linux-gcc环境)
  • WOL(Wake On LAN - 局域网唤醒)外网唤醒 配置教程 远程开机
  • Statement和PreparedStatement的区别与联系
  • pcre简介
  • 【网络安全】nmap深度入门讲解
  • 请问一下java在线编程的网站有哪一些?
  • JDK配置环境变量【图文详解】
  • 微服务网关API Geteway
  • 【Oracle database】 Oracle数据库分区表基础
  • Apriori算法详解
  • linux下logcat命令,Android logcat 命令以及 Log机制
  • 好玩的100个网站收藏
  • BDI和CDI理论四个象限的概念特点及其运用
  • MySQL中information_schema详解
  • Java 匿名内部类
  • R730结构
  • 什么是web service
  • java script 技巧_java script学习方法
  • 如何在VMware Workstation上快速构建一个windows 7虚拟机?[手把手辅导教程]
  • SQL Server中Convert函数转换日期的用法 日期格式化
  • Linux RPM包安装、卸载和升级(rpm命令)
  • python easyicon同类型ico图片批量爬取
  • Linux网络 FTP
  • 揭开pkill的秘密:在Linux中杀死进程的完整指南
  • 图解net use 命令使用示例
  • 安装最新版 MATLAB:详细安装教程
  • viewport详细讲解
  • PaddleNLP系列1-基础知识
  • Java的clientSocket
  • Docker之RUN、COMMAND、ENTRYPOINT辨析