二叉树的4种遍历方式

四种遍历概念

        (1)前序遍历:先访问根节点,再访问左子树,最后访问右子树。

          (2)  后序遍历:先左子树,再右子树,最后根节点。

        (3)中序遍历:先左子树,再根节点,最后右子树。

        (4)层序遍历:每一层从左到右访问每一个节点。

     每一个子树遍历时依然按照此时的遍历顺序。

如下图:

    先序遍历:FCADBEHGM

    后序遍历:ABDCHMGEF

    中序遍历:ACBDFHEMG

    层序遍历:FCEADHGBM


代码上的话,递归的写法最好理解,也最简单. 非递归的就比较麻烦.

定义了一个节点类,很简单.一开始想用结构体,但是c语言的内存管理有点麻烦,就不写了.

#import <Foundation/Foundation.h>

@interface Node : NSObject

@property (nonatomic,assign) NSInteger data ;
@property (nonatomic,strong) Node * left ;
@property (nonatomic,strong) Node * right ;

+ (instancetype)nodeWithData:(NSInteger)data;

@end


#import "Node.h"

@implementation Node

+ (instancetype)nodeWithData:(NSInteger)data {
    
    Node * n = [[self alloc] init];
    n.data = data;
    return n;
    
}

- (NSString *)description {
    return @(self.data).description;
}

@end

外界调用, 前序/中序/后序 递归的写法很类似,只是输出的时机略有不同而已.生成的树结构是这样的.

#import <Foundation/Foundation.h>
#import "Node.h"

Node * initTree() {
    Node * root = [Node nodeWithData:10];
    Node * left5 = [Node nodeWithData:5];
    Node * right15 = [Node nodeWithData:15];
    root.left = left5;
    root.right = right15;
    
    Node * left1 = [Node nodeWithData:1];
    Node * right7 = [Node nodeWithData:7];
    left5.left = left1;
    left5.right = right7;
    
    Node * left12 = [Node nodeWithData:12];
    Node * right18 = [Node nodeWithData:18];
    right15.left = left12;
    right15.right = right18;
    
    Node * left6 = [Node nodeWithData:6];
    right7.left = left6;
    
    Node * left17 = [Node nodeWithData:17];
    right18.left = left17;

    Node * right2 = [Node nodeWithData:2];
    left1.right = right2;
    
    return root;
}

// 层次遍历
void showLineTree(Node * root){
    NSMutableArray<Node *> * array = [NSMutableArray array];
    [array addObject:root];
    NSLog(@"层次遍历--start");
    while (array.count>0) {
        
        Node * temp = array.firstObject ;
        [array removeObject:temp];
        NSLog(@"%@",@(temp.data) );
        if (temp.left) {
            [array addObject:temp.left];
        }
        if (temp.right) {
            [array addObject:temp.right];
        }
    }
    NSLog(@"层次遍历--end");

}
// 前序遍历
void showMLRTree(Node * root){
    if (root == nil) {
        return;
    }
    NSLog(@"%@",@(root.data) );
    showMLRTree(root.left);
    showMLRTree(root.right);
}
// 中序遍历
void showLMRTree(Node * root){
    if (root == nil) {
        return;
    }
    showLMRTree(root.left);
    NSLog(@"%@",@(root.data) );
    showLMRTree(root.right);
}
// 后序遍历
void showLRMTree(Node * root){
    if (root == nil) {
        return;
    }
    showLRMTree(root.left);
    showLRMTree(root.right);
    NSLog(@"%@",@(root.data) );
}


// 中序遍历,非递归的方式比较麻烦,也不好理解,就写一个吧
void showLMRTree2(Node * root){
    
    NSMutableArray * stack = [NSMutableArray array];
    
    while (stack.count>0||root!=nil) {
        
        // 一直找左节点,找到root节点的最左边节点
        while (root) {
            [stack addObject:root];
            root = root.left;
        }
        // 弹出这个子树下的最左节点,打印
        Node * left = stack.lastObject;
        [stack removeLastObject];
        NSLog(@"%@",@(left.data) );
        
        // 然后该打印最左节点的中间节点,这个中间节点其实也在栈上,下次循环就会打印
        
        // 打印栈顶节点对应的右子树
        root = left.right;
        
    }
    
}

int main(){    
    
    // 初始化树
    Node * root = initTree();
    // 层次遍历
    showLineTree(root);
    // 前序遍历
    showMLRTree(root);
    NSLog(@"前序遍历--end");
    // 中序遍历
    showLMRTree(root);
    NSLog(@"中序遍历--end");
    // 后序遍历
    showLRMTree(root);
    NSLog(@"后序遍历--end");
    // 中序遍历,非递归
    showLMRTree2(root);
    NSLog(@"中序遍历-非递归--end");

}
 


 

发布了101 篇原创文章 · 获赞 33 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/u014600626/article/details/104089759