二叉查找树的各项操作(重点是结点的删除部分和递归的运用)

什么是二叉查找树? 树简介对于树的基本认识,我们很容易通过我们平常所见到的树来理解:一棵树,有一个根,根往上又会分叉出大树枝,大树枝又会分叉出小树枝,以此往复,直到最后是叶子。而作为数据结构... 阅读详情

          大半年前学二叉树时,看不懂删除结点的代码,对递归的理解很浅,今天把问题一并解决,加深对递归的理解。

         1.删除结点的算法描述:如果待删除的结点至多只有一个子结点,那么需要删除的就是这个结点本身,通过改变指针指向即可;如果待删除的结点有2个结点,那么就需要删除这个结点在中序遍历时的直接后继结点,再通过赋值完成删除。删除后要记得释放结点空间。

         2.递归:递归在非线性结构中用的非常普遍。二叉树的查找,插入,删除都可以用递归实现。以前刚学递归的时候老师说递归算法需要长时间的学习才能够入门,当时根本感觉不到,现在却越来越体会到了。递归固然能够使得程序清晰简洁,但是如果写错,debug的时候是比较痛苦的。

        3.总结:《算法导论》上描述的删除结点的算法非常简洁而且清晰,逻辑非常严密,但自己再理解上花费了不少时间,说明自己的思考练习还差的很远,今后要进一步加强思维上的练习。

        4.算法代码及测试代码:

        代码如下:   注:前半部分函数是大半年前的代码,命名规则上与现在有所不同。

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <ctype.h>

typedef struct node//定义一个二叉树结点   
{
	long item;//结点数值
	int count;//计数器
	struct node *pLeft;
	struct node *pRight;
}NODE;

//函数原型
NODE *CreatNode(long value);
NODE *AddNode(long value,NODE *pNode);
void ListNodesAsc(NODE *pNode);
NODE *tree_search(NODE *pNode,long k);
NODE *iterative_tree_search(NODE *pNode,long k);
NODE *iterative_tree_search(NODE *pNode,long k);
NODE *tree_minimum(NODE *pNode);
NODE *tree_maximun(NODE *pNode);
void parent(NODE *&pNode,NODE *&p,NODE *head);
NODE *tree_successor(NODE *&pNode,NODE *&p,NODE *head);
void tree_delete(NODE *head,long k);

//声明全局变量,存储根结点
NODE *root=NULL;

int main()
{
	long value=0;
	NODE *pNode=NULL;
	long test[]={15,6,3,7,2,4,13,9,18,17,20};//测试数据
	for(int i=0;i<11;i++)
	{
		value=test[i];
		if(pNode==NULL)
			pNode=CreatNode(value);
		else
			AddNode(value,pNode);
	}
	root=pNode;//得到根结点
	ListNodesAsc(pNode);
	printf("\n");
	NODE *result=NULL;

	//测试
	//result=tree_successor(pNode->pLeft->pRight->pRight,result,pNode);
	//parent(pNode->pLeft->pRight->pRight,result,pNode);
	//printf("\n%ld",result->item);
	tree_delete(pNode,15);
	ListNodesAsc(pNode);
	getch();
}


//创建结点
NODE *CreatNode(long value)
{
	NODE *pNode=(NODE *)malloc(sizeof(NODE));
	pNode->item=value;
	pNode->count=1;
	pNode->pLeft=pNode->pRight=NULL;
	return pNode;
}

//添加结点
NODE *AddNode(long value,NODE *pNode)
{
	if(pNode==NULL)
		return CreatNode(value);
	if(pNode->item==value)
	{
		pNode->count++;
		return pNode;
	}
	else if(value<pNode->item)
	{
		if(pNode->pLeft==NULL)
		{
			pNode->pLeft=CreatNode(value);
			return pNode->pLeft;//注意:这里不能直接写成return CreatNode(value);是因为必须要有根结点与左结点的联系
		}
		else                                //加上else看起来更加的清晰,有利于维护
			return AddNode(value,pNode->pLeft);
	}
	else //value>pNode->item的情况
	{
		if(pNode->pRight==NULL)
		{
			pNode->pRight=CreatNode(value);
			return pNode->pRight;
		}
		else
			return AddNode(value,pNode->pRight);
	}
}

