一:初衷

我自己也好奇,为什么莫名其妙的想起写这个,其实数据里面包含的结构和逻辑我自己觉得才是最原始经典的,最近也在学swift,就向着利用swift整理一些二叉树。自己刚开始的时候也是用OC看着别的小伙伴的博客在写的,OC的逻辑是理清楚了,但用swift去写的时候,遇到些许问题,不是逻辑上的问题,就是语法问题。经过这两天的这个二叉树遇到的问题发现,还是觉得基础不够扎实。以为最基本的掌握了,其实不然,有好多东西还是欠火候!还是得静下心,就从最基本的开始吧!不知道有没有和我一样的小伙伴,基础你真的打好了吗?哈哈··

二:先利用OC写二叉树基本的创建和遍历

你可以先学习一些这些基本的一些概念,什么是二叉树,二叉树遍历的分类和基本规则。

1 二叉树的概念:点击—这是度娘给的答案,还是挺完整的,不知道的可以去看看它的基本概念和一些基本的性质

2 二叉树的深度和宽度(下面代码有具体的说到)

3 二叉树遍历: 先序遍历   中序遍历   后序遍历   层次遍历 (这也是在度娘找的,答案很精辟)

三:OC 二叉树代码(从.H 文件到 .M 文件 再到 调用方法的顺序)

下面是  ZXTThreeObject.h 整个文件的代码,整个文件方便学习。里面思路的整理解释我全都加在代码注释里面了,仔细阅读就OK。

//  Created by mxsm on 16/3/30.
//  Copyright © 2016年 mxsm. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface ZXTThreeObject : NSObject

// 值
@property(nonatomic,assign)NSInteger Value;

// 左节点
@property(nonatomic,strong) ZXTThreeObject * leftTreeNode;

// 右节点
@property(nonatomic,strong) ZXTThreeObject * rightTreeNode;

/*
      基本方法
 */

//  创建二叉树
+(ZXTThreeObject * )CreatTreesWithValues:(NSArray * )Values;

//  计算二叉树的深度
+(NSInteger)DepthOfTree:(ZXTThreeObject * ) RootNode;

//  计算二叉树的宽度
+(NSInteger)WidthOfTree:(ZXTThreeObject * )RootNode;

//  先序遍历二叉树
+(void)XianXuBianLTreeNode:(ZXTThreeObject * ) RootTreeNode handle:(void(^)(ZXTThreeObject *  Treenode))handle;

//  中序遍历二叉树
+(void)ZhongXuBLTreeNode:(ZXTThreeObject * ) RootTreeNode handle:(void(^)(ZXTThreeObject *  Treenode))handle;

//  后序遍历二叉树
+(void)HouXuBLTreeNode:(ZXTThreeObject * ) RootNode handle:(void (^)(ZXTThreeObject *  treenode))handle;

//  层次遍历
+(void)CengCiBLTreeNode:(ZXTThreeObject * ) RootNode handle:(void(^)(ZXTThreeObject * treenode))handle;

@end

下面是 ZXTThreeObject.m 的文件

//
//  ZXTThreeObject.m
//  sinatest
//
//  Created by mxsm on 16/3/30.
//  Copyright © 2016年 mxsm. All rights reserved.
//

#import "ZXTThreeObject.h"

@implementation ZXTThreeObject

/* 

    创建二叉树

*/

+(ZXTThreeObject * )CreatTreesWithValues:(NSArray * )Values
{

    ZXTThreeObject * RootNode = nil;

    for (NSInteger  i =0 ; i < Values.count; i++)
    {
        NSInteger  vlaue = [Values[i]integerValue];
        // 一直返回的是根节点
        RootNode = [ZXTThreeObject  addTreeNode:RootNode values:vlaue];
    }

    return  RootNode;
}

