中序遍历
https://leetcode-cn.com/problems/binary-tree-inorder-traversal/
递归
这里直接判断左右节点是否是NULL,意味着不需要将节点下移到叶子节点,在下一次递归的时候再判断,个人认为这样会好一点,虽然代码逻辑会复杂一点。
递归的对象是子树,那么传递的参数主要就是根节点;
递归的思路很简单:
如果有左子树,就先递归左子树(因为这一步不需要保存左叶子,因此暂时不考虑);
递归完左子树后,或者没有左子树了,就保存根节点;
如果有右子树就递归右子树(因为这一步不需要保存右叶子,因此暂时不考虑);
考虑一下叶子是否被保存了,是的,因为叶子可以看作NULL的根,所以在递归到最底层会被保存。
最后考虑一下需不需要返回值,每次递归只需要处理子树,子树不需要反馈父树什么内容,因此不需要返回值。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
void mid_fun(struct TreeNode* node,int* out, int* returnSize){
printf("%d,",node->val);
if(node->left != NULL){
mid_fun(node->left,out,returnSize);
}
out[*returnSize] = node->val;
(*returnSize)++;
if(node->right != NULL){
mid_fun(node->right,out,returnSize);
}
}
#define N 200
int* inorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
if(root==NULL){
return NULL;
}
int res[N] = {0};
mid_fun(root,res,returnSize);
// printf("%d===",*returnSize);
// for(int i=0;i<*returnSize;i++){
// printf("%d,",res[i]);
// }
int *res0 = malloc((*returnSize)*sizeof(int));
memcpy(res0,res,(*returnSize)*sizeof(int));
return res0;
}
栈
何时入栈?对每一个节点先沿左子树遍历,对每一个路过的节点入栈。
入栈顺序?先入栈所有的左节点,出栈保存后,即入栈右节点。
何时出栈?出栈时保存。当遍历到每个子树最左端的叶子节点后,开始出栈。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
#define N 200
int* inorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
if(root==NULL){
return NULL;
}
struct TreeNode* stack[N] = {0};
int stacktop = -1;
int res[N] = {0};
struct TreeNode *p = root;
while(stacktop!=-1 || p != NULL){//栈不为空
while(p!=NULL){
stack[++stacktop] = p;
p = p->left;
}
p = stack[stacktop--];
res[*returnSize] = p->val;
(*returnSize)++;
p = p->right;
}
int *res0 = malloc((*returnSize)*sizeof(int));
memcpy(res0,res,(*returnSize)*sizeof(int));
return res0;
}
前序遍历
https://leetcode-cn.com/problems/binary-tree-preorder-traversal/
递归
因为要先保存根节点,因此换一下顺序就行了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void left_fun(struct TreeNode* node,int* out, int* returnSize){
// printf("%d,",node->val);
out[*returnSize] = node->val;
(*returnSize)++;
if(node->left != NULL){
left_fun(node->left,out,returnSize);
}
if(node->right != NULL){
left_fun(node->right,out,returnSize);
}
}
#define N 200
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* preorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
if(root==NULL){
return NULL;
}
int res[N] = {0};
left_fun(root,res,returnSize);
// printf("%d===",*returnSize);
// for(int i=0;i<*returnSize;i++){
// printf("%d,",res[i]);
// }
int *res0 = malloc((*returnSize)*sizeof(int));
memcpy(res0,res,(*returnSize)*sizeof(int));
return res0;
}
栈
我们要把根节点保存起来,不然访问到叶子节点后就丢失整个树了。观察递归的代码,我们发现保存叶子节点和保存根节点的动作是一致的,因此我们规定,入栈不保存,出栈时保存,下一个解决的问题就是何时入栈,何时出栈,入栈顺序的问题了。
何时入栈:因为树结构保存在栈中,因此得到一个节点后想要迭代到叶子节点,必须先把叶子节点都保存起来,因此出栈后就把这个节点的叶子节点按照(右-左)顺序入栈;
入栈顺序:按照右-左顺序入栈,出栈时就是左-右,符合要求。
何时出栈:刚开始root入栈,之后就开始迭代,没出栈一个节点就处理当前节点,直到栈空。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
#define N 200
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* preorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
if(root==NULL){
return NULL;
}
struct TreeNode* stack[N] = {0};
int stacktop = -1;
int res[N] = {0};
struct TreeNode *p;
stack[++stacktop] = root;//根节点入栈
while(stacktop!=-1){//栈不为空
p = stack[stacktop--];
res[*returnSize] = p->val;
(*returnSize)++;
if(p->right != NULL) stack[++stacktop] = p->right;
if(p->left != NULL) stack[++stacktop] = p->left;
}
// printf("%d===",*returnSize);
// for(int i=0;i<*returnSize;i++){
// printf("%d,",res[i]);
// }
int *res0 = malloc((*returnSize)*sizeof(int));
memcpy(res0,res,(*returnSize)*sizeof(int));
return res0;
}
后序遍历
https://leetcode-cn.com/problems/binary-tree-postorder-traversal/
递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void right_fun(struct TreeNode* node,int* out, int* returnSize){
// printf("%d,",node->val);
if(node->left != NULL){
right_fun(node->left,out,returnSize);
}
if(node->right != NULL){
right_fun(node->right,out,returnSize);
}
out[*returnSize] = node->val;
(*returnSize)++;
}
#define N 200
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* postorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
if(root==NULL){
return NULL;
}
int res[N] = {0};
right_fun(root,res,returnSize);
// printf("%d===",*returnSize);
// for(int i=0;i<*returnSize;i++){
// printf("%d,",res[i]);
// }
int *res0 = malloc((*returnSize)*sizeof(int));
memcpy(res0,res,(*returnSize)*sizeof(int));
return res0;
}
栈
这个可以考虑和中序遍历一样的方法,先遍历到最左边的叶子,但是这意味着在遍历过程中需要把大半个树入栈。在网上看到下面这种方法不错:
和前序遍历一样,只不过交换一下左右子树入栈顺序,最后得到的结果是”右左中“,那么只需要对结果反转便可以了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
#define N 200
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* postorderTraversal(struct TreeNode* root, int* returnSize){
*returnSize = 0;
if(root==NULL){
return NULL;
}
struct TreeNode* stack[N] = {0};
int stacktop = -1;
int res[N] = {0};
struct TreeNode *p;
//对每一层按序存入(右左),出栈保存
stack[++stacktop] = root;//根节点入栈
while(stacktop!=-1){//栈不为空
p = stack[stacktop--];
res[*returnSize] = p->val;
(*returnSize)++;
if(p->left != NULL) stack[++stacktop] = p->left;
if(p->right != NULL) stack[++stacktop] = p->right;
}
int *res0 = malloc((*returnSize)*sizeof(int));
for(int i=0;i<*returnSize;i++){
res0[i] = res[(*returnSize)-i-1];
}
return res0;
}
层次遍历
这个用队列可以轻松实现,就不说了。