//升序排列二叉树(中序遍历二叉树)
void ListNodesAsc(NODE *pNode)
{
	if(pNode->pLeft!=NULL)
		ListNodesAsc(pNode->pLeft);
	for(int i=0;i<pNode->count;i++)
		printf("%d ",pNode->item);
	if(pNode->pRight!=NULL)
		ListNodesAsc(pNode->pRight);
}

//查找
NODE *tree_search(NODE *pNode,long k)
{
	if(pNode==NULL || k==pNode->item)
		return pNode;
	if(k<pNode->item)
		return tree_search(pNode->pLeft,k);
	else
		return tree_search(pNode->pRight,k);
}

//非递归查找
NODE *iterative_tree_search(NODE *pNode,long k)
{
	while(pNode!=NULL && k!=pNode->item)
	{
		if(k<pNode->item)
			pNode=pNode->pLeft;
		else
			pNode=pNode->pRight;
	}
	return pNode;
}

//查找最小值
NODE *tree_minimum(NODE *pNode)
{
	if(pNode==NULL)
		return NULL;
	while(pNode->pLeft!=NULL)
		pNode=pNode->pLeft;
	return pNode;
}

//查找最大值
NODE *tree_maximun(NODE *pNode)
{
	if(pNode==NULL)
		return NULL;
	while(pNode->pRight!=NULL)
		pNode=pNode->pRight;
	return pNode;
}

//计算父亲结点  
void parent(NODE *&pNode,NODE *&p,NODE *head)
{
	if(head!=NULL)
	{
		if((head->pLeft!=NULL && head->pLeft==pNode )|| (head->pRight!=NULL && head->pRight==pNode))
		{
			p=head;
			//return p; //问:为什么这里必须要返回一个指针?  粗心错误,把这个函数的返回值误设为void *
		}		
		if(head->pLeft!=NULL)
			parent(pNode,p,head->pLeft);	
		if(head->pRight!=NULL)
			parent(pNode,p,head->pRight);
	}
}

//查找一个结点的后继   
NODE *tree_successor(NODE *&pNode,NODE *&p,NODE *head)
{
	if(pNode->pRight!=NULL)
		return tree_minimum(pNode->pRight);
	parent(pNode,p,head);
	NODE *p1=p;
	while(p1!=NULL && p1->pRight==pNode)
	{
		pNode=p1;
		parent(p1,p1,head);
	}
	return p1;
}

//删除一个结点
void tree_delete(NODE *head,long k)
{
	NODE *target=tree_search(head,k);
	NODE *y=NULL,*x=NULL;
	NODE *p=NULL;
	if(target->pLeft==NULL || target->pRight==NULL)
		y=target;
	else
		y=tree_successor(target,p,head);
	if(y->pLeft!=NULL)
		x=y->pLeft;
	else
		x=y->pRight;
	parent(y,p,head);
	if(p==NULL)
		root=x;
	else if(y==p->pLeft)
		p->pLeft=x;
	else
		p->pRight=x;
	if(y!=target)
	{
		target->item=y->item;
		free(y);//释放被删除的结点的空间
	}
	else
		free(target);
}


         

数据结构——19.二叉查找树 从根结点开始,如果要查找的值等于当前结点的值,则查找成功。如果遇到空结点,则说明树中没有该值,查找失败。如果此时要查找60,需要从头到尾遍历所有结点,查找效率低,时间复杂度为。二叉查找树,也叫二叉搜索树或二叉排序树,是数据结构中非常重要的一种。: 在这棵树中,结点分布均匀,树的高度很低(相对于结点数量)。查找过程会因为找不到要插入的值而结束于一个空指针的位置,这个位置就是新结点的插入位置。当向AVL树中插入或删除一个结点后,可能会导致某些结点的平衡因子绝对值变为2,从而破坏了AVL树的平衡。 阅读详情

