动态查找表之二叉搜索树

一、二叉搜索树(BST)

二叉搜索树(二叉排序树)定义如下:

1)一棵空树;

2)或者不是空树:

         1)若左子树不空,则左子树上所有结点的值均小于它的根结点的值;

         2)若右子树不空,则右子树上所有结点的值均大于它的根结点的值;

         3)左、右子树也分别为二叉排序树。

 

二、二叉搜索的操作

/*************************************************************************
这是一个二叉查找树,实现了以下操作:插入结点、构造二叉树、删除结点、查找、
查找最大值、查找最小值、查找指定结点的前驱和后继。上述所有操作时间复杂度
均为o(h),其中h是树的高度
注释很详细,具体内容就看代码吧
*************************************************************************/#include<stdio.h>  
#include<stdlib.h>  //二叉查找树结点描述  
typedef int KeyType;
typedef struct Node
{KeyType key;          //关键字  struct Node * left;   //左孩子指针  struct Node * right;  //右孩子指针  struct Node * parent; //指向父节点指针  
}Node, *PNode;//往二叉查找树中插入结点  
//插入的话,可能要改变根结点的地址,所以传的是二级指针  
void inseart(PNode * root, KeyType key)
{//初始化插入结点  PNode p = (PNode)malloc(sizeof(Node));p->key = key;p->left = p->right = p->parent = NULL;//空树时,直接作为根结点  if ((*root) == NULL) {*root = p;return;}//插入到当前结点(*root)的左孩子  if ((*root)->left == NULL && (*root)->key > key) {p->parent = (*root);(*root)->left = p;return;}//插入到当前结点(*root)的右孩子  if ((*root)->right == NULL && (*root)->key < key) {p->parent = (*root);(*root)->right = p;return;}if ((*root)->key > key)inseart(&(*root)->left, key);else if ((*root)->key < key)inseart(&(*root)->right, key);elsereturn;
}//查找元素,找到返回关键字的结点指针,没找到返回NULL  
PNode search(PNode root, KeyType key)
{if (root == NULL)return NULL;if (key > root->key) //查找右子树  return search(root->right, key);else if (key < root->key) //查找左子树  return search(root->left, key);elsereturn root;
}//查找最小关键字,空树时返回NULL  
PNode searchMin(PNode root)
{if (root == NULL)return NULL;if (root->left == NULL)return root;else  //一直往左孩子找,直到没有左孩子的结点  return searchMin(root->left);
}//查找最大关键字,空树时返回NULL  
PNode searchMax(PNode root)
{if (root == NULL)return NULL;if (root->right == NULL)return root;else  //一直往右孩子找,直到没有右孩子的结点  return searchMax(root->right);
}//查找某个结点的前驱  
PNode searchPredecessor(PNode p)
{//空树  if (p == NULL)return p;//有左子树、左子树中最大的那个  if (p->left)return searchMax(p->left);//无左子树,查找某个结点的右子树遍历完了  else {if (p->parent == NULL)return NULL;//向上寻找前驱  while (p) {if (p->parent->right == p)break;p = p->parent;}return p->parent;}
}//查找某个结点的后继  
PNode searchSuccessor(PNode p)
{//空树  if (p == NULL)return p;//有右子树、右子树中最小的那个  if (p->right)return searchMin(p->right);//无右子树,查找某个结点的左子树遍历完了  else {if (p->parent == NULL)return NULL;//向上寻找后继  while (p) {if (p->parent->left == p)break;p = p->parent;}return p->parent;}
}//根据关键字删除某个结点,删除成功返回1,否则返回0  
//如果把根结点删掉,那么要改变根结点的地址,所以传二级指针  
int deleteNode(PNode* root, KeyType key)
{PNode q;//查找到要删除的结点  PNode p = search(*root, key);KeyType temp;    //暂存后继结点的值  //没查到此关键字  if (!p)return 0;//1.被删结点是叶子结点,直接删除  if (p->left == NULL && p->right == NULL) {//只有一个元素,删完之后变成一颗空树  if (p->parent == NULL) {free(p);(*root) = NULL;}else {//删除的结点是父节点的左孩子  if (p->parent->left == p)p->parent->left = NULL;else  //删除的结点是父节点的右孩子  p->parent->right = NULL;free(p);}}//2.被删结点只有左子树  else if (p->left && !(p->right)) {p->left->parent = p->parent;//如果删除是父结点,要改变父节点指针  if (p->parent == NULL)*root = p->left;//删除的结点是父节点的左孩子  else if (p->parent->left == p)p->parent->left = p->left;else //删除的结点是父节点的右孩子  p->parent->right = p->left;free(p);}//3.被删结点只有右孩子  else if (p->right && !(p->left)) {p->right->parent = p->parent;//如果删除是父结点,要改变父节点指针  if (p->parent == NULL)*root = p->right;//删除的结点是父节点的左孩子  else if (p->parent->left == p)p->parent->left = p->right;else //删除的结点是父节点的右孩子  p->parent->right = p->right;free(p);}//4.被删除的结点既有左孩子,又有右孩子  //该结点的后继结点肯定无左子树(参考上面查找后继结点函数)  //删掉后继结点,后继结点的值代替该结点  else {//找到要删除结点的后继  q = searchSuccessor(p);temp = q->key;//删除后继结点  deleteNode(root, q->key);p->key = temp;}return 1;
}//创建一棵二叉查找树  
void create(PNode* root, KeyType *keyArray, int length)
{int i;//逐个结点插入二叉树中  for (i = 0; i<length; i++)inseart(root, keyArray[i]);
}int main(void)
{int i;PNode root = NULL;KeyType nodeArray[11] = { 15,6,18,3,7,17,20,2,4,13,9 };create(&root, nodeArray, 11);for (i = 0; i<2; i++)deleteNode(&root, nodeArray[i]);printf("%d\n", searchPredecessor(root)->key);printf("%d\n", searchSuccessor(root)->key);printf("%d\n", searchMin(root)->key);printf("%d\n", searchMax(root)->key);printf("%d\n", search(root, 13)->key);return 0;
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/461998.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Mysql数据导入导出

导出导入数据库导出mysqldump方法mysqldump -u用户名 -p密码名 database [table]> 目标文件导入mysql -uroot -prootuse databasesource 目标文件&#xff1b;PS: 这种方法是导出整个表数据&#xff0c;并且带着建表信息&#xff0c;假如导入的数据库有同名的表&#xff0c;…

2-10 就业课(2.0)-oozie:9、oozie与hue的整合,以及整合后执行MR任务

5、hue整合oozie 第一步&#xff1a;停止oozie与hue的进程 通过命令停止oozie与hue的进程&#xff0c;准备修改oozie与hue的配置文件 第二步&#xff1a;修改oozie的配置文件&#xff08;老版本的bug&#xff0c;新版本已经不需要了&#xff09;这一步我们都不需要做了 修改ooz…

Screen Painter 程序设计

一、Screen 的创建及维护, TCode:SE51 输入程序名称&#xff0c;单击【建立】&#xff0c; 程序1000为SAP预留屏幕号&#xff0c;屏幕号必须定义1000外的其他数字&#xff0c;且最多不超过四位&#xff0c; 本例定义屏幕为SAP预留屏幕号为&#xff1a;100 * 属性设置&#xff1…

完全图解VS2017安装过程并演示VS2017创建Linux项目和调试

VS2017个人免费版即社区官方下载地址为&#xff1a;https://download.microsoft.com/download/D/1/4/D142F7E7-4D7E-4F3B-A399-5BACA91EB569/vs_Community.exe 这是一个很小的在线下载安装器。VS2017安装变得人性化了&#xff0c;根据组件的分类&#xff0c;供安装用户选择&…

spring--打印hello--注解component--自动创建对象

1.创建 GroupId----项目目录&#xff08;com.javaspring&#xff09; Artifactid---项目名称(spring01qiuckstart) Version--版本默认 2.默认打开的pom.xml文件 编辑---编写spring核心项目依赖 <?xml version"1.0" encoding"UTF-8"?> <project …

菜鸟学数据库(四)——超键、候选键、主键、外键

这些年的一些经历告诉我&#xff0c;很多初学者搞不清超键、候选键等&#xff0c;被数据库中的各种键搞的一头雾水。下面就跟大家一起聊聊数据库中的那些键。 首先看看各种键的定义&#xff1a; 超键(super key):在关系中能唯一标识元组的属性集称为关系模式的超键 候选键(ca…

嵌入式C语言之struct内存分配分析

本文源于微信号《嵌入式ARM》。链接&#xff1a;http://mp.weixin.qq.com/s/j2mk6jY79nrJge2cDZVH_A 对结构MyStruct采用sizeof会出现什么结果呢&#xff1f;sizeof(MyStruct)为多少呢&#xff1f; 也许你会这样求&#xff1a;sizeof(MyStruct)sizeof(double)sizeof(char)sizeo…

open和fopen的区别

open和fopen的区别&#xff1a; 1.非缓冲文件系统缓冲文件系统是借助文件结构体指针来对文件进行管理&#xff0c;通过文件指针来对文件进行访问&#xff0c;既可以读写字符、字符串、格式化数据&#xff0c;也可以读写二进制数 据。非缓冲文件系统依赖于操作系统&#xff0c;通…

PostMessage发送字符串和结构体

2019独角兽企业重金招聘Python工程师标准>>> 1.首先定义消息变量 #define WM_POST_MSG WM_USER 2 2.增加消息处理函数 afx_msg LRESULT UpdateStatic(WPARAM wParam, LPARAM lParam); 3.增加消息映射 ON_MESSAGE(WM_POST_MSG,UpdateStatic) 当调用PostMessage函…

求一个数组的最长递减子序列 比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}...

