四种遍历概念
(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");
}