二叉树的遍历
二叉树的结构:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
建议使用下图这个例子:
二叉树先中后序遍历(递归实现)
1 //递归实现中序遍历 2 void InorderTraversal(TreeNode* root) 3 { 4 if(root) //如果不是空树 5 { 6 InorderTraversal(root->Left); 7 printf("%d", root->val); //此处假设对BT节点的访问就是打印数据 8 InorderTraversal(root->right); 9 } 10 11 } 12 13 14 //递归实现先序遍历 15 void PreorderTraversal(TreeNode* root) 16 { 17 if(root) //如果不是空树 18 { 19 printf("%d", root->val); 20 PreorderTraversal(root->left); 21 PreorderTraversal(root->right); 22 } 23 } 24 25 26 //递归实现后序遍历 27 void PostorderTraversal(TreeNode* root) 28 { 29 if(root) //如果不是空树 30 { 31 PostorderTraversal(root->left); 32 PostorderTraversal(root->right); 33 printf("%d", root->val); 34 } 35 }
非递归实现中序遍历
1 class Solution { 2 public: 3 vector<int> inorderTraversal(TreeNode* root) { 4 vector<int> res; 5 if(root == NULL) { 6 return res; 7 } 8 9 stack<TreeNode*> S; 10 //根结点入栈 11 S.push(root); 12 13 TreeNode* t = root; 14 //将左孩子全部入栈 15 while(t->left) { 16 S.push(t->left); 17 t = t->left; 18 } 19 20 21 while(!S.empty()) { 22 //pop出一个结点,并且将其对应的值加入答案数组 23 t = S.top(); 24 S.pop(); 25 res.push_back(t->val); 26 27 //如果此结点有右孩子,则将右孩子入栈 28 if(t->right) { 29 S.push(t->right); 30 t = t->right; 31 32 //将左孩子全部入栈 33 while(t->left) { 34 S.push(t->left); 35 t = t->left; 36 } 37 } 38 } 39 40 return res; 41 42 } 43 };
非递归实现先序遍历
方式一:跟上述非递归中序遍历很像很像的代码。区别在于,中序是出栈的时候加入答案数组,先序是入栈的时候加入答案数组。
1 class Solution { 2 public: 3 vector<int> preorderTraversal(TreeNode* root) { 4 vector<int> res; 5 if(root == NULL) { 6 return res; 7 } 8 9 stack<TreeNode*> S; 10 //根结点入栈,并且将其对应的值加入答案数组 11 S.push(root); 12 res.push_back(root->val); 13 14 TreeNode* t = root; 15 //将左孩子全部入栈,并且将其对应的值加入答案数组 16 while(t->left) { 17 S.push(t->left); 18 res.push_back(t->left->val); 19 t = t->left; 20 } 21 22 23 while(!S.empty()) { 24 //pop出一个结点 25 t = S.top(); 26 S.pop(); 27 28 //如果此结点有右孩子,则将右孩子入栈,并且将其对应的值加入答案数组 29 if(t->right) { 30 S.push(t->right); 31 res.push_back(t->right->val); 32 t = t->right; 33 34 //将左孩子全部入栈,并且将其对应的值加入答案数组 35 while(t->left) { 36 S.push(t->left); 37 res.push_back(t->left->val); 38 t = t->left; 39 } 40 } 41 } 42 43 return res; 44 } 45 };
方法二:
1 class Solution { 2 public: 3 vector<int> preorderTraversal(TreeNode* root) { 4 vector<int> res; 5 if(root == NULL) { 6 return res; 7 } 8 9 stack<TreeNode*> S; 10 //根结点入栈 11 S.push(root); 12 TreeNode* t = root; 13 14 while(!S.empty()) { 15 //pop出一个结点,并且将其对应的值加入答案数组 16 t = S.top(); 17 res.push_back(t->val); 18 S.pop(); 19 20 //先把右孩子入栈,因为栈是后进先出 21 if(t->right) { 22 S.push(t->right); 23 } 24 25 // 再把左孩子入栈 26 if(t->left) { 27 S.push(t->left); 28 } 29 } 30 31 return res; 32 } 33 };
非递归实现后序遍历
因为后序非递归遍历二叉树的顺序是先访问左子树,再访问右子树,最后访问根节点。当用堆栈来存储节点,必须分清返回根节点时,是从左子树返回的,还从右子树返回的。
所以,使用辅助指针r,其指向最近访问过的节点。也可以在节点中增加一个标志域,记录是否已被访问。
1 //非递归实现后序遍历 2 void PostOrder3(BinTree BT) 3 { 4 BinTree T = BT, r = NULL; //r用来标记最近访问过的节点 5 stack<TNode *> s; 6 while (T || !s.empty()) 7 { 8 if (T) //T非空时,遇到一个节点就把这个节点入栈,走到最左边 9 { 10 s.push(T); 11 T = T->Left; 12 } 13 else 14 { 15 T = s.top(); 16 if (T->Right && T->Right != r)//右子树存在且未被访问 17 T = T->Right; 18 else 19 { 20 s.pop(); 21 printf("%d", T->Data); 22 r = T; //记录最近访问过的节点 23 T = NULL; //节点访问完后,重置T指针 24 } 25 }//else 26 }//while 27 28 }
补充一个bug级二叉树非递归遍历的写法
先序遍历:
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 11 struct Command { 12 string s; // go, print二者之一 13 TreeNode* node; 14 Command(string s, TreeNode* node): s(s), node(node) {} 15 }; 16 17 class Solution { 18 public: 19 vector<int> preorderTraversal(TreeNode* root) { 20 vector<int> res; 21 if(root == NULL) 22 return res; 23 24 stack<Command> stack; 25 stack.push( Command("go", root) ); 26 while( !stack.empty() ) { 27 28 Command command = stack.top(); 29 stack.pop(); 30 31 if( command.s == "print" ) 32 res.push_back( command.node -> val ); 33 else { 34 // 先序遍历是先输出,然后遍历左孩子,然后右孩子 35 // 所以先把右孩子入栈,再把左孩子入栈,再把输出入栈 36 assert( command.s == "go" ); 37 if( command.node -> right ) 38 stack.push( Command("go", command.node -> right) ); 39 if( command.node -> left ) 40 stack.push( Command("go", command.node -> left) ); 41 stack.push( Command("print", command.node) ); 42 } 43 } 44 45 return res; 46 } 47 };
中序遍历:
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 11 struct Command { 12 string s; // go, print二者之一 13 TreeNode* node; 14 Command(string s, TreeNode* node): s(s), node(node) {} 15 }; 16 17 class Solution { 18 public: 19 vector<int> inorderTraversal(TreeNode* root) { 20 vector<int> res; 21 if(root == NULL) 22 return res; 23 24 stack<Command> stack; 25 stack.push( Command("go", root) ); 26 while( !stack.empty() ) { 27 28 Command command = stack.top(); 29 stack.pop(); 30 31 if( command.s == "print" ) 32 res.push_back( command.node -> val ); 33 else { 34 // 中序遍历是先遍历左孩子,然后输出,最后右孩子 35 // 所以先把右孩子入栈,再把输出入栈,再把左孩子入栈 36 assert( command.s == "go" ); 37 if( command.node -> right ) 38 stack.push( Command("go", command.node -> right) ); 39 stack.push( Command("print", command.node) ); 40 if( command.node -> left ) 41 stack.push( Command("go", command.node -> left) ); 42 } 43 } 44 return res; 45 } 46 };
后序遍历:
1 /** 2 * Definition for a binary tree node. 3 * struct TreeNode { 4 * int val; 5 * TreeNode *left; 6 * TreeNode *right; 7 * TreeNode(int x) : val(x), left(NULL), right(NULL) {} 8 * }; 9 */ 10 11 struct Command { 12 string s; // go, print二者之一 13 TreeNode* node; 14 Command(string s, TreeNode* node): s(s), node(node) {} 15 }; 16 17 class Solution { 18 public: 19 vector<int> postorderTraversal(TreeNode* root) { 20 vector<int> res; 21 if(root == NULL) 22 return res; 23 24 stack<Command> stack; 25 stack.push( Command("go", root) ); 26 while( !stack.empty() ) { 27 28 Command command = stack.top(); 29 stack.pop(); 30 31 if( command.s == "print" ) 32 res.push_back( command.node -> val ); 33 else { 34 // 后序遍历是先遍历左孩子,然后右孩子,最后输出 35 // 所以先把输出入栈,再把右孩子入栈,再把左孩子入栈 36 assert( command.s == "go" ); 37 stack.push( Command("print", command.node) ); 38 if( command.node -> right ) 39 stack.push( Command("go", command.node -> right) ); 40 if( command.node -> left ) 41 stack.push( Command("go", command.node -> left) ); 42 } 43 } 44 return res; 45 } 46 };
二叉树的层序遍历:
(1) 从队列中取出一个元素;
(2) 访问该元素所指节点;
(3) 若该元素所指节点的左右孩子节点非空,则将其左右孩子节点顺序入队。
不断执行这三步操作,直到队列为空,再无元素可取,二叉树的层序遍历就完成了。
1 class Solution { 2 public: 3 vector<vector<int>> levelOrder(TreeNode* root) { 4 vector<vector<int>> res; 5 if(root == NULL) 6 return res; 7 8 queue<TreeNode *> Q; 9 Q.push(root); 10 11 while(!Q.empty()) { 12 vector<int> v; 13 int qsize = Q.size(); 14 15 for(int i = 0; i < qsize; ++i) { 16 TreeNode *t = Q.front(); 17 Q.pop(); 18 v.push_back(t->val); 19 20 if(t->left) 21 Q.push(t->left); 22 if(t->right) 23 Q.push(t->right); 24 } 25 26 res.push_back(v); 27 } 28 29 return res; 30 } 31 };