#pragma mark  添加节点
+(ZXTThreeObject * ) addTreeNode:(ZXTThreeObject * )treeNode  values:(NSInteger)value
{

    if (!treeNode) {

        treeNode=[[ZXTThreeObject alloc]init];
        treeNode.Value=value;
        NSLog(@"节点:%ld",(long)value);
    }

    // value 值小于 节点的值 插入 左节点
    else if (value <= treeNode.Value)
    {
        NSLog(@"-------to left");
        treeNode.leftTreeNode = [self addTreeNode:treeNode.leftTreeNode values:value];

    }
    // 否则就是右边的节点值
    else
    {
        NSLog(@"=======to right");
        treeNode.rightTreeNode = [self addTreeNode:treeNode.rightTreeNode values:value];
    }

    NSLog(@"返回节点的值:%ld",(long) treeNode.Value);
    return treeNode;

    /*
        这里调用的思想是递归的思想,递归大家应该都理解,但我不知道有多少孩纸和我一样,刚开始不理解其中的运行过程。
        你要是理解了其中的运行过程,你也就理解了他的创建。。
    */
    /*  这里返回的 treeNode 这个参数其实是一个局部变量,不管上面嵌套调用多少次

        +(ZXTThreeObject * ) addTreeNode:(ZXTThreeObject * )treeNode  values:(NSInteger)value

        这个方法,这里返回值 一次返回的一直都是 它的 最原始的根节点!!
       (很重要,但如果返回值你写成全局变量就不一样了,他返回的就是最后赋给它的值)
       (这里简单说一下,局部变量是存储在 栈 中的,全局变量是存储在静态存储区的!!每存储一个局部变量,编译器就会开辟一块 栈区域来保存 方法第一次传递的 treeNode 这个变量,编译器就开辟了 栈区域保存了它的值,后面要是有嵌套调用了这个方法,编译器就又开辟新的栈区域保存他们的返回值,但不会影响第一次保存的值,你要调用多次的话,第一个保存的值也就是最后一个返回的了,这就解释了为什么每次最后的返回值都是 最原始的根节点了!)

        NSArray * array= @[@"15",@"14",@"16",@"13",@"17",@"18",@"9",@"20",@"16",@"12",@"21",@"22",@"10",@"26",@"1"];
        root= [ZXTThreeObject  CreatTreesWithValues:array];

 **  以上面创建的数组为例  不管嵌套调用多少次,最后返回的 任然是 @“15” 这个节点,下面是打印的值!!
     2016-04-05 11:57:29.532 sinatest[2005:339019] 节点:15
     2016-04-05 11:57:29.532 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.532 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.532 sinatest[2005:339019] 节点:14
     2016-04-05 11:57:29.532 sinatest[2005:339019] 返回节点的值:14
     2016-04-05 11:57:29.532 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.533 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.533 sinatest[2005:339019] 节点:16
     2016-04-05 11:57:29.533 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.533 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.533 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.533 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.533 sinatest[2005:339019] 节点:13
     2016-04-05 11:57:29.533 sinatest[2005:339019] 返回节点的值:13
     2016-04-05 11:57:29.533 sinatest[2005:339019] 返回节点的值:14
     2016-04-05 11:57:29.533 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.533 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.534 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.534 sinatest[2005:339019] 节点:17
     2016-04-05 11:57:29.534 sinatest[2005:339019] 返回节点的值:17
     2016-04-05 11:57:29.534 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.534 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.534 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.534 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.534 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.534 sinatest[2005:339019] 节点:18
     2016-04-05 11:57:29.534 sinatest[2005:339019] 返回节点的值:18
     2016-04-05 11:57:29.534 sinatest[2005:339019] 返回节点的值:17
     2016-04-05 11:57:29.535 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.535 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.535 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.535 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.535 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.535 sinatest[2005:339019] 节点:9
     2016-04-05 11:57:29.535 sinatest[2005:339019] 返回节点的值:9
     2016-04-05 11:57:29.535 sinatest[2005:339019] 返回节点的值:13
     2016-04-05 11:57:29.535 sinatest[2005:339019] 返回节点的值:14
     2016-04-05 11:57:29.535 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.536 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.536 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.536 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.536 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.536 sinatest[2005:339019] 节点:20
     2016-04-05 11:57:29.536 sinatest[2005:339019] 返回节点的值:20
     2016-04-05 11:57:29.536 sinatest[2005:339019] 返回节点的值:18
     2016-04-05 11:57:29.536 sinatest[2005:339019] 返回节点的值:17
     2016-04-05 11:57:29.536 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.536 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.537 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.537 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.537 sinatest[2005:339019] 节点:16
     2016-04-05 11:57:29.537 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.537 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.537 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.537 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.537 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.537 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.537 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.538 sinatest[2005:339019] 节点:12
     2016-04-05 11:57:29.538 sinatest[2005:339019] 返回节点的值:12
     2016-04-05 11:57:29.538 sinatest[2005:339019] 返回节点的值:9
     2016-04-05 11:57:29.538 sinatest[2005:339019] 返回节点的值:13
     2016-04-05 11:57:29.538 sinatest[2005:339019] 返回节点的值:14
     2016-04-05 11:57:29.538 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.538 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.538 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.538 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.538 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.539 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.539 sinatest[2005:339019] 节点:21
     2016-04-05 11:57:29.539 sinatest[2005:339019] 返回节点的值:21
     2016-04-05 11:57:29.539 sinatest[2005:339019] 返回节点的值:20
     2016-04-05 11:57:29.539 sinatest[2005:339019] 返回节点的值:18
     2016-04-05 11:57:29.539 sinatest[2005:339019] 返回节点的值:17
     2016-04-05 11:57:29.539 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.539 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.539 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.539 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.539 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.540 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.540 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.540 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.540 sinatest[2005:339019] 节点:22
     2016-04-05 11:57:29.540 sinatest[2005:339019] 返回节点的值:22
     2016-04-05 11:57:29.540 sinatest[2005:339019] 返回节点的值:21
     2016-04-05 11:57:29.540 sinatest[2005:339019] 返回节点的值:20
     2016-04-05 11:57:29.540 sinatest[2005:339019] 返回节点的值:18
     2016-04-05 11:57:29.540 sinatest[2005:339019] 返回节点的值:17
     2016-04-05 11:57:29.540 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.541 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.541 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.541 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.541 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.541 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.541 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.541 sinatest[2005:339019] 节点:10
     2016-04-05 11:57:29.541 sinatest[2005:339019] 返回节点的值:10
     2016-04-05 11:57:29.541 sinatest[2005:339019] 返回节点的值:12
     2016-04-05 11:57:29.541 sinatest[2005:339019] 返回节点的值:9
     2016-04-05 11:57:29.541 sinatest[2005:339019] 返回节点的值:13
     2016-04-05 11:57:29.542 sinatest[2005:339019] 返回节点的值:14
     2016-04-05 11:57:29.542 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.542 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.542 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.542 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.542 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.542 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.542 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.542 sinatest[2005:339019] =======to right
     2016-04-05 11:57:29.542 sinatest[2005:339019] 节点:26
     2016-04-05 11:57:29.543 sinatest[2005:339019] 返回节点的值:26
     2016-04-05 11:57:29.543 sinatest[2005:339019] 返回节点的值:22
     2016-04-05 11:57:29.543 sinatest[2005:339019] 返回节点的值:21
     2016-04-05 11:57:29.543 sinatest[2005:339019] 返回节点的值:20
     2016-04-05 11:57:29.543 sinatest[2005:339019] 返回节点的值:18
     2016-04-05 11:57:29.543 sinatest[2005:339019] 返回节点的值:17
     2016-04-05 11:57:29.543 sinatest[2005:339019] 返回节点的值:16
     2016-04-05 11:57:29.543 sinatest[2005:339019] 返回节点的值:15
     2016-04-05 11:57:29.543 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.543 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.544 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.544 sinatest[2005:339019] -------to left
     2016-04-05 11:57:29.544 sinatest[2005:339019] 节点:1
     2016-04-05 11:57:29.544 sinatest[2005:339019] 返回节点的值:1
     2016-04-05 11:57:29.544 sinatest[2005:339019] 返回节点的值:9
     2016-04-05 11:57:29.544 sinatest[2005:339019] 返回节点的值:13
     2016-04-05 11:57:29.544 sinatest[2005:339019] 返回节点的值:14
     2016-04-05 11:57:29.544 sinatest[2005:339019] 返回节点的值:15

     */

}

