无论是何种遍历都抓住遍历的特征
先、中、后,三种遍历方式,都是深度优先搜索,差别仅在于访问根节点的顺序。
深度优先搜索的特点:
1、使用栈。
2、存在可访问节点时,向下延伸。
3、无可访问节点时,回退至上级可访问节点。
二叉树先、中、后遍历中DFS思想的体现:
1、使用栈。
2、左子树存在,向左子树迭代。
3、左子树不存在,移向右子树,回2。
1、先序
特征:一直向左,对访问的节点进行入栈,直到左边没有,回退,向右一步,再回到一直向左。
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
stack<TreeNode *> pStack;
while (root || !pStack.empty()) {
while (root) {
result.push_back(root->val);
pStack.push(root);
root = root->left;
}
if (!pStack.empty()) { // 这里栈不会为空,所以可以去掉
root = pStack.top();
pStack.pop();
root = root->right;
}
}
return result;
}
private:
vector<int> result;
};
2、中序
特征:一直向左,不访问,入栈,回退访问,向右,再一直向左
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode *root) {
stack<TreeNode *> pStack;
while (root || !pStack.empty()) {
while (root) {
pStack.push(root);
root = root->left;
}
if (!pStack.empty()) {
root = pStack.top();
pStack.pop();
result.push_back(root->val);
root = root->right;
}
}
return result;
}
private:
vector<int> result;
};
3、后序
特征:叶节点直接访问;非叶节点,子树必须已访问,上一个被访问的必然是子节点
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode *root) {
if (root == NULL) {
return result;
}
stack<TreeNode *> s;
TreeNode *pre = NULL;
s.push(root);
while (!s.empty()) {
root = s.top();
if (root->left == NULL && root->right == NULL) {
result.push_back(root->val);
pre = root;
s.pop();
} else if (root->right != NULL && pre == root->right) {
result.push_back(root->val);
pre = root;
s.pop();
} else if (root->left != NULL && pre == root->left) {
result.push_back(root->val);
pre = root;
s.pop();
} else {
if (root->right && pre != root->right) {
s.push(root->right);
}
if (root->left && pre != root->left) {
s.push(root->left);
}
}
}
return result;
}
private:
vector<int> result;
};
考虑到节点如果有左子树,则必然先背访问,那么需要考虑的是右子树如果存在,有没有被访问呢?
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode *root) {
if (root == NULL) {
return result;
}
stack<TreeNode *> s;
TreeNode *pre = NULL;
TreeNode *cur = root;
while (cur || !s.empty()) {
while (cur) {
s.push(cur);
cur = cur->left;
} // 一直向左子树方向探索
cur = s.top();
if (cur->right == NULL || pre == cur->right) {
result.push_back(cur->val);
pre = cur;
s.pop();
cur = NULL;
} else {
cur = cur->right;
}
}
return result;
}
private:
vector<int> result;
};
优化
迭代条件是
1、节点不空,此时栈可能为空,进入迭代会将节点入栈;
2、或者栈不空
因此在任何遍历出栈的时候,都可以保证栈是不空的,在出栈前也就没有必要判断栈是否为空。
优化的先序
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode *root) {
stack<TreeNode *> s;
TreeNode *cur = root;
while (cur || !s.empty()) {
while (cur) {
re.push_back(cur->val);
s.push(cur);
cur = cur->left;
}
cur = s.top();
cur = cur->right;
s.pop();
}
return re;
}
private:
vector<int> re;
};
优化的中序
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode *root) {
stack<TreeNode *> s;
while (root || !s.empty()) {
while (root) {
s.push(root);
root = root->left;
}
root = s.top();
s.pop();
re.push_back(root->val);
root = root->right;
}
return re;
}
private:
vector<int> re;
};
优化的后序
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode *root) {
stack<TreeNode *> s;
TreeNode *pre = NULL, *cur = root;
while (cur || !s.empty()) {
while (cur) {
s.push(cur);
cur = cur->left;
}
cur = s.top();
if (cur->right && pre != cur->right) {
cur = cur->right;
} else {
re.push_back(cur->val);
pre = cur;
s.pop();
cur = NULL;
}
}
return re;
}
private:
vector<int> re;
};