节点定义如下
1 // Definition for a binary tree node. 2 struct TreeNode { 3 int val; 4 TreeNode *left; 5 TreeNode *right; 6 TreeNode(int x) : val(x), left(NULL), right(NULL) {} 7 }
前序遍历:
若二叉树为空,则空操作返回,否则:
- 访问根节点
- 前序遍历根节点的左子树
- 前序遍历根节点的右子树
中序遍历:
若二叉树为空,则空操作返回,否则:
- 中序遍历根节点的左子树
- 访问根节点
- 中序遍历根节点的右子树
后序遍历:
若二叉树为空,则空操作返回,否则:
- 后序遍历根节点的左子树
- 后序遍历根节点的右子树
- 访问根节点
层序遍历:
其中后序遍历可以看作是和前序遍历是对称的,所以从根节点开始先遍历右子树,再遍历左子树,不过要把最后的遍历输出翻转过来。所以后序遍历的代码和前序遍历的代码基本一致,只是左右子树的访问顺序不同。
1. 递归方法
前序遍历:
1 void preorderTraversal(TreeNode* root, vector<int>& nums) { 2 if(!root) return; 3 nums.push_back(root->val); // 访问根节点 4 preorderTraversal(root->left); // 前序遍历左子树 5 preorderTraversal(root->right); // 前序遍历右子树 6 }
中序遍历:
1 void inorderTraversal(TreeNode* root, vector<int>& nums) { 2 if(!root) return; 3 inorderTraversal(root->left, nums); // 中序遍历左子树 4 nums.push_back(root->val); // 访问根节点 5 inorderTraversal(root->right, nums); // 中序遍历右子树 6 }
后序遍历:
1 void postorderTraversal(TreeNode* root, vector<int>& nums) { 2 if(!root) return; 3 postorderTraversal(root->left, nums); // 后序遍历左子树 4 postorderTraversal(root->right, nums); // 后序遍历右子树 5 nums.push_back(root->val); // 访问根节点 6 }
层序遍历:
1 vector<vector<int>> levelOrder(TreeNode* root) { 2 vector<vector<int> > res; 3 levelorder(root, 0, res); 4 return res; 5 } 6 void levelorder(TreeNode *root, int level, vector<vector<int> > &res) { 7 if (!root) 8 return; 9 if (res.size() == level) 10 res.push_back({}); 11 12 res[level].push_back(root->val); 13 14 if (root->left) 15 levelorder(root->left, level + 1, res); 16 if (root->right) 17 levelorder(root->right, level + 1, res); 18 }
2.迭代方法(使用栈)
前序遍历 1):
1 void preorderTraversal(TreeNode* root, vector<int>& nums) { 2 TreeNode* cur = root; 3 stack<TreeNode* > st; 4 5 while (cur || !st.empty()) { 6 if (cur) { 7 st.push(cur); 8 nums.push_back(cur->val); 9 cur = cur->left; 10 } else { 11 cur = st.top(); 12 st.pop(); 13 cur = cur->right; 14 } 15 } 16 }
前序遍历 2):
1 void preorderTraversal(TreeNode* root, vector<int>& nums) { 2 TreeNode* cur = root; 3 stack<TreeNode* > st; 4 5 while (cur || !st.empty()) { 6 if (!cur) { // 根节点为空,则需要返回上一级 7 cur = st.top(); // 访问右子树,而右子树已被保存在栈中 8 st.pop(); 9 } 10 nums.push_back(cur->val); // 访问根节点 11 if (cur->right) st.push(cur->right); // 保存待遍历节点 12 cur = cur->left; // 继续访问左子树 13 } 14 }
前序遍历 3):
void preorderTraversal(TreeNode* root, vector<int>& nums) { stack<TreeNode* > st; if (!root) return; st.push(root); while (!st.empty()) { TreeNode* cur = st.top(); st.pop(); nums.push_back(cur->val); if (cur->right) st.push(cur->right); if (cur->left) st.push(cur->left); } }
中序遍历:
1 void inorderTraversal(TreeNode* root, vector<int>& nums) { 2 TreeNode* cur = root; 3 stack<TreeNode* > st; 4 5 while (cur || !st.empty()) { 6 if (cur) { // 找到最左节点并保存根节点 7 st.push(cur); // 即访问左子树 8 cur = cur->left; 9 } else { 10 cur = st.top(); 11 st.pop(); 12 nums.push_back(cur->val); // 访问根节点 13 cur = cur->right; // 访问右子树 14 } 15 } 16 }
后序遍历 1) 遍历结果需要翻转:
1 void postorderTraversal(TreeNode* root, vector<int>& nums) { 2 stack<TreeNode* > st; 3 TreeNode* cur = root; 4 5 while (cur || !st.empty()) { 6 if (cur) { 7 nums.push_back(cur->val); 8 st.push(cur); 9 cur = cur->right; 10 } else { 11 cur = st.top(); 12 st.pop(); 13 cur = cur->left; 14 } 15 } 16 reverse(nums.begin(), nums.end()); 17 }
后序遍历 2) 遍历结果需要翻转:
1 void postorderTraversal(TreeNode* root, vector<int>& nums) { 2 stack<TreeNode* > st; 3 TreeNode* cur = root; 4 5 while (cur|| !st.empty()) { 6 if (!cur) { 7 cur= st.top(); 8 st.pop(); 9 } 10 nums.push_back(cur->val); 11 if (cur->left) st.push(cur->left); 12 cur= cur->right; 13 } 14 reverse(nums.begin(), nums.end()); 15 }
后序遍历 3) 遍历结果无需翻转:
1 void postorderTraversal(TreeNode* root, vector<int>& nums) { 2 stack<TreeNode* > st; 3 TreeNode* cur = root, *pre = nullptr; 4 5 while (cur || !st.empty()) { 6 while (cur) { // 找到最左节点,并存储沿路节点 7 st.push(cur); 8 cur = cur->left; 9 } 10 cur = st.top(); // 11 if (!cur->right || cur->right == pre) { // 右子树已遍历或为空,则访问根节点 12 nums.push_back(cur->val); // 并将根节点从栈中推出 13 pre = cur; 14 st.pop(); 15 cur = nullptr; // cur置为null,从而再从栈中取节点,即返回父节点 16 } else { 17 cur = cur->right; // 当前节点的右子树尚未遍历,则该节点保留在栈中 18 } // 遍历右子树 19 } 20 }
3.Morris遍历
Morris算法基于线段树,利用叶子结点的空指针建立索引,此索引按照中序遍历的顺序建立。
前序遍历:
1 void preorderTraversal(TreeNode* root, vector<int>& nums) { 2 TreeNode* cur = root, *pre = nullptr; 3 4 while (cur) { 5 if (cur->left) { // 左孩子不为空,则找中序遍历下的前驱结点 6 pre= cur->left; // 前驱结点为左子树的最右节点 7 while (pre->right && pre->right != cur) { // 找到最优节点,且该节点未建立线索 8 pre = pre->right; // cur的中序遍历下的前驱结点 9 } 10 11 if (pre->right == cur) { // cur与pre已建立线索,则去掉该线索 12 pre->right = nullptr; // 剪掉线索 13 cur= cur->right; // 左子树已遍历完毕,遍历右子树 14 } else { // cur与pre并未建立线索,则建立线索 15 nums.push_back(cur->val); 16 pre->right = cur; 17 cur= cur->left; // 遍历左子树,继续建立线索 18 } 19 } else { 20 nums.push_back(cur->val); 21 cur = cur->right; // 左子树为空,则返回父节点,且父节点已与此节点已建立线索,即parent = cur->right 22 } 23 } 24 }
中序遍历:
1 void inorderTraversal(TreeNode* root, vector<int>& nums) { 2 TreeNode* cur = root, *pre = nullptr; 3 4 while (cur) { 5 if (cur->left) { 6 pre = cur->left; 7 while (pre->right && pre->right != cur) { 8 pre = pre->right; 9 } 10 11 if (pre->right == cur) { 12 nums.push_back(cur->val); // 建立的线索是根据中序遍历 13 pre->right = nullptr; 14 cur = cur->right; 15 } else { 16 pre->right = cur; 17 cur = cur->left; 18 } 19 } else { 20 nums.push_back(cur->val); 21 cur = cur->right; 22 } 23 } 24 }
后序遍历:
1 void postorderTraversal(TreeNode* root, vector<int>& nums) { 2 TreeNode* cur = root, *pre = nullptr; 3 4 while (cur) { 5 if (cur->right) { 6 pre = cur->right; 7 while (pre->left && pre->left != cur) { 8 pre = pre->left; 9 } 10 11 if (pre->left == cur) { 12 pre->left = nullptr; 13 cur = cur->left; 14 } else { 15 nums.push_back(cur->val); 16 pre->left = cur; 17 cur = cur->right; 18 } 19 20 } else { 21 nums.push_back(cur->val); 22 cur = cur->left; 23 } 24 } 25 reverse(nums.begin(), nums.end()); 26 }
4.分治
前序遍历:
1 vector<int> preorderTraversal(TreeNode* root) { 2 vector<int> res; 3 if (!root) 4 return res; 5 6 vector<int> leftSubTree = preorderTraversal(root->left); 7 vector<int> rightSubTree = preorderTraversal(root->right); 8 9 res.push_back(root->val); 10 res.insert(res.end(), leftSubTree.begin(), leftSubTree.end()); 11 res.insert(res.end(), rightSubTree.begin(), rightSubTree.end()); 12 13 return res; 14 }