144.给你二叉树的根节点 root ,返回它节点值的 前序 遍历。
- 一个简单的通过递归来解答的题目,那为什么在这要做记录呢?由于我用的是c语言来解题,没有vector这种数据结构,所以要提前知道二叉树中有多少个元素,才能定义要返回的数组,可遗憾的是我们并不知道二叉树有多少个元素。所以想着要递归遍历二叉树两次,第一次计算二叉树有多少个元素,第二次在创建了要返回的数组的前提下遍历二叉树给这个数组添加元素。但是这样需要写两个递归函数,想想有点麻烦,看看题解是怎么做的。好家伙,题解直接使用malloc函数分配了2000个int空间,怎么感觉是投机取巧呢!
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void preOrder(struct TreeNode* root, int* res, int* returnSize) {
if (root == NULL)
return;
res[(*returnSize)++] = root->val;
preOrder(root->left, res, returnSize);
preOrder(root->right, res, returnSize);
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* preorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
preOrder(root, res, returnSize);
return res;
}
可是此时我又在想,为什么一定要用malloc呢,直接静态定义一个2000大小的整型数组不行吗?尝试了一下居然报错了,错误信息是这样的runtime error: load of null pointer of type 'int' [__Serializer__.c]
,好吧看来不行,但是这是为什么呢?又想了想觉得可能是因为我直接把数组名传递进递归函数了,而数组名是一个指针型常量,所以才导致出错,然而就算是我新创建一个指针变量去指向数组第一个元素,然后把这个指针变量传递给递归函数,结果依旧是不行。
所以只能是应该在传递指针给递归函数时,如果指针指向的区域是malloc函数分配的区域,那么这块区域已经分配好了,而如果是静态定义一个数组的话,只是声明了一个数组,只有在使用时才会分配空间,所以如果传递指向静态数组的指针变量,才会空指针错误。
不知道这种理解方法对不对,以后再遇到类似的情况再说吧。
- 这个题还有一种使用迭代法的解法,即非递归的方法,通过一个栈来实现遍历。首先将根节点入栈,然后出栈访问根节点(将节点元素放入res数组中),同时将根节点的右左结点依次入栈,然后只要栈不空就继续按照这样的规则执行下去,这样按照出栈的顺序就能得到中左右的遍历序列。
/**
* 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().
*/
int* preorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
struct TreeNode** stack = malloc(sizeof(struct TreeNode*) * 2000);
int top = -1;
if (root != NULL)
stack[++top] = root;
while (top != -1) {
struct TreeNode *temp = stack[top--];
res[(*returnSize)++] = temp->val;
if (temp->right != NULL)
stack[++top] = temp->right;
if (temp->left != NULL)
stack[++top] = temp->left;
}
return res;
}
94.给定一个二叉树的根节点 root ,返回它的 中序 遍历。
- 中序遍历的递归代码跟前序遍历的递归代码基本是一样的,只是要改变一下访问结点的顺序就行了。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void inOrder(struct TreeNode* root, int* res, int* returnSize) {
if (root == NULL)
return;
inOrder(root->left, res, returnSize);
res[(*returnSize)++] = root->val;
inOrder(root->right, res, returnSize);
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* inorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
inOrder(root, res, returnSize);
return res;
}
- 中序遍历的迭代法解法跟前序遍历的迭代法解法比较不一样,因为前序遍历的迭代法解法中遍历到哪个节点就访问哪个节点(放入res数组),而中序遍历的迭代法解法要等遍历到树左边底部时才开始访问节点,因此除了借助栈之外,还需要额外定义一个遍历指针p。
/**
* 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().
*/
int* inorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
struct TreeNode** stack = malloc(sizeof(struct TreeNode*) * 2000);
int top = -1;
struct TreeNode* p = root;
while (p != NULL || top != -1) {
if (p != NULL) { //往左走到底
stack[++top] = p;
p = p->left;
} else {
p = stack[top--]; //出栈的元素就是左边最底部的元素
res[(*returnSize)++] = p->val;
p = p->right; //往右走一步
}
}
return res;
}
145.给定一个二叉树,返回它的 后序 遍历。
- 后序遍历的递归代码和前序遍历跟中序遍历的递归代码基本是一样的。
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* struct TreeNode *left;
* struct TreeNode *right;
* };
*/
void postOrder(struct TreeNode* root, int* res, int* returnSize) {
if (root == NULL)
return;
postOrder(root->left, res, returnSize);
postOrder(root->right, res, returnSize);
res[(*returnSize)++] = root->val;
}
/**
* Note: The returned array must be malloced, assume caller calls free().
*/
int* postorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
postOrder(root, res, returnSize);
return res;
}
- 后序遍历的迭代法不难,只需要对前序遍历的迭代法修改一下即可。由于前序遍历得到的遍历序列是中左右,我们只需要修改一下代码,得到中右左的遍历序列,然后把遍历序列翻转一下即可得到左右中的遍历序列,即后序遍历序列。
/**
* 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().
*/
int* postorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
struct TreeNode** stack = malloc(sizeof(struct TreeNode*) * 2000);
int top = -1;
if (root != NULL)
stack[++top] = root;
//得到中右左的遍历序列
while (top != -1) {
struct TreeNode *temp = stack[top--];
res[(*returnSize)++] = temp->val;
if (temp->left != NULL)
stack[++top] = temp->left;
if (temp->right != NULL)
stack[++top] = temp->right;
}
//反转遍历序列
int i = 0;
int j = *returnSize - 1;
while (i < j) {
int temp = res[j];
res[j] = res[i];
res[i] = temp;
i++, j--;
}
return res;
}
- 看到题解还提供了一种前中后遍历的迭代法,这种做法也叫做标记法,也是利用栈来遍历二叉树,但是在将元素入栈的时候,要加上一个空标记用于标记下一个出栈结点是要被处理的结点。
前序遍历标记法:
/**
* 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().
*/
int* preorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
struct TreeNode** stack = malloc(sizeof(struct TreeNode*) * 2000);
int top = -1;
if (root != NULL)
stack[++top] = root;
while (top != -1) {
struct TreeNode *temp = stack[top];
if (temp != NULL) {
top--; //栈顶元素不为空的话,代表该元素不是要被处理的元素,则将它出栈,把右左孩子节点入栈后再把它加回去
if (temp->right != NULL)
stack[++top] = temp->right;
if (temp->left != NULL)
stack[++top] = temp->left;
stack[++top] = temp;
stack[++top] = NULL;
} else {
//栈顶元素是空的话,则代表标记下一个元素是要被处理的元素
res[(*returnSize)++] = stack[top - 1]->val;
top -= 2;
}
}
return res;
}
中序遍历标记法:
/**
* 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().
*/
int* inorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
struct TreeNode** stack = malloc(sizeof(struct TreeNode*) * 2000);
int top = -1;
if (root != NULL)
stack[++top] = root;
while (top != -1) {
struct TreeNode *temp = stack[top];
if (temp != NULL) {
top--; //栈顶元素不为空的话,代表该元素不是要被处理的元素,则将它出栈,把右左孩子节点入栈后再把它加回去
if (temp->right != NULL)
stack[++top] = temp->right;
stack[++top] = temp;
stack[++top] = NULL;
if (temp->left != NULL)
stack[++top] = temp->left;
} else {
//栈顶元素是空的话,则代表标记下一个元素是要被处理的元素
res[(*returnSize)++] = stack[top - 1]->val;
top -= 2;
}
}
return res;
}
后序遍历标记法:
/**
* 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().
*/
int* postorderTraversal(struct TreeNode* root, int* returnSize){
int *res = malloc(sizeof(int) * 2000);
*returnSize = 0;
struct TreeNode** stack = malloc(sizeof(struct TreeNode*) * 2000);
int top = -1;
if (root != NULL)
stack[++top] = root;
while (top != -1) {
struct TreeNode *temp = stack[top];
if (temp != NULL) {
top--; //栈顶元素不为空的话,代表该元素不是要被处理的元素,则将它出栈,把右左孩子节点入栈后再把它加回去
stack[++top] = temp;
stack[++top] = NULL;
if (temp->right != NULL)
stack[++top] = temp->right;
if (temp->left != NULL)
stack[++top] = temp->left;
} else {
//栈顶元素是空的话,则代表标记下一个元素是要被处理的元素
res[(*returnSize)++] = stack[top - 1]->val;
top -= 2;
}
}
return res;
}