目录
1.概述
二叉树:一个节点只有一个入度和至多两个出度的图。
遍历方式:树/图的遍历分为深度优先搜索(DFS和广度优先遍历(BFS)。一般来说深度优先搜索的特点决定了深度优先搜索依赖于栈的实现,而广度优先搜索的实现依赖于队列的实现。
2.二叉树的深度优先遍历
关键词:递归、栈
2.1前序遍历
顺序:先根节点、然后左子树、右子树
//递归版本
void traversal(TreeNode* root, vector<int>& res) {
if(root == nullptr)
return;
res.emplace_back(root->val);
traversal(root->left, res);
traversal(root->right, res);
}
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
traversal(root, res);
return res;
}
//非递归实现使用栈来保存遍历过的节点,不断入栈出栈直到栈空为止。 非递归实现与递归实现不同,遍历根节点后要先遍历右子树再遍历左子树(因栈的后进先出特性)
vector<int> preorderTraversal(TreeNode* root) {
vector<int> res;
if(root == nullptr)
return res;
stack<TreeNode*> st;
st.push(root);
while (!st.empty()) {
auto node = st.top();
res.push_back(node->val);
st.pop();
if(node->right != nullptr)
st.push(node->right);
if(node->left != nullptr)
st.push(node->left);
}
return res;
}
2.2中序遍历
顺序:左子树--根节点--右子树
#递归版本
void travesal(TreeNode* root, vector<int>& res){
if(!root)
return;
travesal(root->left,res);
res.push_back(root->val);
travesal(root->right, res);
}
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
travesal(root, res);
return res
}
#非递归实现,使用栈保存遍历过的节点,先找到最左节点然后依次出栈遍历节点对应的右子节点:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> res;
stack<TreeNode*> st;
while (root != nullptr || !st.empty()) {
while (root != nullptr) {
st.push(root);
root = root->left;
}
root = st.top();
st.pop();
res.push_back(root->val);
root = root->right;
}
return res;
}
2.3后序遍历
顺序:左子树--右子树--根节点
#递归版本
void traversal(TreeNode* root, vector<int>&res){
if(root == nullptr)
return;
traversal(root->left, res);
traversal(root->right, res);
res.push_back(root->val);
}
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
traversal(root, res);
return res;
}
#非递归实现,使用栈保存遍历过的节点,先找到最右节点然后依次出栈遍历节点对应的左子节点,最后需要反转遍历结果:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> res;
if(root == nullptr)
return res;
stack<TreeNode*> st;
TreeNode* prev = nullptr;
while (!st.empty() || root != nullptr) {
while(root != nullptr) {
res.push_back(root->val);
st.push(root);
root = root->right;
}
root = st.top()->left;
st.pop();
}
reverse(res.begin(), res.end());
return res;
}
3.二叉树的广度优先遍历
二叉树的广度优先搜索类似于层序遍历:遍历跟节点,遍历左子节点和右子节点,然后遍历左子节点和它的左右子节点以及右子节点和它的左右子节点。广度优先搜索严格按照遍历的先后循序遍历节点,符合队列先进先出(FIFO)的特点,适合使用队列来实现。
3.1二叉树的广度优先遍历
void bfs(TreeNode* root) {
if(!root)
return;
queue<TreeNode*> que;
que.push(root);
while(!que.empty()){
auto node = que.front();
que.pop();
cout << node->val << endl;
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}
return res;
}
3.2二叉树的层序遍历
不同点:需要对每层做一个标记
#跟节点入队后加入一个空节点做哨兵,出队的时候发现是空节点就知道一层遍历结束了,保存本层结果继续加入空节点做哨兵。
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root)
return res;
queue<TreeNode*> que;
que.push(root);
que.push(nullptr);
vector<int> temp;
while(!que.empty()){
auto node = que.front();
que.pop();
if(node){
temp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}else if(!temp.empty()){
res.push_back(temp);
temp.clear();
que.push(nullptr);
}
}
return res;
}
3.3二叉树自底向上层序遍历
路子:3.2自顶向下遍历后,逆置一下数组
vector<vector<int>> levelOrderBottom(TreeNode* root) {
vector<vector<int>> res;
if(root == nullptr)
return res;
queue<TreeNode*> que;
que.push(root);
que.push(nullptr);
vector<int> temp;
while(!que.empty()){
auto node = que.front();
que.pop();
if(node){
temp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}else if(!temp.empty()){
res.push_back(temp);
temp.clear();
que.push(nullptr);
}
}
reverse(res.begin(), res.end());
return res;
}
3.4二叉树的锯齿形层序遍历
路子:只需要在层序遍历基础上加上一个标志,需要逆序时逆置一下该层遍历结果就可以了。
vector<vector<int>> zigzagLevelOrder(TreeNode* root) {
vector<vector<int>> res;
if(!root)
return res;
queue<TreeNode*> que;
que.push(root);
que.push(nullptr);
vector<int> temp;
bool change = false;
while(!que.empty()){
auto node = que.front();
que.pop();
if(node){
temp.push_back(node->val);
if(node->left) que.push(node->left);
if(node->right) que.push(node->right);
}else if(!temp.empty()){
if(change)
reverse(temp.begin(), temp.end());
res.push_back(temp);
temp.clear();
que.push(nullptr);
change = !change;
}
}
return res;
}