目前想到的一个方法&#xff0c;就是用栈来寻找&#xff0c;说下思想&#xff1a;&#xff08;栈中的data为元素所在的位置&#xff0c;这意味着出栈和进栈的都是索引值&#xff0c;所以比较的时候根据索引找到其值后比较&#xff09; &#xff08;1&#xff09;栈为空&#xf…

SPI、I2C、UART(即串口)三种串行总线详解

以下内容均来源于网络资源的学习与整理&#xff0c;如有侵权请告知删除。 参考博客 几个串口协议学习整理 UART IIC SPI_mainn的博客-CSDN博客 SPI、I2C、UART三种串行总线的原理、区别及应用_嵌入式Linux,的博客-CSDN博客 RS-232 和 UART 之间有什么区别&#xff1f; - 知乎…

select()函数以及FD_ZERO、FD_SET、FD_CLR、FD_ISSET

从别人的博客中转载过来了这一篇文章&#xff0c;经过重新编辑排版之后展现于此&#xff0c;做一个知识点保存与学习。select函数用于在非阻塞中&#xff0c;当一个套接字或一组套接字有信号时通知你&#xff0c;系统提供select函数来实现多路复用输入/输出模型&#xff0c;原型…

网络4 交换机终端命令

1、switch> 是用户模式 en/enable switch# 是特权模式 conf t/ configure temral switch(config)#是全局模式 int f0/1 /interface f0/1 switch (config-if)# 是接口模式2、show version 显示系统ISO 名称ctrlE 把光标移动到命令行结尾处ctrlA 把光标移动…

