額, 先看下什麼是完全二叉樹 ,
葉子只能出現在最下面的二層
最下層的葉子一定集中在左部的連續位置
倒數第二層 若有葉子結點 一定在右部連續位置
如果結點的度爲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];
}
}