#pragma mark  计算二叉树的深度

/*
 二叉树的深度定义为:从 根节点 到 叶子节点 依次经过的节点形成树的一条路径,  最长路径  的长度为树的深度!

 1)如果根节点为空,则深度为0;

 2)如果左右节点都是空,则深度为1;

 3)递归思想:二叉树的深度=max(左子树的深度,右子树的深度)+ 1

 */

+(NSInteger)DepthOfTree:(ZXTThreeObject * ) RootNode
{

    if (!RootNode) {

        return 0;

    }
    else if (!RootNode.leftTreeNode && !RootNode.rightTreeNode)
    {

        return 1;

    }
    else
    {
        NSInteger leftDepth =  [self DepthOfTree:RootNode.leftTreeNode];
        NSInteger rightDepth =  [self DepthOfTree:RootNode.rightTreeNode];
        return MAX(leftDepth, rightDepth) + 1;
    }

}

#pragma mark 二叉树宽度
/*

    二叉树宽度的定义:各层节点数的最大值!

 */
+(NSInteger)WidthOfTree:(ZXTThreeObject * )RootNode
{
    // 根节点不存在,就返回 0
    if (!RootNode) {

        return 0;
    }

    /*
        这里这层次遍历有点相似的味道在里面,但不是说完全相同,理解学习思路。
    */

    NSMutableArray * queeArray = [NSMutableArray array];
    NSInteger currentWidth = 0;
    NSInteger maxWidth = 1;// 前面 0 的不存在就 肯定有,至少是 1
    [queeArray addObject:RootNode]; // 添加根节点

    while (queeArray.count > 0) {

        currentWidth=queeArray.count;// 这就是当前的节点的数目,第一层就只有根节点 宽度是1 ,下一层,按照下面逻辑添加了左右节点就变成了 2

        // 遍历该层,删除原始数组中遍历过的节点,添加它下一层的节点。再循环遍历
        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;
}

/*

 先序遍历
 下面是遍历的结果;
 2016-04-05 10:31:16.627 sinatest[1707:294999] 先序遍历结果:15,14,13,9,1,12,10,16,16,17,18,20,21,22,26
 2016-04-05 10:31:16.628 sinatest[1707:294999] 中序遍历结果:1,9,10,12,13,14,15,16,16,17,18,20,21,22,26
 2016-04-05 10:31:16.629 sinatest[1707:294999] 后序遍历结果:1,10,12,9,13,14,16,26,22,21,20,18,17,16,15
 2016-04-05 10:31:16.629 sinatest[1707:294999] 层次遍历结果:15,14,16,13,16,17,9,18,1,12,20,10,21,22,26

*/

+(void)XianXuBianLTreeNode:(ZXTThreeObject * ) RootTreeNode handle:(void(^)(ZXTThreeObject *  Treenode))handle
{

    if (RootTreeNode) {

        if (handle) {

            handle(RootTreeNode);

        }

        // 基本的顺序就是 根节点 --> 左节点  --> 右节点
        // 这里这样子调用就有一个方法执行顺序的问题,这样子写嵌套进去方法调用的过程正好就是先序遍历的顺序。
        // 下面的中序遍历 和 后序遍历 都是同样的道理。
        // 这里的 先 中 后 理解成根节点在遍历过程中的位置就理解了,比如 先序遍历,就是根节点在最前面 中序遍历,就是根节点在中间
        [self  XianXuBianLTreeNode:RootTreeNode.leftTreeNode handle:handle];

        [self  XianXuBianLTreeNode:RootTreeNode.rightTreeNode handle:handle];

    }

}

/*

  中序遍历

 */

+(void)ZhongXuBLTreeNode:(ZXTThreeObject * ) RootTreeNode handle:(void(^)(ZXTThreeObject *  Treenode))handle
{
    if (RootTreeNode) {

        [self ZhongXuBLTreeNode:RootTreeNode.leftTreeNode handle:handle];
        if (handle) {

            handle(RootTreeNode);

        }

        [self ZhongXuBLTreeNode:RootTreeNode.rightTreeNode handle:handle];
    }

}

/*

     后序遍历

 */

+(void)HouXuBLTreeNode:(ZXTThreeObject * ) RootNode handle:(void (^)(ZXTThreeObject *  treenode))handle
{
    if (RootNode) {

        [self HouXuBLTreeNode:RootNode.leftTreeNode handle:handle];

        [self HouXuBLTreeNode:RootNode.rightTreeNode handle:handle];

        if (handle) {

            handle(RootNode);

        }
    }
}

/*

      层次遍历
      层次遍历,就是一层一层的遍历,下面的方法用到了队列的想法。

*/

+(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) {

                // 添加这个元素的值到数组中去,这个就结合调用时候的BLOCK去研究,就明白了。
                handle(rootnode);

            }
            // 添加完这个元素的值就把这个元素删除了
            [queeArray removeObjectAtIndex:0];

            // 这个节点要有左节点的话,就添加左节点到数组中去,有右节点的话就添加右节点到数组中去。
            // 建议一步一步研究这个添加顺序,就可以清晰的看到这个是一层一层的遍历到的。
            if (rootnode.leftTreeNode) {

                [queeArray addObject:rootnode.leftTreeNode];

            }
            if (rootnode.rightTreeNode) {

                [queeArray addObject:rootnode.rightTreeNode];

            }

        }

    }

}

