用OC和Swift一起说说二叉树

前言:

   一:在计算机科学中,二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree)。二叉树常被用于实现二叉查找树和二叉堆。
   二:二叉树的每个结点至多只有二棵子树(不存在度大于2的结点),二叉树的子树有左右之分,次序不能颠倒。二叉树的第i层至多有2^{i-1}个结点;深度为k的二叉树至多有2^k-1个结点;对任何一棵二叉树T,如果其终端结点数为n_0,度为2的结点数为n_2,则n_0=n_2+1。
   三:一棵深度为k,且有2^k-1个节点称之为满二叉树;深度为k,有n个节点的二叉树,当且仅当其每一个节点都与深度为k的满二叉树中,序号为1至n的节点对应时,称之为完全二叉树。
   四:二叉树遍历: 先序遍历、中序遍历、后序遍历、层次遍历 、下面答案很精辟;

 

二✘树的OC创建源码:

/**创建二叉树@param Values 传入数组@return return value description*/
+(ZXTThreeObject * )CreatTreesWithValues:(NSArray * )Values{__block ZXTThreeObject * rootNode = nil;/** 这里顺便提一下这个循环遍历,可能不部分都用的是for循环或者for..in..来循环的 **//** 大家了解一下 NSEnumerator 遍历和Block遍历还有GCD中的dispatch_apply  **//** 链接在这里 **/[Values enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {int value = [obj intValue];rootNode =  [self AddTreeNode:rootNode andValue:value];}];return rootNode;
}/**递归的思想这里返回的 node 这个参数其实是一个局部变量,不管里面嵌套调用多少次AddTreeNode这个方法,这里每一次返回的一直都是它的最原始的根节点!!这点对创建过程的 理解很重要,但如果返回值你写成全局变量就不一样了,它返回的就是最后赋给它的值。这里简单说一下,局部变量是存储在栈中的,全局变量是存储在静态存储区的!每存储一个局部变量,编译器就会开辟一块栈区域来保存方法第一次传递的node这个变量,编译器就开辟了栈区域保存了它的值,后面要是有嵌套调用了这个方法编译器就又开辟新的栈区域保存它们的返回值,但不会影响第一次保存的值,你要调用多次的话,第一个保存的值也就是最后一个返回的了这就解释了为什么每次最后的返回值都是 最原始的根节点了!
**/
+(ZXTThreeObject * )AddTreeNode:(ZXTThreeObject *)node andValue:(int) value{if (!node) {node = [[ZXTThreeObject alloc]init];node.Value = value;}else if (value <= node.Value){/**值小于节点的值,插入到左节点**/node.leftTreeNode = [self AddTreeNode:node.leftTreeNode  andValue:value];}else{/**值大于节点的值,插入到右节点**/node.rightTreeNode = [self AddTreeNode:node.rightTreeNode andValue:value];}return node;
}

你可以验证一下它的正确性,你在创建左右节点的时候他们打印出来,下面的数组提供大家参考:

NSArray * array = @[@2,@3,@7,@5,@9,@4,@6,@1,@8];
/**     上面的数组创建的二叉树应该是这样的 * 代表没有值21          3*       75         94      6  8       ***/   
[ZXTThreeObject CreatTreesWithValues:array];

二✘树的Swift创建源码:

