1.二叉树的递归遍历
写递归需要考虑
确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
前序遍历
void traversal(TreeNode* cur,vector& vec){ //①确定递归函数的参数和返回值
if(cur == nullptr) return; //②确定终止条件
//③确定单层递归的逻辑
vec.push_back(cur->val);
traversal(cur->left,vec);
traversal(cur->right,vec);
}
vector preorderTraversal(TreeNode* root) {
vector result;
traversal(root,result);
return result;
}
2.二叉树的非递归遍历
使用栈,对于前序遍历,先将根节点入栈,然后栈顶元素出栈,右节点入栈,左节点入栈。
vector preorderTraversal(TreeNode* root) {
stack st;
vector result;
if(root == nullptr) return result;
st.push(root); //根节点入栈
while(!st.empty()){
TreeNode* node = st.top();
st.pop();
result.push_back(node->val);
if(node->right) st.push(node->right);
if(node->left) st.push(node->left);
}
return result;
}
后续遍历(左右中)可以根据前序遍历代(中左右)码修改得到。
前序遍历是中左右,因此我们可以得到中右左顺序的遍历方法,然后将中右左反转(reverse),得到左右中。
vector postorderTraversal(TreeNode* root) {
vector result;
stack st;
if(root == nullptr) return result;
st.push(root);
while(!st.empty()){
TreeNode* cur = st.top();
st.pop();
result.push_back(cur->val);
if(cur->left) st.push(cur->left);
if(cur->right) st.push(cur->right);
}
reverse(result.begin(),result.end());
return result;
}
中序遍历的非递归和前序和后序不一样,需要遍历节点和处理节点两部分。
vector inorderTraversal(TreeNode* root) {
vector result;
stack st;
TreeNode* cur = root;
while(cur != nullptr || !st.empty()){ //循环条件是当前节点不为空,循环到最后当前节点是空的,为了让循环终止需要在加一个判断条件:判断栈是否为空,如果空跳出循环
if(cur != nullptr){ //遍历节点
st.push(cur);
cur = cur->left; //左
}else{ //处理节点
cur = st.top();
st.pop();
result.push_back(cur->val); //中
cur = cur->right;
}
}
return result;
}
3.二叉树的层序遍历 (广度优先搜索)
vector> levelOrder(TreeNode* root) {
vector> result;
queue que;
if(root == nullptr) return result;
else{
que.push(root);
while(!que.empty()){
int size = que.size(); //que.size是不断变化的
vector vec;
for(int i = 0; i < size; i++){
TreeNode* cur = que.front();
que.pop();
vec.push_back(cur->val);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
result.push_back(vec);
}
}
return result;
}
二叉树的右视图
vector rightSideView(TreeNode* root) {
queue que;
if (root != NULL) que.push(root);
vector result;
while (!que.empty()) {
int size = que.size();
for (int i = 0; i < size; i++) {
TreeNode* node = que.front();
que.pop();
if (i == 0) result.push_back(node->val);
if (node->right) que.push(node->right);
if (node->left) que.push(node->left);
}
}
return result;
}
4.翻转二叉树
(1)递归法
TreeNode* invertTree(TreeNode* root) {
//递归
//1.确定递归函数的返回值和参数:返回头节点;参数需要当前节点
//2.确定终止条件:当前节点为空的时候,就返回
//3.单层递归的逻辑:交换左右孩子,然后以在孩子为根节点继续递归
if(root == nullptr) return root;
swap(root->left,root->right);
invertTree(root->left);
invertTree(root->right);
return root;
}
(2)迭代法:深度优先遍历
TreeNode* invertTree(TreeNode* root) {
//迭代法:深度优先遍历
if(root == NULL) return root;
stack st;
st.push(root);
while(!st.empty()){
TreeNode* cur = st.top();
st.pop();
swap(cur->left,cur->right);
if(cur->right) st.push(cur->right);
if(cur->left) st.push(cur->left);
}
return root;
}
(3)迭代法:广度优先遍历
TreeNode* invertTree(TreeNode* root) {
//迭代法:广度优先遍历
queue que;
if(root == NULL) return root;
que.push(root);
while(!que.empty()){
int size = que.size();
for(int i = 0; i < size; i++){
TreeNode* cur = que.front();
que.pop();
swap(cur->left,cur->right);
if(cur->left) que.push(cur->left);
if(cur->right) que.push(cur->right);
}
}
return root;
}
4.判断是否是对称树
迭代法
bool isSymmetric(TreeNode* root) {
if(root == nullptr) return false;
queue que;
que.push(root->left);
que.push(root->right);
while(!que.empty()){ //没有判断空节点,这个队列一直都是非空,需要一个if跳出循环
TreeNode* leftNode = que.front(); que.pop();
TreeNode* rightNode = que.front(); que.pop();
if(!leftNode && !rightNode) continue;
if(!leftNode || !rightNode ||(leftNode->val != rightNode->val) ) return false;
que.push(leftNode->left);
que.push(rightNode->right);
que.push(leftNode->right);
que.push(rightNode->left);
}
return true;
}
5.平衡二叉树
每个节点左右两个子树的高度差的绝对值不超过 1 ,高度只能从下到上去查,所以只能后序遍历(左右中)
//递归
//1.函数返回值和参数:参数:当前传入节点。返回值:以当前传入节点为根节点的树的高度。
//2.递归终止条件:当前节点为空
//3.单层递归逻辑:求根节点左子树高度和其右子树高度的差值。分别求出其左右子树的高度,然后如果差值小于等于1,则返回当前二叉树的高度,否则则返回-1,表示已经不是二叉平衡树了。
int getHeight(TreeNode* cur){
if(cur == nullptr) return 0;
int leftHeight = getHeight(cur->left);
if(leftHeight == -1) return -1; // -1 表示已经不是平衡二叉树了,否则返回值是以该节点为根节点树的高度
int rightHeight = getHeight(cur->right);
if(rightHeight == -1) return -1;
return abs(leftHeight - rightHeight) <= 1 ? 1 + max(leftHeight,rightHeight) : -1 ;
}
bool isBalanced(TreeNode* root) {
return getHeight(root) == -1 ? false : true;
}
6.二叉树的所有路径
从根节点到叶子的路径,所以需要前序遍历,这样才方便让父节点指向孩子节点,找到对应的路径。
(1)递归法
void traversal(TreeNode* cur,vector& result,string path){
path = path + to_string(cur->val);
if(cur->left) traversal(cur->left, result, path + "->");
if(cur->right) traversal(cur->right, result, path + "->");
if(cur->left == nullptr && cur->right == nullptr){ //叶子节点
result.push_back(path);
return;
}
}
vector binaryTreePaths(TreeNode* root) {
vector result;
if(root == nullptr) return result;
traversal(root,result,"");
return result;
}
(2)迭代法:使用栈
vector binaryTreePaths(TreeNode* root) {
vector result;
if(root == nullptr) return result;
stack treeSt; //存放树节点
stack pathSt; //存放路径
treeSt.push(root);
pathSt.push(to_string(root->val));
while(!treeSt.empty()){
TreeNode* cur = treeSt.top(); treeSt.pop();
string path = pathSt.top(); pathSt.pop();
if(cur->right){
treeSt.push(cur->right);
pathSt.push(path + "->" + to_string(cur->right->val));
}
if(cur->left){
treeSt.push(cur->left);
pathSt.push(path + "->" + to_string(cur->left->val));
}
if(cur->left == nullptr && cur->right == nullptr){//叶子节点
result.push_back(path);
}
}
return result;
}
相关题目:二叉树路径之和是否满足目标值
(方法一)
思路:根据上一题思路设置俩个栈,一个放节点值,一个放已经遍历节点之和
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return false;
stack treeSt;
stack sumSt;
treeSt.push(root);
sumSt.push(root->val);
while(!treeSt.empty()){
TreeNode* cur = treeSt.top();treeSt.pop();
int curvalue = sumSt.top();sumSt.pop();
if(cur->right){
treeSt.push(cur->right);
sumSt.push(curvalue + cur->right->val);
}
if(cur->left){
treeSt.push(cur->left);
sumSt.push(curvalue + cur->left->val);
}
if(cur->left == nullptr && cur->right == nullptr){//叶子节点
if(curvalue == targetSum) return true;
}
}
return false;
}
(方法二)
此时栈里一个元素不仅要记录该节点指针,还要记录从头结点到该节点的路径数值总和,用pair结构来存放这个栈里的元素。定义为:pair
pair<节点指针,路径数值>
bool hasPathSum(TreeNode* root, int targetSum) {
if(root == nullptr) return false;
stack> st;
st.push(pair(root,root->val));
while(!st.empty()){
pair cur = st.top();
st.pop();
if(cur.first->right){
st.push(pair(cur.first->right,cur.second + cur.first->right->val));
}
if(cur.first->left){
st.push(pair(cur.first->left,cur.second + cur.first->left->val));
}
if(cur.first->left == nullptr && cur.first->right == nullptr){//叶子节点
if(targetSum == cur.second) return true;
}
}
return false;
}