额, 先看下什么是完全二叉树 ,
叶子只能出现在最下面的二层
最下层的叶子一定集中在左部的连续位置
倒数第二层 若有叶子结点 一定在右部连续位置
如果结点的度为1 ,则该结点只有左孩子
同样结点的二叉树,完全二叉树的深度最小
这是一个完全二叉树
以下都不是完全二叉树
根据数组生成一个完全二叉树,
思路1:叶子节点的下标/2 就是对应的父节点,(此思路的核心)
先有一个数组保存所有的节点,
然后生成每一个节点,然后根据生成节点的下标/2 找到父节点,
如果下标是偶数, 那就是左孩子,下标为奇数,是右孩子.
思路2:数组的传入顺序和二叉树的层次遍历顺序一致的(核心思路)
1.用一个数组模拟队列, 进行层次遍历,把第一个节点放入到队列中,
2.取出队列中第一个元素, 如果数组有后续,就生成一个节点,设置为左孩子
3.下标增加,如果数组还有后续,就生成一个节点,设置为右孩子
4.循环2,3步,直到传入数组遍历完成
@interface TreeNode : NSObject
/// 根据数组生成一个完全二叉树
+ (TreeNode *)nodeWithDataArray:(NSArray *)dataArray;
/// 生成一个节点,左右节点为nil
+ (TreeNode *)nodeWithData:(int)data;
/// 生成一个节点,左右节点为指定节点
+ (TreeNode *)nodeWithData:(int)data leftNode:(TreeNode *)leftNode rightNode:(TreeNode *)rightNode;
@property (nonatomic, assign) int data;
@property (nonatomic, strong) TreeNode * leftNode;
@property (nonatomic, strong) TreeNode * rightNode;
@end
-------
#import "TreeNode.h"
@implementation TreeNode
// 实现方式1:根据完全二叉树的下标(1~n)来处理, 任意子节点的下标/2 都是父节点
+ (TreeNode *)nodeWithDataArray:(NSArray *)dataArray {
if (dataArray == nil || dataArray.count == 0) {
return nil;
}
//根据数组的数量,生成一个完全二叉树
NSMutableArray<TreeNode *> * treeArray = [NSMutableArray array];
//放一个占位的值,这样根节点的下标就对应成treeArray[1]了,计算父节点会更容易点
[treeArray addObject:[TreeNode nodeWithData:NAN]];
for (int i = 0; i<dataArray.count; i++) {
NSNumber * num = dataArray[i];
TreeNode * temp = [TreeNode nodeWithData:num.intValue];
// 如果是偶数,说明是对应父节点的左子节点
if (treeArray.count%2==0&&treeArray.count>1) {
TreeNode * father = treeArray[treeArray.count/2];
father.leftNode = temp;
}
// 如果是奇数,说明是对应父节点的右子节点
if (treeArray.count%2==1) {
TreeNode * father = treeArray[treeArray.count/2];
father.rightNode = temp;
}
[treeArray addObject:temp];
}
return treeArray[1];
}
/// 实现方式2:模拟层次遍历, 依次生成子节点并赋值
+ (TreeNode *)nodeWithDataArray2:(NSArray<NSNumber *> *)dataArray {
if (dataArray == nil || dataArray.count == 0) {
return nil;
}
//模拟队列结构,进行层次遍历
NSMutableArray<TreeNode *> * treeArray = [NSMutableArray array];
TreeNode * root = [TreeNode nodeWithData:dataArray.firstObject.intValue];
[treeArray addObject:root];
for (int i = 1; i<dataArray.count; i++) {
NSNumber * num = dataArray[i];
TreeNode * leftNode = [TreeNode nodeWithData:num.intValue];
TreeNode * father = treeArray.firstObject;
[treeArray removeObject:father];
father.leftNode = leftNode;
[treeArray addObject:leftNode];
i++;
if (i>=dataArray.count) {
break;
}
num = dataArray[i];
TreeNode * rightNode = [TreeNode nodeWithData:num.intValue];
father.rightNode = rightNode;
[treeArray addObject:rightNode];
}
return root;
}
+ (TreeNode *)nodeWithData:(int)data {
TreeNode * root = [[TreeNode alloc] init];
root.data = data;
return root;
}
+ (TreeNode *)nodeWithData:(int)data leftNode:(TreeNode *)leftNode rightNode:(TreeNode *)rightNode {
TreeNode * root = [[TreeNode alloc] init];
root.data = data;
root.leftNode = leftNode;
root.rightNode = rightNode;
return root;
}
- (NSString *)description {
return [NSString stringWithFormat:@"%d %@ %@",self.data,self.leftNode,self.rightNode];
}
@end
到此,我们可以很方便的生成一个二叉树了, 然后开始处理二叉树镜像. 类似于这样的, 对于根节点来说, 就是左右孩子的值进行一次交换, 然后递归左子树,递归右子树.
- (void)viewDidLoad {
[super viewDidLoad];
[self mirrorTree];
}
/// 二叉树镜像
- (void)mirrorTree {
TreeNode * root = [TreeNode nodeWithDataArray:@[@(8),@(6),@(10),@(5),@(7),@(9),@(11)]];
NSLog(@"%@",root);
[self __mirrorAction:root];
NSLog(@"%@",root);
}
- (void)__mirrorAction:(TreeNode *)root {
if (root.leftNode == nil && root.rightNode == nil) {
return;
}
// 左右节点交换值
TreeNode * temp = root.leftNode;
root.leftNode = root.rightNode;
root.rightNode = temp;
// 递归调用左子树
if (root.leftNode) {
[self __mirrorAction:root.leftNode];
}
// 递归调用右子树
if (root.rightNode) {
[self __mirrorAction:root.rightNode];
}
}