目录
二叉树理论基础篇
二叉树的定义
刚刚我们说过了二叉树有两种存储方式顺序存储,和链式存储,顺序存储就是用数组来存,这个定义没啥可说的,我们来看看链式存储的二叉树节点的定义方式。
C++代码如下:
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};
二叉树分为满二叉树(节点只为0或2)、完全二叉树、二叉搜索树(有序,左节点小于中节点,中节点小于右节点)、平衡二叉搜索树(有序且若不是空树则左右子树高度差不超过1)。
二叉树可以链式存储,也可以顺序存储。
链式存储方式就用指针, 顺序存储的方式就是用数组。
二叉树的遍历方式
二叉树主要有两种遍历方式:
- 深度优先遍历:先往深走,遇到叶子节点再往回走。
- 广度优先遍历:一层一层的去遍历。
这两种遍历是图论中最基本的两种遍历方式,后面在介绍图论的时候 还会介绍到。
那么从深度优先遍历和广度优先遍历进一步拓展,才有如下遍历方式:
- 深度优先遍历
- 前序遍历(递归法,迭代法)
- 中序遍历(递归法,迭代法)
- 后序遍历(递归法,迭代法)
- 广度优先遍历
- 层次遍历(迭代法)
二叉树的递归遍历
递归实现三要素:
-
确定递归函数的参数和返回值: 确定哪些参数是递归的过程中需要处理的,那么就在递归函数里加上这个参数, 并且还要明确每次递归的返回值是什么进而确定递归函数的返回类型。
-
确定终止条件: 写完了递归算法, 运行的时候,经常会遇到栈溢出的错误,就是没写终止条件或者终止条件写的不对,操作系统也是用一个栈的结构来保存每一层递归的信息,如果递归没有终止,操作系统的内存栈必然就会溢出。
-
确定单层递归的逻辑: 确定每一层递归需要处理的信息。在这里也就会重复调用自己来实现递归的过程。
例如前序遍历:
前序遍历:
class Solution {
public:
//确定二叉树参数和返回值
void traversal(TreeNode* cur, vector<int>& vec) {
if (cur == NULL) return;//判断终止条件
//遍历顺序:
vec.push_back(cur->val); // 中
traversal(cur->left, vec); // 左
traversal(cur->right, vec); // 右
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
traversal(root, result);
return result;
}
};
中序和后序的顺序只需将遍历顺序进行一下调换。
二叉树的迭代遍历
前序遍历(迭代法)
我们先看一下前序遍历。
前序遍历是中左右,每次先处理的是中间节点,那么先将根节点放入栈中,然后将右孩子加入栈,再加入左孩子。
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
stack<TreeNode*> st;
vector<int> result;
if (root == NULL) 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;
}
};
后序遍历:
可将前序遍历改一下,在遍历时按中右左的顺序在最后的时候翻转顺序
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
stack<TreeNode*>st;
vector<int>result;
if( root ==NULL) 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);
}
reverse(result.begin(),result.end());
return result;
}
};
中序遍历:
定义一个栈用来存放遍历过的数据,数组来存放结果,向左遍历,当左节点为空时,弹出栈顶元素,然后寻找右节点,当栈里为空,且给出的数组也为空则结束。
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int>result;
stack<TreeNode*>st;
TreeNode* cur=root;
while( !st.empty() ||cur !=NULL){
if(cur != NULL) {
st.push(root);
cur=cur->left;
}else{
cur=st.top();
st.pop();
result.push_back(cur->val);
cur=cur->right;
}
}
return result;
}
};