相关推荐

如何正确地删除目录树中的节点

本文适用于做java swing及apache wicket学习的朋友。介绍了如何定义树结点的响应事件,在wicket中如何得到选中的树结点及树结点中的数据;如何正确地删除树中的结点,以避免在删除结点后程序抛出空...更多>> 本文适用于做java swing及apache wicket学习的朋友。介绍了如何定义树结点的响应事件,在wicket中如何得到选中的树结点及树结点中的数据;如何正确地删除树中的结点,以避免在删除结点后程序抛出空指针异常;在删除树结点后,如何按需要求让程序自动选中其它的树结点;在删除树结点的过程中如何正确地处理相关的业务要求

树的删除(递归)

树的删除

mohanhan13131的博客 2152

使用递归删除树形结构的所有子节点(java和mysql实现)

下面小编就为大家带来一篇使用递归删除树形结构的所有子节点(java和mysql实现)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧

【递归删除树形结构】

目标是删除树形结构,树形结构是在数据库内存储,如图所示。 id表示一个节点的id,fid表示一个节点的父id,我个人认为这个结构有点问题,如果不标出来根节点

weixin_46023994的博客 1944

用Spirent Test Center测试交换机Head of Line(HOL)Blocking

测试目的:设备执行拥塞控制,使非阻塞端口不受阻塞端口影响 预设条件:在RFC2889里按以下步骤设置,端口1和端口3同时向端口4发送数据包,端口1向端口2发送数据包 测试步骤:运行设置好的RFC2889 测试结果:所有frame size都显示没有Head of Line(HOL),即非阻塞端口不受阻塞端口所影响 ...

Yuna_的博客 1357

(篇八)C语言在母串删子串、输入位置截取子串

文章目录一、字符串二、删除指定的字符三、从母串中截取子串四、输入位置截取子串 本篇主要介绍C语言字符串中的相关操作,然后分析两个C语言实例——在母串中指定删除子串、在母串中截取子串 一、字符串 了解C 语言的都知道,C语言中没有字符串类型,所以C语言是用字符串常量、字符指针、字符数组来表示字符串。这些字符串都是以 NULL、’\0’或者ASCII==0来结尾。说白了就是一个个字符组成一串有序序列,...

Viewinfinitely的博客 1512

java树型结构数据根据条件移除节点(递归方式)

树型结构数据根据条件移除节点

键盘烫手的博客 1908

【codex教程】Codex 注册和使用教程(2026最新版)

Codex 是 OpenAI 推出的 AI 编程助手,可以帮助开发者阅读代码、修改代码、运行命令、生成测试、排查 bug、做代码审查,也可以在终端、IDE、Codex App 或网页端使用。根据 OpenAI 帮助中心,截至 2026 年 6 月,Codex 已包含在 Free、Go、Plus、Pro、Business、Edu 和 Enterprise 等 ChatGPT 方案中,但不同套餐的使用额度会有所不同。适合开发者在终端中使用。如果你想在命令行里使用 Codex,可以安装 Codex CLI。

与时俱进,开放共享 2万+

递归删除树状数据/递归删除树形结构

递归删除树状结构的实现

程序员小雨的博客 1055

别再只盯着时序了!聊聊SDC里那些容易被忽略的‘配角’命令:工作条件、线载模型与面积约束

本文深入探讨了SDC(设计约束)中常被忽视的关键命令,包括set_operating_conditions、set_wire_load_model和set_max_area。这些‘配角’命令在芯片设计中扮演着至关重要的角色,影响时序收敛、功耗和面积优化。文章通过实际案例和最佳实践,揭示了如何正确配置工作条件、选择线载模型以及动态调整面积约束,以提升设计质量和效率。