class ZXTreeObject: NSObject {var leftNode :ZXTreeObject?var rightNode:ZXTreeObject?var nodevalue:Int?func CreatTreesWithValues(Values:[Int]) -> ZXTreeObject {var rootNode:ZXTreeObject?for value in Values {rootNode = self.AddTreeNode(node: &rootNode,value)}return rootNode!}/**注意在Swift3中:函数签名中的下划线的意思是告诉编译器,我们在调用函数时第一个参数不需要外带标签这样,我们可以按照 Swift 2 中的方式去调用函数,还有这个下划线和参数名之间要有空格!必须要有!**/func AddTreeNode(node: inout ZXTreeObject?, _ value:Int) -> ZXTreeObject {if (node == nil) {node = ZXTreeObject()node?.nodevalue = value}else if (value < (node?.nodevalue)!) {//print("----- to left ")_ = AddTreeNode(node: &node!.leftNode, value)}else{//print("----- to right ")_ = AddTreeNode(node: &node!.rightNode, value)}// print("节点:",node!.nodevalue ?? 0)return node!}
}

调用的时候这样:

// 定义一个数组
let sortArray:[Int] = [2,3,7,5,9,4,6,1,8]        _ = ZXTreeObject().CreatTreesWithValues(Values: sortArray)

这个结果的话大家可以把上面的打印注释打开自己看看结果,是没问题的,这里在给大家看看这样一个警告:

就这个返回值没有使用的警告,这警告有两种办法消除:

/*
一:就像上面的加 _ = 在调用的函数前面
二:在函数声明的前面加上 @discardableResult 如:
@discardableResult func AddTreeNode(node: inout ZXTreeObject?, _ value:Int) -> ZXTreeObject {
}*/

计算二✘树的深度OC:

/**树的深度三种情况: 一:根节点要是不存在就返回0二:左节点和右节点都不存在,到这里的前提是根节点存在,返回1三:都存在,再递归获取深度,返回最大值!@param node 节点@return return value description*/
// 2017-03-03 14:06:15.248 算法OC版本[22755:262170] 数的深度==5
+(NSInteger)deepWithThree:(ZXTThreeObject *)node{if (!node) {return 0;     }else if (!node.leftTreeNode && !node.rightTreeNode){return 1;}else{NSInteger leftDeep = [self deepWithThree:node.leftTreeNode];NSInteger rightDeep = [self deepWithThree:node.rightTreeNode];return MAX(leftDeep, rightDeep) + 1;}
}

计算二✘树的深度Swift:

    // Swift 求二叉树的深度func deepWithThree(rootNode: ZXTreeObject?) -> Int {if ((rootNode) == nil){return 0   }else if((rootNode?.leftNode) == nil && (rootNode?.rightNode) == nil){return 1}else{let deepLeft = self.deepWithThree(rootNode: rootNode?.leftNode)let rightLeft = self.deepWithThree(rootNode: rootNode?.rightNode)return  max(deepLeft, rightLeft) + 1}}
// 调用
// 打印 ====== 5let deep  =  node.deepWithThree(rootNode: node)print("======",deep)

计算二✘树的宽度OC: 

/*二叉树宽度的定义:各层节点数的最大值!*/
+(NSInteger)WidthOfTree:(ZXTThreeObject * )RootNode{// 根节点不存在,就返回 0if (!RootNode) {return 0;}NSMutableArray * queeArray = [NSMutableArray array];NSInteger currentWidth = 0;NSInteger maxWidth = 1;         // 前面 0 的不存在就 肯定有,至少是 1[queeArray addObject:RootNode]; // 添加根节点while (queeArray.count > 0) {// 这就是当前的节点的数目,第一层就只有根节点 宽度是1// 下一层,按照下面逻辑添加了左右节点就变成了2currentWidth=queeArray.count;// 遍历该层,删除原始数组中遍历过的节点,添加它下一层的节点。再循环遍历for (NSInteger i=0; i<currentWidth; i++) {ZXTThreeObject * treenode = [queeArray firstObject];[queeArray removeObjectAtIndex:0];if (treenode.leftTreeNode) {[queeArray addObject:treenode.leftTreeNode];}if (treenode.rightTreeNode) {[queeArray addObject:treenode.rightTreeNode];}}// 一层一层的遍历的时候去最大值,返回maxWidth = MAX(maxWidth, queeArray.count);}return maxWidth;
}