解决Office系列安装不上的办法

安装Office时提示“扩展属性不一致”的解决办法&#xff1a;使用系统自带的输入法&#xff0c;Win空格键就搞定了。转载于:https://blog.51cto.com/dreamerhan/1313823

用数据辅助设计-搜索中的实践

设计时不能单凭经验和直觉&#xff0c;因为涉及到的目标人群、场景、操作习惯的不同。为了获取更准确、有效的信息去辅助、检测设计&#xff0c;设计师会选择定性&#xff08;用户访谈、焦点小组&#xff09;和定量&#xff08;调研问卷、网站数据分析&#xff09;的方式进行用…

在IBM服务器安装Windows server 2012的心得

一个简单的问题被我搞复杂了&#xff01; 前些日子&#xff0c;由于连接服务器时卡顿、没有反应&#xff0c;我把服务器强制重启了&#xff0c;之后很不幸地&#xff0c;系统开机进入界面后&#xff0c;不断地转圈圈&#xff0c;一段时间后提示“你的电脑遇到问题&#xff0c;…

fd_set 详解

一、winsock中#include <winsock.h> 原型 int select( int nfds , fd_set* readfds , fd_set* writefds , fd_set* exceptfds , const struct timeval* timeout ); nfds&#xff1a;本参数忽略&#xff0c;仅起到兼容作用。 readfds&#xff1a;&#…

VisualVM远程连接Linux服务器通过jstatd方式监控JVM内存状态

2019独角兽企业重金招聘Python工程师标准>>> VisualVM远程连接Linux监控JVM的方式有两种,一种是jstatd,另外一种是JMX,这里描述jstatd的方式: 1.通过google/baidu出来的文章做法大致都雷同这里给出我开始参考的连接http://lixjluck.iteye.com/blog/516447 2. 但是…

STRUTS2 标签调用静态方法

struts2 ognl 调用静态方法 用ognl的静态调用<s:property value"%{java.lang.SystemcurrentTimeMillis()}"/>来显示,发现结果集为空.查了好多资料都发现这个是正确的引用,困惑......最后在查struts2.1.2的文档时发现struts2.1.2中加了很多配置元素,其中有一个名…

一些自己编写的字符串操作函数

1、编写strcat函数。&#xff08;在目的字符串结束处添加源字符串&#xff09; /*已知strcat函数的原型是char *strcat(char *strDest, const char *strSrc); 其中strDest 是目的字符串&#xff0c;strSrc 是源字符串。 不调用C / C 的字符串库函数&#xff0c;请编写函数 strc…