weixin_26875109的博客 208

无人机飞控技术最详细解读

已剪辑自: https://zhuanlan.zhihu.com/p/64519280[导读]被称作是“飞行器的大脑”的飞控到底是什么?以前,搞无人机的十个人有八个是航空、气动、机械出身,更多考虑的是如何让飞机稳定飞起来、飞得更快、飞得更高。如今,随着芯片、人工智能、大数据技术的发展,无人机开始了智能化、终端化、集群化的趋势,大批自动化、机械电子、信息工程、微电子的专业人材投入到了无人机研发大潮中,几年的时间让无人机从远离人们视野的军事应用飞入了寻常百姓家、让门外汉可以短暂的学习也能稳定可靠的飞行娱乐。不可

qq_41854911的博客 1万+

JS通过递归函数来剔除树结构特定节点

最近在处理权限类问题过程中,遇到多次需要过滤一下来列表的数据,针对不同用户看到的数据不同。

慢慢 1055

【异常】安装hermes-agent提示Git克隆仓库网络中断 fetch-pack: unexpected disconnect while reading sideband packet

本文分析了Git克隆仓库时出现网络中断错误的常见原因及解决方案。报错表现为连接被远程主机关闭、管道破裂或数据包意外终止,通常由网络不稳定、仓库过大或配置不当引起。提供了5种优先级排序的解决方法:1)使用浅克隆减少数据量;2)优化Git配置参数;3)切换网络或配置代理;4)检查SSH密钥设置;5)改用HTTPS方式克隆。特别推荐先尝试「浅克隆+HTTPS」组合方案快速验证,若问题持续再根据具体报错深入排查。文中包含详细的命令示例和配置说明,适合不同网络环境下的Git用户参考。

奶爸的编程之路,也就一周冷个三天 1418

二叉查找树和红黑树

文章目录1 二叉查找树1.1 原理1.2 二叉查找树插入1.3 二叉查找树删除1.2 缺陷2 红黑树2.1 平衡树2.1.1 简介2.1.2 平衡性的维护2.1.2.1 LL(右单旋转)2.1.2.2 RR(左单旋转)2.1.2.3 LR平衡旋转(先左后右旋转)2.1.2.4 RL RL平衡旋转(先右后左旋转)2.2 2-3 查找平衡树2.2.1 简介2.2.2 2-3平衡树的插入2.2.2.1 ...

梦的灰色边沿... 655

Claude Code Cli 源码泄露事件全解析:从51万行代码中拆解AI Agent的记忆护城河

2026年3月,Anthropic的AI编程助手Claude Code意外泄露51万行核心代码,暴露了其多Agent架构、六级权限验证系统及创新的记忆机制。记忆系统采用四层设计:用户自定义框架、自动记忆提取、智能上下文压缩和纯文件存储。最独特的是"自动做梦"功能,AI会定期整理记忆,类似人类睡眠记忆巩固。代码还揭示未发布功能如电子宠物系统,但也暴露权限系统漏洞和代码质量问题。这次泄露展现了AI助手核心技术的复杂性,特别是其记忆系统如何通过透明可编辑的设计建立用户信任。

program哲学 469

C和C++Everything教程的简介

C和C++Everything教程的简介 C和C++Everything教程,该专栏目前已有8000博文,订阅该专栏相当于同时订阅以下所有收费专栏

希望我的博客,能帮上你解决学习中工作中所遇到的问题 4392

【tree】二叉查找树

二叉查找树的递归实现和非递归实现

厚积薄发者,轻舟万重山 597

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

java二叉查找树的删除_二叉查找树的查找、插入和删除 - Java实现

