【数据结构】二叉树

数据结构二叉树-C语言 现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。根结点的左子树和右子树分别又是由子树结点、子树结点的左孩子、子树结点的右孩子组成的,因此二叉树定义是递归式的,后序链式二叉树的操作中基本都是按照该概念实现的。的原则,使用递归的方法,先将根结点打印出来,在访问结点的左孩子,直到访问到为空,在回到结点,访问结点的右孩子。:若一个结点含有子结点,则这个结点称为其子结点的夫结点; 阅读详情

二叉树,每个节点包含一个数据元素,一个左子树和一个右子树(地址)。

typedef int T;
struct BTNode{
  T elem;
  struct BTNode *lchild,*rchild;
};
typedef struct BTNode* BTree;

初始化一棵二叉树
注意这里传的参数是二叉树地址的地址,是个二级指针,因为我们需要将二叉树的地址(一级指针)置为NULL

void initBTree(BTree *ptree){
  assert(ptree!=NULL);
  *ptree=NULL;
}

是否为空

bool emptyBTree(BTree tree){
  return tree==NULL;
}

获取一个二叉树的大小,递归,tree为null时返回0,代表这个子树大小为0,子树不为空时,调用时继续调用这颗二叉树两个子树的大小,加1表示这个子树当前节点不为空。

size_t sizeBTree(BTree tree){
  if(tree==NULL) return 0;
  return sizeBTree(tree->lchild)+sizeBTree(tree->rchild)+1;
}

获取一棵二叉树的高度,同样需要递归,树为空时返回0,不为空则分别调用此书两颗子树的高度,则此树的高度为两颗子树中最高的高度加1。

size_t heightBTree(BTree tree){
  if(tree==NULL) return 0;
  size_t lheight = sizeBTree(tree->lchild);
  size_t rheight = sizeBTree(tree->rchild);
  return lheight>rheight?lheight+1:rheight+1;
}

前序遍历,先判断是否为空,然后先遍历根节点(就是当前的树),再分别用递归的方式遍历左子树和右子树。

