1. 题目描述
给定一个二叉树,返回其按层次遍历的节点值。 (即逐层地,从左到右访问所有节点)。
例如:
给定二叉树: [3,9,20,null,null,15,7],
3
/
9 20
/
15 7
返回其层次遍历结果:
[
[3],
[9,20],
[15,7]
]
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/binary-tree-level-order-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
2.思考过程
//思路:这道题的flag是广度搜索优先,但是我是按照自己的想法来写的(-_-!),由于题目限定是二叉树,所以我使用递归,
题目的要求是将遍历后的结果以一个二维数组的形式返回,而且,也要返回这个二维数组的每一行的元素个数。
通过看要求可以得出,这个二维数组的维度应该为:树的高度 * 每一个高度(层)所代表的广度(也就是该层数的节点总数)。
所以我的思路就是:
(1)我开始第一次遍历一个特定的层次(高度)的时候,我就动态分配一块内存(也即是,分配该二维数组的一行内存空间),并将访问的该层次的第一个节点的值赋值给我所分配的内存空间的第一个元素。
(2)我在遍历一个特定的层次(高度)的时候,我判断我是否是第一次遍历该层次,是的话我就执行(1),不是的话我就在(1)中所分配的那一行空间,将我正在访问的到的节点的值复制给这行空间中的某个下标所代表的空间,
,该下标是采用一个相对于该层次来说的全局变量来存储的,所以不用担心会找不到正确的赋值位置。每一次的全局变量就构成了要返回的二维数组的每一行的元素个数的数组。
这就是我的基本思路,代码就是在这个思路上写出来,然后不停地提交、gdb调试、vs写测试用例来调试,不断地改进,最终提交通过!总共提交了17次才通过(历时估计快半个月了,卡在一个点写不出来又放一放,然后又改改挑挑地,最终通过!)
3.代码如下
//2019-08-06提交通过
typedef struct TreeNode treenode;
void makearray(treenode* root,int* treedim,int** returnColumnSizes,int* colunmnarray,int count,int *returnSize)
{
int lefttreedim = 0;
int righttreedim = 0;
int basecount = 0;
int i = 0;
int tempa = 0;
int tempcount = 0;
int *ptemp = NULL;
if(root!=NULL)
{
if( returnColumnSizes[*treedim] == NULL)
{//该层遍历尚未开始,则为其分配数组空间,且初始化该维数组的第一个数组元素
returnColumnSizes[*treedim] = (int*)malloc(sizeof(int)*count);
memset(returnColumnSizes[*treedim],0,sizeof(int)*count);
returnColumnSizes[*treedim][0] = root->val;
colunmnarray[*treedim] = 1;
(*returnSize) += 1;//数组维度
}
else
{//表明此层的遍历并不是第一次开始
returnColumnSizes[*treedim][colunmnarray[*treedim]] = root->val;
colunmnarray[*treedim]++;
}
(*treedim)++;//树深度增加
lefttreedim = *treedim;
righttreedim = *treedim;
/*这是我觉得最精妙的地方,我为了能够使用在下面的左右孩子中递归使用
同一个维度(当前树的高度),因此使用两个变量lefttreedim和righttreedim,
并作为指针传递下去,这样我每一层的遍历都可以使用指针不同(为了避免维度增加时造成同步),
值相同的值来进行*/
makearray(root->left,&lefttreedim,returnColumnSizes, colunmnarray,count,returnSize);
makearray(root->right,&righttreedim,returnColumnSizes,colunmnarray,count,returnSize);
}
}
int maxnum(int a,int b)
{//两值取最大值
if(a >= b)
{
return a;
}
return b;
}
int BTDeep(treenode*root)
{//递归计算二叉树的高度
if(root == NULL)
{
return 0;
}
if(root->left != NULL || root->right != NULL )
{
return 1 + maxnum(BTDeep(root->left),BTDeep(root->right));
}
return 1;
}
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes)
{
if(root == NULL)
{
*returnSize = 0;
return NULL;
}
int newcount = 0;
int **newreturnColumnSizes = NULL;//动态分配的指针数组
int treedeep = BTDeep(root);//计算树的高度
int count = 0;
int treedim = 0;
int *colomun = NULL;
*returnSize = 0;
if(treedeep <= 0)
{
return NULL;
}
count = 200;//列数
colomun = (int*)malloc(sizeof(int)*treedeep);//用于存储二维数组的每一维的数组元素个数
if(colomun == NULL )
{
return NULL;
}
memset(colomun,0,sizeof(int)*treedeep);
newreturnColumnSizes = (int**)malloc(sizeof(int*)*treedeep);
if(newreturnColumnSizes == NULL )
{
return NULL;
}
memset(newreturnColumnSizes,0,sizeof(int*)*treedeep);
makearray(root,&treedim,newreturnColumnSizes,colomun,count,&newcount);
if(returnColumnSizes == NULL)
{
returnColumnSizes = (int**)malloc(sizeof(int*)*1);
}
*returnSize = newcount;
printf("%d\r\n",newcount);
*returnColumnSizes = colomun;
return newreturnColumnSizes;
}
4.新的实现
之前的方法是自己冥思苦想出来的,经过很长时间调试调通的,在调试过程中也加深了对C语言一二级指针的理解。
其实广度搜索优先类的题,借助一个队列,将每一层的元素入队后,然后逐元素出队,并将每个出队的元素的子结点再入队,这样就能得到从上到下,从左到右的访问顺序。
而队列里的一串元素,怎么保证不是多层的元素的组合呢?这个就是我们的for循环的作用,for循环保证我们将本层的元素全部处理完,再进入下一层元素的的遍历。所以while+for元素,就能实现层次遍历。
刷力扣真的要讲方法和套路,不然面试做题的时候,这种题除非真的编码能力超级强,才能快速地bug-free,不然写出来的代码也是错误百出。刷题真的太难了。
2021-03-26
/**
* 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().
*/
typedef struct TreeNode Node;
typedef struct st_node
{
Node* pnode;
struct st_node *prior;
struct st_node *next;
}que_node;
typedef struct st_queue
{
que_node *phead;
int size;
}queue;
que_node* make_quenode(Node* pnode)
{
que_node* ptmp = (que_node *)malloc(sizeof(que_node));
memset(ptmp,0,sizeof(que_node));
ptmp->pnode = pnode;
ptmp->prior = ptmp->next = ptmp;
return ptmp;
}
queue *pg_queue = NULL;
void init_queue()
{
pg_queue = (queue *)malloc(sizeof(queue));
memset(pg_queue,0,sizeof(queue));
}
void push_queue(Node* pnode)
{
if (pnode == NULL)
{
return;
}
que_node* ptmp = make_quenode(pnode);
if (pg_queue->phead == NULL)
{
pg_queue->phead = ptmp;
}
else
{//尾插入一个双向循环链表
ptmp->prior = pg_queue->phead->prior;
ptmp->next = pg_queue->phead;
pg_queue->phead->prior->next = ptmp;
pg_queue->phead->prior = ptmp;
}
pg_queue->size += 1;
}
que_node* pop_queue()
{
que_node *ptmp = NULL;
if (pg_queue->size == 0)
{
return ptmp;
}
ptmp = pg_queue->phead;
if (pg_queue->size == 1)
{
pg_queue->phead = NULL;
pg_queue->size -= 1;
return ptmp;
}
ptmp->prior->next = ptmp->next;
ptmp->next->prior = ptmp->prior;
pg_queue->phead = ptmp->next;
ptmp->next = NULL;
pg_queue->size -= 1;
return ptmp;
}
bool empty_queue()
{
if (pg_queue->size == 0)
{
return true;
}
return false;
}
int size_queue()
{
return pg_queue->size;
}
void free_queue()
{
free(pg_queue);
}
int** levelOrder(struct TreeNode* root, int* returnSize, int** returnColumnSizes)
{
init_queue();
push_queue(root);
int **ret = (int **)malloc(sizeof(int *)*(1000));;
int *colsize = NULL;
*returnSize = 0;
while (empty_queue() == false)
{
colsize = realloc(colsize,sizeof(int)*(*returnSize + 1));
colsize[*returnSize] = 0;
int size = size_queue();
printf("size:%d\n",size);
int elem_size = 0;
if (size > 0)
{
ret[*returnSize] = (int *)malloc(sizeof(int)*(1000));
elem_size = 0;
}
for (int i = 0;i < size;i++)
{
que_node *ptmp = pop_queue();
printf("%d\n",ptmp->pnode->val);
ret[*returnSize][elem_size++] = ptmp->pnode->val;
push_queue(ptmp->pnode->left);
push_queue(ptmp->pnode->right);
free(ptmp);
ptmp = NULL;
}
colsize[*returnSize] = elem_size;
(*returnSize)++;
}
*returnColumnSizes = colsize;
free_queue();
return ret;
}
5.新的实现
上述代码,其实没有必要将详细的出入队过程写出来,代码长耗时间和容易出错,且都是没有必要的,下面的实现更简洁
//2021-03-31
typedef struct TreeNode Node;
typedef struct st_stack
{
Node *nodearray[3000];
int top;
int tail;
int size;
}Queue;
/**
* 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){
int **ret = NULL;
int *retcol = NULL;
*returnSize = 0;
int tmpcount = 0;
if (root == NULL)
{
return ret;
}
Queue g_queue;
memset(&g_queue,0,sizeof(Queue));
g_queue.nodearray[g_queue.top++] = root;
g_queue.size++;
while (g_queue.size > 0)
{
ret = realloc(ret,sizeof(int *)*(*returnSize + 1));
ret[*returnSize] = (int *)malloc(sizeof(int)*(g_queue.size));
tmpcount = 0;
retcol = realloc(retcol,sizeof(int)*(*returnSize + 1));
retcol[*returnSize] = g_queue.size;
int size = g_queue.size;
for (int i = 0; i< size;i++)
{
Node *ptop = g_queue.nodearray[g_queue.tail];
g_queue.tail++;
g_queue.size--;
ret[*returnSize][tmpcount++] = ptop->val;
if (ptop->left)
{
g_queue.nodearray[g_queue.top++] = ptop->left;
g_queue.size++;
}
if (ptop->right)
{
g_queue.nodearray[g_queue.top++] = ptop->right;
g_queue.size++;
}
}
(*returnSize)++;
}
*returnColumnSizes = retcol;
return ret;
}