http://www.cnblogs.com/yangecnu/p/Introduce-Binary-Search-Tree.html前文介绍了符号表的两种实现,无序链表和有序数组,无序链表在插入的时候具有较高的灵活性,而有序数组在查找时具有较高的效率,本文介绍的二叉查找树(Binary Search Tree,BST)这一数据结构综合了以上两种数据结构的优点。二叉查找树具有很高的灵活性,对其优化...

weixin_39614877的博客 248

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

数据结构:二叉查找树ADT的基本操作

二叉查找树的基本操作 因为是尽可能的为了让小伙伴们都能看的明白,博主不会用冗杂的概念,品质保证,还请,多多关照。 首先我们得知道二叉查找树是什么,它就是一种结构,只不过这种结构的重点应用在于查找,它也是一个二叉树。 我们必须得清楚的一个性质:二叉查找树的一个节点的左节点中的元素,一定是小于该节点的元素的,而右节点的元素一定是大于该节点的。我们可以用图片来直观的反映 (取自博客园walfud) 这...

qq_45804132的博客 612

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

算法序列 - 二叉查找树

一、常见的查找数据结构和算法介绍 1.1 链表(顺序查找) 针对少量的、无规则的数据,可以采用链表进行顺序查找 从头到尾依次逐个查找,直到找到所要的数据或搜索完整个数据序列。时间复杂度是O(n) 它的优点是插入比较快,但是查找比较慢。 1.2 有序数组(二分查找) 针对有序数组,可以采用二分查找法(折半查找法) 基本原理: 首先讲要查找的元素月数组的中间元素比较 定义三个遍历,最小值,最大值,中间值,其中中间值=(最小值+最大值)/2 如果key小于中间值,把最大值的下标移动到中间值的前一个 如果k

翻肚鱼儿的博客 358

二叉查找树节点删除全解析,彻底搞懂C语言递归与迭代实现

掌握二叉查找树删除难点,本文深入解析C语言实现二叉查找树的删除操作,涵盖递归与迭代两种方法,详解节点替换、子树调整等关键步骤,适用于算法开发与数据结构学习,逻辑清晰易懂,值得收藏。

AlgoFun的博客 787

二叉树与二叉查找树

二叉树与二叉查找树。

Carl_helloworld 755

数据结构(java语言描述)-- 二叉查找树的链式存储结构的实现

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

一大三千的博客 1072

音视频开发系列(56)算法序列 - 二叉查找树

一、常见的查找数据结构和算法介绍 1.1 链表(顺序查找) 针对少量的、无规则的数据,可以采用链表进行顺序查找 从头到尾依次逐个查找,直到找到所要的数据或搜索完整个数据序列。时间复杂度是O(n) 它的优点是插入比较快,但是查找比较慢。 1.2 有序数组(二分查找) 针对有序数组,可以采用二分查找法(折半查找法) 基本原理: 首先将要查找的元素和数组的中间元素比较 定义三个遍历,最小值,最大值,中间值,其中中间值=(最小值+最大值)/2 如果key小于中间值,把最大值的下标移动到中间值的前一个 如果k

yinshipin007的博客 161

音视频开发之旅(27) 算法序列 - 二叉查找树

目录 常见的查找数据结构和算法介绍 二叉查找树 资料 收获 一、常见的查找数据结构和算法介绍 1.1 链表(顺序查找) 针对少量的、无规则的数据,可以采用链表进行顺序查找 从头到尾依次逐个查找,直到找到所要的数据或搜索完整个数据序列。时间复杂度是O(n) 它的优点是插入比较快,但是查找比较慢。 1.2 有序数组(二分查找) 针对有序数组,可以采用二分查找法(折半查找法) 基本原理: 首先讲要查找的元素月数组的中间元素比较 定义三个遍历,最小值,最大值,中间值,其中中间值=(最小值+最大值)/

yabin的专栏 154
上一篇: 计数排序及其扩展思路
下一篇: 希尔排序(使用希尔增量)
NeilHappy
博客等级 码龄15年 126粉丝 84原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值