void foreachPrevBTree(BTree tree ,void(*callback)(T)){
  if(tree!=NULL){
    callback(tree->elem);
    foreachPrevBTree(tree->lchild,callback);
    foreachPrevBTree(tree->rchild,callback);
  }

类似的,中序和后序的遍历

void foreachMidBTree(BTree tree ,void (*callback)(T)){
  if(tree!=NULL){
    foreachMidBTree(tree->lchild,callback);
    callback(tree->elem);
    foreachMidBTree(tree->rchild,callback);
  }
}

void foreachBackBTree(BTree tree,void (*callback)(T)){
  if(tree!=NULL){
    foreachBackBTree(tree->lchild,callback);
    foreachBackBTree(tree->rchild,callback);
    callback(tree->elem);
  }
}

查找操作(针对二叉查找树)
从当前的树开始,如果当前树的数据大于要找的数据,去这颗树的左子树继续找,反之去右子树,直到找到或者遇到空节点(找完了)。

int searchBTree(BTree tree,T elem){
  struct BTNode *node = tree;
  while(node!=NULL){
    if (elem<node->elem)
    {
      node=node->lchild;
    }
    else if(elem>=node->elem){
      node=node->rchild;
    }
    else{
      return 1;
    }
  }
  return 0;
}

递归版本的查找操作,原理大致相同,只不过是从节点的遍历变为了层层调用子树。

int searchBTreeCallself(BTree tree,T elem){
  if (tree==NULL)
    return 0;
  if(elem<tree->elem){
    return searchBTreeCallself(tree->lchild,elem);
  }
  else if (elem>tree->elem)
  {
    return searchBTreeCallself(tree->rchild,elem);
  }
  return 1;
}

创建一个二叉排序树的结点 ,设置为静态,因为只在本文件中调用。注意静态文件需要在调用之前定义。需要传递节点的数据、此节点的左右子树。


//创建一个二叉排序树的结点 
static struct BTNode *createBTNode(T elem,struct BTNode *lchild,struct BTNode *rchild){
	struct BTNode *node = (struct BTNode *)malloc(sizeof(struct BTNode));
	if(node!=NULL){
		node->elem = elem;
		node->lchild = lchild;
		node->rchild = rchild;
	}
	return node;
}

给一棵二叉查找树中插入数据。这里的参数为一个二级指针,树的地址的地址。采用节点遍历的思想,当要插入的数据小于当前节点的数据,去左子树,否则去右子树,循环完毕后,当前节点来到了一个合适的空的叶子节点的位置。调用创建节点的函数,左右子树为NULL,一个二叉查找树的新节点就创建好了。
注意:二级指针ptree所对应的节点数据应该用(*ptree)->elem 来访问。

int insertBTree(BTree *ptree,T elem){
	assert(ptree!=NULL);
	while(*ptree != NULL){
		if(elem < (*ptree)->elem){//说明应该插入到(*ptree)左子树中 
			ptree = &(*ptree)->lchild;
		}else if(elem > (*ptree)->elem){
			ptree = &(*ptree)->rchild;
		}else{//elem == (*ptree)->elem 
			return FAILURE;
		}
	}
	*ptree = createBTNode(elem,NULL,NULL);
	if(*ptree == NULL){
		return FAILURE;
	} 
	return SUCCESS;
}

递归版本的插入,判断当前节点是大于还是小于要查的数据,递归去对应的左子树或右子树,为空时结束递归,创建节点。

int insertBTreeCallSelf(BTree *ptree,T elem){
	assert(ptree!=NULL);
	if(*ptree == NULL){
		*ptree = createBTNode(elem,NULL,NULL);
		if(*ptree == NULL){
			return FAILURE;
		}
		return SUCCESS;
	}
	if(elem < (*ptree)->elem){
		return insertBTreeCallSelf(&(*ptree)->lchild,elem);
	}else if(elem > (*ptree)->elem){
		return insertBTreeCallSelf(&(*ptree)->rchild,elem);
	}
	//有相等元素 
	return FAILURE;
}

删除当前节点,需要去这颗树的右子树中找一个数据最大的节点替换当前节点,然后删除被用来替换的节点。如果当前节点没有子树就直接删除。
先判断是不是左右子树都存在,如果是,则用一个for循环,找最右边的子树,找到后替换里面的数据。
注意,在此之后,被替换的节点可能还有一棵左子树,右子树为NULL,如果有左子树,则用他的左子树代替他的位置,再释放他。

static int removeBTNode(BTree * pnode){
  struct BTNode *node=*pnode;
  if(node->lchild!=NULL&&node->rchild!=NULL){
    pnode=&(node->rchild);
    for(;(*pnode)->rchild!=NULL;pnode=&(*pnode)->rchild);
    node->elem=(*pnode)->elem;

  }
    *pnode=node->lchild!=NULL?node->lchild:node->rchild;
    free(node);
    return SUCCESS;
}

删除指定的数据,首先要找到相同的数据,从根节点开始查找,和前面查找操作相同,找到后则调用删除该节点的函数。

int deleteBTree(BTree *ptree,T elem){
  assert(ptree!=NULL);
  while(*ptree!=NULL){
    if((*ptree)->elem==elem){
      return removeBTNode(ptree);
    }
    if(elem<(*ptree)->elem){
      ptree=&(*ptree)->lchild;
    }
    else if (elem>(*ptree)->elem){
      ptree=&(*ptree)->rchild;
    }
  }
  return FAILURE;
}

递归版本删除

int deleteBTreeCallself(BTree *ptree,T elem){
  assert(ptree!=NULL);
  if(*ptree==NULL){
    return FAILURE;
  }
  if(elem<(*ptree)->elem){
    return deleteBTreeCallself(&(*ptree)->lchild,elem);
  }
  if(elem>(*ptree)->elem){
    return deleteBTreeCallself(&(*ptree)->rchild,elem);
  }
  return removeBTNode(ptree);
}

清除一棵二叉树。递归分别清除自己的左右子树,再free此节点,记得free之后将此节点地址置NULL。


void clearBTree(BTree *ptree){
  assert(ptree!=NULL);
  if(*ptree!=NULL){
    clearBTree(&(*ptree)->lchild);
    clearBTree(&(*ptree)->rchild);
    free(*ptree);
    *ptree=NULL;
  }
}

是否为二叉查抄树,在每个节点对左右子树分别调用查找最大和最小值的函数,来和当前的数据作比较,没有问题之后递归调用两颗子树,有问题则return false。

bool isBinSortTree(BTree tree){
  if(tree==NULL)
    return true;
  if(tree->lchild!=NULL&&maxValueSortTree(tree->lchild)>tree->elem){
    return false;
  }
  if(tree->rchild!=NULL&&minValueSortTree(tree->rchild)<tree->elem){
    return false;
  }
  return isBinSortTree(tree->lchild)&&isBinSortTree(tree->rchild);
}

是不是平衡二叉树,获取左右子树的高度,判断左减右和右减左的值是不是超过绝对值1。没问题就对左右子树递归调用。

bool isBalanceBinTree(BTree tree){
  if(tree==NULL){
    return true;
  }
  size_t lheight=heightBTree(tree->lchild);
  size_t rheight=heightBTree(tree->rchild);
  if(lheight-rheight>1||lheight-rheight<-1){
    return false;
  }
  return isBalanceBinTree(tree->lchild)&&isBalanceBinTree(tree->rchild);
}

是不是平衡二叉查找树,即同时满足平衡和二叉查找树的条件。

bool isAvlTree(BTree tree){
  return isBalanceBinTree(tree)&&isBinSortTree(tree);
}
int maxValueSortTree(BTree tree){
  while(tree->lchild!=NULL){
    tree=tree->lchild;;
  }
  return tree->elem;
}

找一棵二叉查找树中最小的值,一直向右遍历即可,最右边的树就是最小的。
查找最大值也是同理。


int minValueSortTree(BTree tree){
  while(tree->rchild!=NULL){
    tree=tree->rchild;
  }
  return tree->elem;
}

别再对着数据手册画图了!用HFSS 2023 R2快速复现ESP-01的PCB天线(附模型文件) 本文详细介绍了使用HFSS 2023 R2逆向复现ESP-01 PCB天线的五个关键步骤,包括逆向工程准备、高效建模技巧、材料与边界设置、激励与求解配置以及结果分析与设计验证。通过参数化建模和智能边界检测,大幅提升仿真效率,适用于WIFI和蓝牙设备的射频设计优化。 阅读详情

相关推荐

Cadence Virtuoso VIVA波形分析:从背景色修改到线宽调整的完整指南

本文详细介绍了Cadence Virtuoso VIVA波形分析工具的核心使用技巧,包括背景色修改、线宽调整等高级功能。通过具体操作步骤和配置方法,帮助工程师优化波形显示效果,提升工作效率。特别强调了与Calculator组件的配合使用,以及专业波形图的输出技巧。

weixin_27330481的博客 621

数据结构——二叉树(代码)

 二叉树 C++ 环境codeblocks17 通过 /* 二叉树 使用了自定义的 栈 和 队列 @CGQ 2018/10/29 */ #include &lt;iostream&gt; #include &lt;stdio.h&gt; #include &lt;stdlib.h&gt; #include &lt;stack&gt; using namespace std; #define ...

地址ch3nye.top 389

科研作图不发愁:手把手教你用PyMOL给蛋白-DNA互作图‘美颜’(附完整配色与标注方案)

本文详细介绍了如何使用PyMOL对蛋白-DNA互作结构图进行专业美化,包括从PDB文件加载、结构展示与标注、互作位点突出显示到高质量渲染输出的完整流程。通过具体案例(PDB ID:8SSS)演示了锌指结构域区分、关键残基标注和互作距离测量等实用技巧,帮助科研人员制作可直接用于期刊投稿的高质量示意图。

weixin_42523792的博客 552

二叉树地址

import java.util.ArrayList; import java.util.List; public class Area { private String value; private String parentValue; private String label; private List&lt;Area&gt; children = new Arr...

苦逼码农的博客 533

自抗扰(ADRC)控制原理及控制器设计

自抗扰控制原理以及控制器设计

weixin_43487974的博客 3万+

halcon 检测直线

图中后三个对象既是检测出的图像;

qq_59062726的博客 666

二叉树

【二叉树特点】二叉树由根结点,左子树和右子树构成,具有以下几个典型特点: 只有一个根节点,每个结点下面最多只有两棵树; 在二叉树的第i层上至多有2^(i-1)个结点(i>=1); 深度为k的二叉树至多有(2^k) -1个结点(k>=1); 对任意一颗二叉树,如果叶子结点数为n0,度为2的结点(结点拥有的子树数就是度)点数为n2,则n0 = n2 + 1; 对于第4个特点,需要特别解释一下,可以从连

xinyu913 824

从CTF到实战:Frida Hook无导出SO函数的3种特殊姿势

本文深入探讨了在移动安全逆向工程中,如何利用Frida Hook无导出SO函数的三种高级技巧:字符串引用定位法、调用栈回溯法和内存特征码扫描。针对安卓So层加固和混淆场景,文章结合CTF赛题与实战案例,详细解析了每种方法的原理、实现步骤与适用场景,为安全研究人员提供了从理论到实践的完整解决方案。

jenkins8butler的博客 516

进阶TypeScript!一文带你理解TS中各种高级语法

TypeScript 的重要性我不在强调了,我相信仍然会有大多数前端开发者碰到复杂类型一概使用 any 处理。我写这篇文章的目的就是为了让你告别 AnyScript ,文章告别晦涩的概念结合实例来为你讲述一系列 TS 高级用法:分发、循环、协变、逆变、unknown ... 等等之类。让我们告别枯燥的概念,结合真实用例来掌握 TypeScript 从此彻底告别 AnySc...

zz_jesse的博客 1510

5-EP4CE10F17C8-引脚配置

EP4CE10F17C8-引脚配置

weixin_44479192的博客 719

Android SELinux——neverallow问题处理(十六)

遇到 neverallow 规则问题,千万别急着去注释/剔除里面原有的规则(原生的尽量别动)。增加 allow 规则是常见的解决办法,但是随着 android 版本的升级,系统对 SELinux 的管控越来越严,增加了大量的 neverallow。一般情况下,向默认标签授予权限的做法是错误的,其中许多权限都是 neverallow 规则所不允许的。按照上面方法去添加 SELinux 可能会违反了 neverallow 规则,编译时候会报 neverallow 相关的错误。

小旭的专栏 2670

二叉树(前序遍历下的最后一个结点地址,后序遍历下的第一个结点地址,中序遍历下的最后一个结点)

前序遍历下的最后一个结点地址: 按照遍历顺序,根节点,左子树,右子树; 所以最后一个节点优先考虑右子树 bintree prelast(bintree t) { if(t->rchild) t = prelast(t->rchild); //考虑右子树 else if(t->lchild) t = prelast(t->lc...

是我的博客啊 8709

173、LLC谐振变换器的PCB设计实战(布线)

LLC谐振变换器PCB设计实战要点 LLC谐振变换器的PCB设计核心在于控制寄生参数,避免高频振铃和EMI问题。功率回路需确保电流路径最短且紧耦合,谐振电容焊盘需加宽以减少发热。驱动走线应独立于功率回路,避免干扰,并合理控制宽度和长度。变压器绕组结构影响共模噪声,建议原边在外层并加屏蔽铜箔。地平面设计需根据功率等级选择整块或分割,大功率下功率地与信号地应单点连接。谐振电流采样推荐四端开尔文电阻以减少电感干扰。散热需优化铜皮和过孔布局,功率器件优先放置顶层。布局应先确定谐振腔,再排布控制电路。经验上需实测寄生

Jack010169的博客 46

< 数据结构 > 树与二叉树

目录 1、树的概念及结构 树的概念 树的专有名词 树的表示 树在实际中的运用 2、二叉树的概念及结构 概念 现实中的二叉树 特殊的二叉树 二叉树的性质 二叉树的存储结构 1、树的概念及结构 树的概念 现实中的树: 数据结构中的树: 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集...

bit_zyx的博客 6390

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

数据结构——二叉树

树是一种非线性的数据结构,它是由个有限结点组成的一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树。——有一个特殊的结点,称为,根节点没有前驱结点。——除了根结点之外,其余结点被分为M个互不相交的集合,其中每一个集合又是一棵结构与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或者多个后继。因此,树是递归定义的。——树形结构中,⼦树之间不能有交集,否则就不是树形结构。例如:(注:该图片来自于百度)

2406_83392683的博客 3997

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

数据结构——树,二叉树

树是⼀种非线性的数据结构,它是由 n(n>=0)个有限结点组成⼀个具有层次关系的集合。树中有⼀个特殊的结点,称为根结点,根结点没有前驱结点。除根结点外,其余结点被分成 M(M>0) 个互不相交的集合 T1、T2、……、Tm ,其中每⼀个集合 Ti(1 <= i <= m) ⼜是⼀棵结构与树类似的⼦树。每棵⼦树的根结点有且只有⼀个前驱,可以 有 0 个或多个后继。因此,树是递归定义的。树形结构中,子树之间不能有交集,否则就不是树形结构。:若⼀个结点含有⼦结点,则这个结点称为其⼦结点的⽗结点;

C_C2636xyz的博客 1288

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

数据结构【树和二叉树】

树是一种非线性的数据结构,它是由 n(n>=0)个有限结点组成⼀个具有层次关系的集合。为什么叫树,因为它看起来像一棵倒挂的树。

2401_84320036的博客 3069

【数据结构与算法】二叉树

鲸饮未吞海,剑气已横秋。

hsy1603914691的博客 2794

数据结构二叉树题库

《数据结构二叉树之闲死攻略(一)》 目录 华文课后题 王道课后题 华文课后题 1、一棵有512个结点的完全二叉树的高度为多少?(独根树高度为1) 解析: 答案: 10 2、请写出下面这棵二叉树的中序遍历 解析: 左-根-右 left-root-right 答案: LXMECKPBQHDA 3、下列关于二叉树性质的说法正确的有: A、非空满二叉树的结点个数...

闲狗的博客 1万+

数据结构与算法——树与二叉树

树型结构是一类重要的非线性数据结构,其中以树和二叉树最为常用,直观来看,树是以分支关系定义的层次结构。树型结构在客观世界中广泛存在,比如人类社会中的祖辈关系,社会机构组织等等都可以用树来形象表示。树型结构在计算机领域中也得到了广泛应用。

小田是个程序员的博客欢迎你的到来呀~ 2319

【数据结构】 二叉树

二叉树的相关操作和OJ题

qq_56251766的博客 1212

数据结构 二叉树

想要知道二叉树是什么,先要知道树是什么篇幅较长,主要是顺序结构堆和链式结构二叉树,其中的主要算法:向上/向下调整,先序、后续、中序、层序遍历,还有堆排序,top-k啊啥的。

weixin_67645591的博客 752

二叉树数据结构

二叉树数据结构 元素最多具有2个子代的树称为二叉树。由于二叉树中的每个元素只能有2个子代,因此我们通常将它们命名为左子代和右子代。 二叉树节点包含以下部分。 数据 指向左孩子的指针 指向正确的孩子的指针 二叉树包括: 满二叉树(Full Binary Tree) 完整的二叉树(Complete Binary Tree) 完美二叉树(Perfect Binary Tree ) 平衡二叉树 (Balanced Binary Tree ) 退化或病态树 A degenerate (or pathologi

psywan的博客 495
上一篇: c++ 类的显式转换、隐式转换、可调用对象
下一篇: 【数据结构】链栈
Sweler*19
博客等级 码龄7年 65粉丝 56原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值