@end

下面是它的调用,也是粘贴了整个文件的代码,它的遍历方法是写在这个按钮点击事件里面了,没什么其他意思。

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.

    UIButton * button=[UIButton buttonWithType:UIButtonTypeCustom];
    button.frame=CGRectMake(100, 100, 100, 40);
    [button addTarget:self action:@selector(button ) forControlEvents:UIControlEventTouchUpInside];
    [button setTitle:@"开始" forState:UIControlStateNormal];
    [button setTitleColor:[UIColor purpleColor] forState:UIControlStateNormal];
    [self.view addSubview:button];

    // 数据源
    NSArray * array= @[@"15",@"14",@"16",@"13",@"17",@"18",@"9",@"20",@"16",@"12",@"21",@"22",@"10",@"26",@"1"];
    root= [ZXTThreeObject  CreatTreesWithValues:array];

}

-(void)setUI
{
    [self.delegate younameis:@"caoxiaocao"];

}

-(void)button
{

    // 二叉树的深度
    NSInteger depth =[ZXTThreeObject DepthOfTree:root];
    NSLog(@"二叉树深度:%ld",depth);

    NSInteger width =[ZXTThreeObject WidthOfTree:root];
    NSLog(@"二叉树宽度:%ld",width);

    // 先序遍历调用
    NSMutableArray *orderArray = [NSMutableArray array];
    [ZXTThreeObject XianXuBianLTreeNode: root handle:^(ZXTThreeObject * Treenode) {

        [orderArray addObject:@(Treenode.Value)];

    }];
    NSLog(@"先序遍历结果:%@", [orderArray componentsJoinedByString:@","]);

    // 中序遍历调用
    NSMutableArray *ordertwoArray = [NSMutableArray array];
    [ZXTThreeObject ZhongXuBLTreeNode:root handle:^(ZXTThreeObject *Treenode) {

        [ordertwoArray addObject:@(Treenode.Value)];

    }];
    NSLog(@"中序遍历结果:%@", [ordertwoArray componentsJoinedByString:@","]);

    // 后序遍历调用
    NSMutableArray *orderthreeArray = [NSMutableArray array];
    [ZXTThreeObject HouXuBLTreeNode:root handle:^(ZXTThreeObject *Treenode) {

        [orderthreeArray addObject:@(Treenode.Value)];

    }];
    NSLog(@"后序遍历结果:%@", [orderthreeArray componentsJoinedByString:@","]);

    // 层次遍历调用
    NSMutableArray *orderfourArray = [NSMutableArray array];
    [ZXTThreeObject CengCiBLTreeNode:root handle:^(ZXTThreeObject *Treenode) {

        [orderfourArray addObject:@(Treenode.Value)];

    }];
    NSLog(@"层次遍历结果:%@", [orderfourArray componentsJoinedByString:@","]);

}

