因为平时刷题老是坚持不下来,决定以“show my work”的方式激励自己坚持下来。最近打算刷题巩固数据结构的知识点,就记录一下自己刷题过程中的经验和心得吧。
今天时间有限,记录一道很基础的题:二叉树的中序遍历。
题目描述
解题思路
好久没刷题了,循序渐进吧,我考虑的是更简单的递归算法。
首先要明确二叉树的前序、中序、后序遍历。简单描述就是:
前序:根(或者说当前节点)、左、右
中序:左、根(或者说当前节点)、右
后序:左、右、根(或者说当前节点)
其实就是根(或者说当前节点)在什么时候遍历。
这道题是非常直观的遍历二叉树的题,就是把二叉树节点全都找到,按左根右的顺序输出。但是我觉得前序、中序、后序遍历在更多的题目中并不是非常明显的提到,但我们解大部分题的时候会用到这个思想,以中序遍历为例:某道题我先对当前节点的左边节点(左子树)做了什么操作,然后又对当前节点做了操作,最后对右边节点(右子树)做了操作。这个操作不一定是输出,还有别的更复杂的。但是我们的整体思路其实就是一个中序遍历。
所以这道题如果用递归来解答:
先判断根节点是是否为空,为空,结束。(这也是递归跳出的关键条件)
不为空继续
按照中序遍历的思想:
首先对左节点(左子树)进行操作,如果函数为f,则f(root->left,...)
然后对根节点进行操作(这里包括根节点存的数据等等进行操作)
最后对右节点(右子树)进行操作,如果函数为f,则f(root->right,...)
这就是这题的大致框架,这是我之前就一拍脑袋用c写下了如下代码:
但是注意看LeetCode给的函数和参数:
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
}
struct TreeNode* root:根节点
int *returnSize:int类型的指针,指向返回的数组的size
就是说,我们要有一个数组在我们遍历到当前节点的时候将节点的值存下来,也就是我上面说的,“对当前节点进行的操作”。所以说仅有这2个参数,要构造一个可以递归的函数是不直观也不简单的,所以,我们再构造一个函数,专门用于处理中序遍历的递归过程,而inorderTraversal(struct TreeNode* root, int* returnSize)函数只需要做最基本的变量定义、赋值以及引用新函数即可。
再构造一个新函数:
void inorder(struct TreeNode* root, int*res,int*resSize) {
//左根右
//递归
//如果当前节点为null,返回
//反之 遍历左边,储存本身到res,然后遍历右边
if(!root) return ;
inorder(root->left,res,resSize);
res[(*resSize)++]=root->val;
inorder(root->right,res,resSize);
}
参数:
res:整形数组,按顺序储存每个节点的值
resSize(同上面函数的returnSize,表示res的数组下标,+1后就是数组大小)
最后,我们在inorderTraversal(struct TreeNode* root, int* returnSize)函数定义变量、赋初值以及引用新函数如下:
int* inorderTraversal(struct TreeNode* root, int* returnSize) {
int*res=malloc(sizeof(int)*101);//注意看清题目的数据范围
*returnSize=0;//赋初值
inorder(root,res,returnSize);
return res;
}
这是递归的解法如下,迭代的方法明天写~也许有点啰嗦,但是记录下来印象和思路都很清晰。
细节注意
(1)root是一个指向结构体的指针,所以在用到它存的值时,要用root->val,语句。
(2) res[(*resSize)++]=root->val;把resSize和returnSize定义为指针的原因:传入的是地址,所以递归过程中能保证下标在加1。