一、题目描述
请实现一个函数按照之字形顺序打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右到左的顺序打印,第三行再按照从左到右的顺序打印,其他行以此类推。
例如:
给定二叉树[3,9,20,null,null,15,7]
3
/ \
9 20
/ \
15 7
返回:
[
[3],
[20,9],
[15,7]
]
提示:
节点总数 <= 1000
二、思路分析
注:思路分析中的一些内容和图片参考自力扣各位前辈的题解,感谢他们的无私奉献
思路
①按层打印:题目要求的二叉树的层序遍历又称为二叉树的广度优先搜索(BFS)。BFS通常借助队列的先入先出特性来实现。
②每层打印到一行:将本层全部结点打印到一行,并将下一层全部结点加入队列,以此类推,即可分为多行打印。
③按之字型打印:奇数行顺序打印,偶数行倒序打印。根据行数的奇偶性对打印的位置进行控制,奇数行从开头打印,偶数行则从行尾开始。
算法流程:
1、特例处理:当根结点为空,则返回空列表[]
2、初始化:定义用于返回的二维数组res
,定义队列queue
,将根结点入队
3、BFS循环:当队列queue
为空时跳出;
----3.1 计算出队列的长度,也就是当前层的结点数。
----3.2 判断当前行是奇数行还是偶数行,对后面循环打印的起始位置进行设置
----3.3 当前层打印循环,循环次数为当前层结点数
------3.3.1 出队:队首元素出队,记为tmp
------3.3.2 打印:根据奇偶性不同,将tmp.val
添加至res
对应的地方
------3.3.3 添加子节点:若tmp
的左(右)子结点不为空,则将左(右)子结点加入队列queue
4、返回值:返回二维数组res
即可。
复杂度分析:
时间复杂度 O ( N ) \rm{O(N)} O(N):N
为二叉树的结点数量,即BFS需循环N
次。
空间复杂度 O ( N ) \rm{O(N)} O(N):最差情况下,即当树为平衡二叉树时,最多有N/2
个树结点同时在queue
中,使用O(N)
大小的额外空间。
三、整体
整体代码如下
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Return an array of arrays of size *returnSize.
* The sizes of the arrays are returned as *returnColumnSizes array.
* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().
*/
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes){
//树为空时
if (!root) {
*returnSize = 0;
*returnColumnSizes = NULL;
return NULL;
}
*returnSize = 0; //返回数组的行数,即二叉树的高度
int** res = (int**)malloc(sizeof(int*) * 10001); //返回数组
*returnColumnSizes = (int*)malloc(sizeof(int) * 10001); //返回数组中每一行的列数
struct TreeNode** queue = (struct TreeNode**)malloc(sizeof(struct TreeNode*) * 10001); //新建队列
int head = -1; //head为队首下标,初始化为-1,代表没有元素
int rear = 0; //rear为队尾元素后面的位置,初始化为0,代表需要入的元素插入到这个地方
queue[++head] = root; //将根结点插入,队首坐标往后挪
rear++; //队尾位置往后挪
//遍历二叉树
while (head < rear) {
/*
记录当前的rear,因为我们要对树的每一层进行遍历,每一层的结点数=rear-head
而在遍历每一层过程中,要对各个结点左右孩子进行入队,此时rear又要变化
所以定义一个preRear,根据这个preRear控制对当前层的遍历
*/
int preRear = rear;
res[*returnSize] = (int*)malloc(sizeof(int) * (preRear - head)); //记录当前行的各个结点的值
(*returnColumnSizes)[*returnSize] = preRear - head; //记录当前行的列数
int col; //记录当前行开始遍历的结点的下标
//*returnSize代表当前是多少行,注意这里是从第0行开始,所以*returnSize为偶数时是奇数列
if (*returnSize % 2 == 0) {
col = 0; //奇数列,则顺序对当前层结点进行遍历
}
else{
col = preRear - head - 1; //偶数列,则逆序对当前层结点进行遍历
}
//遍历当前行
for (; head < preRear; head++) {
struct TreeNode* tmp = queue[head]; //出队
if (*returnSize % 2 == 0) {
res[*returnSize][col++] = tmp->val;
}
else{
res[*returnSize][col--] = tmp->val;
}
//左右孩子入队
if (tmp->left) {
queue[rear++] = tmp->left;
}
if (tmp->right) {
queue[rear++] = tmp->right;
}
}
(*returnSize)++; //当前行处理完毕,行数+1
}
return res;
}
运行,测试通过