四:利用swift创建二叉树

用swift创建二叉树,原理和上面的是一样的,可能就是语法细节的把握,注意细节,还有,好好学习。哈哈··

import UIKit

class ZXTreeNode: NSObject {

    var  Value:Int?
    var  leftNode:ZXTreeNode?
    var  rightNode:ZXTreeNode?

    class  func creatTreeNode(RooeNodeArray:[Int]) -> ZXTreeNode {

        var  root:ZXTreeNode?
        for i in 0..<RooeNodeArray.count
        {
            let  value = RooeNodeArray[i]
            root = self.addTreeNode(&root, value: value)
        }

        return root!

    }

    class func addTreeNode( inout  RootNode:ZXTreeNode?,value:Int ) -> ZXTreeNode {

        if (RootNode == nil ) {

            RootNode = ZXTreeNode()
            RootNode!.Value = value
            print("节点:",RootNode!.Value)

        } // 值小于根节点的值,插左边
        else if (value <= RootNode!.Value)
        {
            print("----- to left ")
            addTreeNode(&RootNode!.leftNode, value: value)

        }
        else
        {
            print("----- to right")
            addTreeNode(&RootNode!.rightNode, value: value)
        }

        return RootNode!
    }
}

后序还会更新它的遍历方式

Swift2.2 看完这篇博客 你不想懂也会懂得----二叉树的更多相关文章

  1. [转帖]看完这篇文章,我奶奶都懂了https的原理

    看完这篇文章,我奶奶都懂了https的原理 http://www.17coding.info/article/22 非对称算法 以及 CA证书 公钥 核心是 大的质数不一分解 还有 就是 椭圆曲线算法 ...

  2. 看完这篇文章,我奶奶都懂了https的原理

    本文在个人技术博客同步发布,详情可猛戳 亦可扫描屏幕右方二维码关注个人公众号 Http存在的问题   上过网的朋友都知道,网络是非常不安全的.尤其是公共场所很多免费的wifi,或许只是攻击者的一个诱饵 ...

  3. 第一篇博客 ---- 分享关于Maven使用的一些技巧

    Maven环境搭建 在官网上下载maven安装包,地址:http://maven.apache.org/download.cgi . 解压文件到电脑坐在盘符目录,如E:\apache-maven-3. ...

  4. 第一篇博客:Hello World

    2016年10月10日,双十,好日子,决定开始写第一篇博客,标题想了会,就叫Hello World 吧,哈哈^_^. 首先感谢博客园的管理们能批准我的申请,记得在14年的时候申请过一次,竟然没申请通过 ...

  5. [书籍]值得纪念的第100篇博客,推荐一些看过的UI书籍

    1. 前言 来到博客园11年,这两年闲下来了才有时间写写博客,不知不觉终于写到第100篇博客了.回顾过去发表的博客,居然大部分都与UI相关.明明我本来从事的是Oracle的相关开发,明明我当初的目标是 ...

  6. 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务 | 百篇博客分析OpenHarmony源码 | v41.03

    百篇博客系列篇.本篇为: v41.xx 鸿蒙内核源码分析(任务切换篇) | 看汇编如何切换任务 | 51.c.h .o 任务管理相关篇为: v03.xx 鸿蒙内核源码分析(时钟任务篇) | 触发调度谁 ...

  7. 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙看这篇或许真的够了 | 百篇博客分析OpenHarmony源码 | v50.06

    百篇博客系列篇.本篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉坑指南 | 51.c.h.o 编译构建相关篇为: v50.xx 鸿蒙内核源码分析(编译环境篇) | 编译鸿蒙防掉 ...

  8. Hello World -- 第一篇博客

    今年注定是不寻常的一年,因为技术,接触了许多大牛.通过一篇篇博文,看到了大牛们勤奋好学.孜孜不倦的精神,于是决定也开个博客,向大牛学习. 博客开了,写点什么呢?奈何肚子里墨水不多,吐出来也多是白沫,不 ...

  9. 看完这篇还不会 GestureDetector 手势检测,我跪搓衣板!

    引言 在 android 开发过程中,我们经常需要对一些手势,如:单击.双击.长按.滑动.缩放等,进行监测.这时也就引出了手势监测的概念,所谓的手势监测,说白了就是对于 GestureDetector ...