 计算二✘树的宽度Swift: 

func widthWithThree(rootNode: ZXTreeObject?) -> Int {if ((rootNode) == nil){return 0        }else{var widthDataArray =  Array<ZXTreeObject>()widthDataArray.append(rootNode!)var maxWidth = 1var currentWidth = 0;while (widthDataArray.count > 0) {currentWidth = widthDataArray.countfor _ in 0 ..< currentWidth{let node = widthDataArray.first                    widthDataArray.remove(at: 0)if ((node?.leftNode) != nil) {widthDataArray.append((node?.leftNode)!)}      if ((node?.rightNode) != nil){widthDataArray.append((node?.rightNode)!)}}maxWidth = max(currentWidth, widthDataArray.count)}return maxWidth            }
}

二✘树的先 , 中,后遍历OC: 

// 调用代码
NSMutableArray *  dataArray =  [NSMutableArray array];[ZXTThreeObject preorderTraversal:rootNode andHandle:^(ZXTThreeObject *threeNode) {NSString * value = [NSString stringWithFormat:@"%ld",threeNode.Value];[dataArray addObject:value];}];
NSLog(@"=======%@",dataArray);// 方法实现代码
/**这里所谓的先序,中序,或者后序说的都是根节点的顺序,这个可以看着上面的那张度娘的图片去好好体会一下。handle就是一个回调,node就是根节点,这样就很容易理解记住了。其他的后序和中序就不写代码了,交换顺序就行了。**/
+(void)preorderTraversal:(ZXTThreeObject *)node andHandle:(void(^)(ZXTThreeObject * threeNode))handle{if (node) {// 根if (handle) {handle(node);}//左[self preorderTraversal:node.leftTreeNode andHandle:handle];//右[self preorderTraversal:node.rightTreeNode andHandle:handle];}
}

二✘树的先 , 中,后遍历Swift:

// 定义一个随机数组
let sortArray:[Int] = [2,3,7,5,9,4,6,1,8] 
var dataArray = Array<Int>()
let node = ZXTreeObject().CreatTreesWithValues(Values: sortArray)
_ = node.preorderTraversal(rootNode:node, handle: {(treeNode) indataArray.append((treeNode?.nodevalue)!)
})
print(dataArray)/**  先序遍历  中序和后序就不写了,而上面OC的道理是一样的 **/
// 这是定义的闭包,注意它的位置和我们OC定义Block类似
typealias Handle = (_ root:ZXTreeObject?) -> Void;
func preorderTraversal(rootNode: ZXTreeObject?, handle:@escaping Handle) -> Void {if ((rootNode) != nil) {handle(rootNode);            self.preorderTraversal(rootNode: rootNode?.leftNode, handle: handle)self.preorderTraversal(rootNode: rootNode?.rightNode, handle: handle)}
}

二✘树的层次遍历OC:

/*层次遍历层次遍历,就是一层一层的遍历,下面的方法用到了队列的想法。*/
+(void)CengCiBLTreeNode:(ZXTThreeObject * ) RootNode handle:(void(^)(ZXTThreeObject * treenode))handle{if (RootNode) {NSMutableArray * queeArray=[NSMutableArray array];// 添加了根节点进去[queeArray addObject:RootNode];while (queeArray.count>0) {// 取出数组中的第一个元素ZXTThreeObject * rootnode = [queeArray firstObject];if (handle) {// 添加这个元素的值到数组中去handle(rootnode);}// 添加完这个元素的值就把这个元素删除了[queeArray removeObjectAtIndex:0];// 这个节点要有左节点的话,就添加左节点到数组中去,有右节点的话就添加右节点到数组中去。// 建议一步一步研究这个添加顺序,就可以清晰的看到这个是一层一层的遍历到的。if (rootnode.leftTreeNode) {[queeArray addObject:rootnode.leftTreeNode];}if (rootnode.rightTreeNode) {[queeArray addObject:rootnode.rightTreeNode];}}}
}

二✘树的层次遍历Swift:

/******* 调用/
var array = Array<Int>()
_ = node.preorderTraversal(rootNode:node, handle: {(treeNode) inarray.append((treeNode?.nodevalue)!)
})
//array ====== [2, 1, 3, 7, 5, 4, 6, 9, 8]
print("array ======",array)/*******  层次遍历/
func CengCiBLTreeNode(rootNode: ZXTreeObject?, handle:@escaping Handle) -> Void {if ((rootNode) != nil) {var dataArray =  Array<ZXTreeObject>()dataArray.append(rootNode!)while dataArray.count > 0 {handle(rootNode);dataArray.remove(at: 0)if ((rootNode?.leftNode) != nil) {dataArray.append((rootNode?.leftNode)!)}if ((rootNode?.rightNode) != nil) {dataArray.append((rootNode?.rightNode)!)}}}}

转载于:https://www.cnblogs.com/zhangxiaoxu/p/6484532.html

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

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

相关文章

【Pytorch神经网络理论篇】 30 图片分类模型:Inception模型

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

【Pytorch神经网络理论篇】 31 图片分类模型:ResNet模型+DenseNet模型+EffcientNet模型

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

【Pytorch神经网络理论篇】 32 PNASNet模型:深层可分离卷积+组卷积+空洞卷积

1 PNASNet模型简介 PNASNet模型是Google公司的AutoML架构自动搜索所产生的模型&#xff0c;它使用渐进式网络架构搜索技术&#xff0c;并通过迭代自学习的方式&#xff0c;来寻找最优网络结构。即用机器来设计机器学习算法&#xff0c;使得它能够更好地服务于用户提供的数据。该…

s5k5e2ya MIPI 摄像头调试

1、驱动移植的话按照我之前的文章来做 驱动里面注意是几路的lane,一般mipi的话是差分信号&#xff0c;2路和4路是比较常见的。2、mipi波形 很明显上面的波形是不正确的。dp dn有一个都成了正弦波了。 首先&#xff0c;我们要找一下正确的波形 正确的波形应该是DP和DN不会同时…

【Pytorch神经网络实战案例】23 使用ImagNet的预训练模型识别图片内容

1 案例基本工具概述 1.1 数据集简介 Imagenet数据集共有1000个类别&#xff0c;表明该数据集上的预训练模型最多可以输出1000种不同的分类结果。 Imagenet数据集是目前深度学习图像领域应用得非常多的一个领域&#xff0c;关于图像分类、定位、检测等研究工作大多基于此数据…

杂谈转载

一、什么是运行时&#xff08;Runtime&#xff09;? 运行时是苹果提供的纯C语言的开发库&#xff08;运行时是一种非常牛逼、开发中经常用到的底层技术&#xff09;二、运行时的作用&#xff1f; 能获得某个类的所有成员变量能获得某个类的所有属性能获得某个类的所有方法交换…

【Pytorch神经网络实战案例】24 基于迁移学习识别多种鸟类(CUB-200数据集)

1 迁移学习 在实际开发中&#xff0c;常会使用迁移学习将预训练模型中的特征提取能力转移到自己的模型中。 1.1 迁移学习定义 迁移学习指将在一个任务上训练完成的模型进行简单的修改&#xff0c;再用另一个任务的数据继续训练&#xff0c;使之能够完成新的任务。 1.1.1 迁…

【Pytorch神经网络理论篇】 33 基于图片内容处理的机器视觉:目标检测+图片分割+非极大值抑制+Mask R-CNN模型

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

arduino i2c 如何写16位寄存器_树莓派3B开发Go语言(二)寄存器版本GPIO

作者&#xff1a;爪爪熊链接&#xff1a;https://www.jianshu.com/p/0495c0554a63來源&#xff1a;简书之前将go语言的运行环境给搭建起来了&#xff0c;但是没有开始真正的试试Go 语言操作树莓派硬件的效果。一、树莓派3B硬件介绍树莓派3B采用了博通的BCM2837方案&#xff0c;…

【Pytorch神经网络实战案例】25 (带数据增强)基于迁移学习识别多种鸟类(CUB-200数据集)

1 数据增强 在目前分类效果最好的EficientNet系列模型中&#xff0c;EfficientNet-B7版本的模型就是使用随机数据增强方法训练而成的。 RandAugment方法也是目前主流的数据增强方法&#xff0c;用RandAugment方法进行训练&#xff0c;会使模型的精度得到提升。 2 RandAugment…

diskgenius 数据迁移_U盘格式化后数据恢复免费方法教程

U盘里的数据一般都很重要&#xff0c;比如论文或者办公文件&#xff0c;而有时候我们会被病毒或者误操作把U盘给格式化了&#xff0c;这时候要怎么恢复U盘里的数据呢&#xff0c;只有一个办法&#xff0c;就是用U盘数据恢复软件&#xff0c;但网上此类软件虽然很多&#xff0c;…

【Pytorch神经网络理论篇】 34 样本均衡+分类模型常见损失函数

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

安卓 camera 调用流程_安卓如何做出微信那样的界面仿微信“我”的界面1/5

本系列目标通过安卓编程仿写微信“我”的界面,让大家也能做出类似微信界面.效果图如下:本文目标做出页面顶部的相机部分(其他部分在后续文章中逐步分享).效果图如下:实现方案通过截图工具或者下载一张照相机照片,放到工程的src/main/res/drawable目录下,命名为camera.png添加一…

【Pytorch神经网络实战案例】26 MaskR-CNN内置模型实现目标检测

1 Pytorch中的目标检测内置模型 在torchvision库下的modelsldetecton目录中&#xff0c;找到__int__.py文件。该文件中存放着可以导出的PyTorch内置的目标检测模型。 2 MaskR-CNN内置模型实现目标检测 2.1 代码逻辑简述 将COCO2017数据集上的预训练模型maskrcnm_resnet50_fp…

【Pytorch神经网络实战案例】27 MaskR-CNN内置模型实现语义分割

1 PyTorch中语义分割的内置模型 在torchvision库下的models\segmentation目录中&#xff0c;找到segmentation.Py文件。该文件中存放着PyTorch内置的语义分割模型。 2 MaskR-CNN内置模型实现语义分割 2.1 代码逻辑简述 将COCO 2017数据集上的预训练模型dceplabv3_resnet101…

怎么查看电脑内存和配置_电脑内存不足处理方法,电脑卡死处理方法。

超过10万人正在关注赶快来关注吧&#xff0c;这里有你想找的热点资讯&#xff0c;这里有你想要的各种资料&#xff0c;还有海量的资源&#xff0c;还在等什么。快来关注&#xff0c;大佬带你开车。电脑系统经常奔溃&#xff0c;软件经常运行不了&#xff0c;开不了机&#xff0…

前端开源项目周报0307

由OpenDigg 出品的前端开源项目周报第十一期来啦。我们的前端开源周报集合了OpenDigg一周来新收录的优质的前端开源项目&#xff0c;方便前端开发人员便捷的找到自己需要的项目工具等。 react-trend 简单优雅的光线 react-progressive-web-app 优化ProgressiveWeb应用开发 pull…

【Pytorch神经网络理论篇】 35 GaitSet模型:步态识别思路+水平金字塔池化+三元损失

同学你好&#xff01;本文章于2021年末编写&#xff0c;获得广泛的好评&#xff01; 故在2022年末对本系列进行填充与更新&#xff0c;欢迎大家订阅最新的专栏&#xff0c;获取基于Pytorch1.10版本的理论代码(2023版)实现&#xff0c; Pytorch深度学习理论篇(2023版)目录地址…

win7分区软件_神奇的工作室win7旗舰版重装系统连不上网怎么解决

深度技术win7系统下载有的时刻我们的电脑安装、重装了win10操作系统之后有的小伙伴们就发现了自己的电脑连不上网了。对于这种问题小编以为可能是我们的电脑在安装系统的过程中泛起了一些内部组件的冲突或者是由于网卡驱动没有安装好导致的&#xff0c;可以通过重新安装、重装驱…

【Pytorch神经网络实战案例】28 GitSet模型进行步态与身份识别(CASIA-B数据集)

1 CASIA-B数据集 本例使用的是预处理后的CASIA-B数据集&#xff0c; 数据集下载网址如下。 http&#xff1a;//www.cbsr.ia.ac.cn/china/Gait%20Databases%20cH.asp 该数据集是一个大规模的、多视角的步态库。其中包括124个人&#xff0c;每个人有11个视角(0&#xff0c;18&am…