随机推荐

  1. Servlet中的过滤器Filter用法

    1.过滤器的概念 Java中的Filter 并不是一个标准的Servlet ,它不能处理用户请求,也不能对客户端生成响应. 主要用于对HttpServletRequest 进行预处理,也可以对Http ...

  2. ireport 取消自动分页,detail不分页,当没有数据的时候显示title

    报表文件属性页面 lgnore pagination 勾选上,就可以取消分页功能.

  3. 饼干是这样压缩的——PHP使用zlib扩展实现页面GZIP压缩输出

    饼干是这样压缩的——PHP使用zlib扩展实现页面GZIP压缩输出 GZIP(GNU-ZIP)是一种压缩技术.经过GZIP压缩后页面大小可以变为原来的30%甚至更小.这样用户浏览的时候就会感觉很爽很愉 ...

  4. 在PHP语言中使用JSON

      目前,JSON已经成为最流行的数据交换格式之一,各大网站的API几乎都支持它. 我写过一篇<数据类型和JSON格式>,探讨它的设计思想.今天,我想总结一下PHP语言对它的支持,这是开发 ...

  5. UVa 357 - Let Me Count The Ways

    题目大意:也是硬币兑换问题,与147.674用同样的方法即可解决. #include <cstdio> #include <cstring> #define MAXN 3000 ...

  6. SpringMVC常用注解@Controller,@Service,@repository,@Component

    SpringMVC常用注解@Controller,@Service,@repository,@Component controller层使用@controller注解 @Controller 用于标记 ...

  7. BZOJ1237: [SCOI2008]配对

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=1237 题目大意:你有n 个整数Ai和n 个整数Bi.你需要把它们配对,即每个Ai恰好对应一 ...

  8. 为什么ajax 必须同源,same origin policy

    ajax 所有请求都会附带主域的cookie, 若没有同源策略,攻击者就可以获取你的cookie,状态.

  9. 2.5. Integer 16 、Integer 32、Integer 64(Core Data 应用程序实践指南)

    Core Data 使用 “带符号的整数”,通常我们会选择Integer 32,如果不够,可以升级为Integer 64 (第3章),通过升级托管对象模型. 这三种类型对应的特性(Property)类 ...

  10. C++第五天学习

    回顾: 1.友元 friend 2.运算符重载 类型 operator运算符(参数表) 抽象.封装 类是面向对象程序设计中最基本的概念 类的背后隐藏的思想是数据抽象和封装 是进行封装和数据隐藏的工具, ...