赞
踩
二叉树有先序遍历(根左右)、中序遍历(左根右)和后序遍历(左右根)和层次遍历几种遍历方式。这几种遍历方式是其他二叉树解题的基础,所以必须先掌握。
因为二叉树本身就是用递归定义的,因此采用递归的方法实现三种遍历代码简洁且容易理解,但其开销比较大。
二叉树的先序、中序和后序遍历:
先序遍历:任何子树的处理顺序都是:先根结点,再左子树,然后右子树 (根左右)
中序遍历:任何子树的处理顺序都是:先左子树,再根节点,然后右子树 (左根右)
后序遍历:任何子树的处理顺序都是:先左子树,再右子树,然后根结点 (左右根)
二叉树的节点定义如下:
- struct Node{
- int val;
- Node* left;
- Node* right;
- Node() {
- val = 0;
- left = nullptr;
- right = nullptr;
- }
- Node(int v){
- val = v;
- left = nullptr;
- right = nullptr;
- }
- };
- void preOrderTraversalRecursion(Node* x){
- if(x == nullptr) return;
- cout<<x->val<<endl;
- preOrderTraversalRecursion(x->left);
- preOrderTraversalRecursion(x->right);
- }
- void inOrderTraversalRecursion(Node* x){
- if(x == nullptr) return;
- inOrderTraversalRecursion(x->left);
- cout<<x->val<<endl;
- inOrderTraversalRecursion(x->right);
- }
- void postOrderTraversalRecursion(Node* x){
- if(x == nullptr) return;
- postOrderTraversalRecursion(x->left);
- postOrderTraversalRecursion(x->right);
- cout<<x->val<<endl;
- }
二叉树的递归遍历实际上是对二叉树的递归序(二叉树每个节点都会遍历三次),在第i次到达的时候打印根节点。(第1次到达就是先序遍历,第2次到达就是中序遍历,第3次到达就是后序遍历)
非递归遍历二叉树就是用自己实现的栈替代系统栈。注:任何递归函数都可以改成非递归。
先序遍历:
注意因为栈是先进后出的,所以是先压右子树再压左子树,这样就能保证出栈是左边先出右边后出。
- void preOrderTraversalIteration(Node* x){//先序遍历二叉树迭代法:
- if(x == nullptr ) return;
- cout<<"preOrderTraversalIteration"<<endl;
- stack<Node*> s;//用栈模拟递归
- s.push(x);//先把头节点压栈
- while (!s.empty()){ //栈非空就继续循环
- Node* cur = s.top(); //栈中弹出节点
- s.pop();
- cout<<cur->val<<endl;
- //cur有右节点就压入栈,有左节点就压入栈(因为栈是后进先出,所以按照根左右的遍历,应该先压右子树节点)
- if(cur->right){
- s.push(cur->right);
- }
- if(cur->left){
- s.push(cur->left);
- }
- }
- }
后序遍历:
上面已经实现了非递归先序遍历(根左右),那么只要稍微加工就可以得到非递归后序遍历。将非递归先序遍历的压栈顺序改一下,改成先压左子树再压右子树,那么最终的遍历顺序是<根右左>,然后在每次弹出打印时候改成不打印,进入另外一个temp栈,当整个操作完成后。从temp栈中弹出元素,那么<根右左>就变成了<左右根>,这就是后序遍历。
- void postOrderTraversalIteration(Node* x){
- if(x == nullptr) return;
- cout<<"postOrderTraversalIteration"<<endl;
- stack<Node*> s,tmp;//s是类似于辅助先序遍历的栈;tmp是保存遍历元素,最后输出就是后序遍历
- s.push(x);
- while (!s.empty()){
- Node* cur = s.top();
- s.pop();
- tmp.push(cur);
- if(cur->left){
- s.push(cur->left);
- }
- if(cur->right){
- s.push(cur->right);
- }
- }
- while (!tmp.empty()){
- Node* t = tmp.top();
- cout<<t->val<<endl;
- tmp.pop();
- }
- }
中序遍历:
- void inOrderTraversalIteration(Node* x){//二叉树中序遍历迭代法实现
- if(x == nullptr) return;
- cout<<"inOrderTraversalIteration"<<endl;
- stack<Node* > s;
- Node* cur = x;
- Node* tmp = nullptr;
- //栈不为空或者cur不为空,那么循环继续
- while (!s.empty() || cur){
- if(cur){ //以cur为头节点的树,整条左边进栈(包括cur这个根节点),直到遇到cur的左边为nullptr结束
- s.push(cur);
- cur = cur->left;
- }else {
- cur = s.top(); //从栈中弹出cur,经过上面if判断cur的左边是nullptr,访问cur后,让cur=cur->right;
- s.pop();
- cout<<cur->val<<endl;
- cur = cur->right;
- }
- }
- }
层次遍历二叉树需要用队列实现,就是宽度优先遍历,每层入队然后出队让左右孩子分别入队。
- vector<vector<int> > levelOrder(Node* root) {
- // write code here
- vector<vector<int> > v;
- if(root == nullptr) return v;
- Node* cur = root;
- queue<Node*> q;
- q.push(cur);
- while(!q.empty()){
- int size = q.size(); //先获取当前层的节点数
- vector<int> ans;
- for(int i = 0;i<size;++i){ //将当前层的节点遍历,同时将它的孩子节点加入队列
- cur = q.front();
- q.pop();
- ans.push_back(cur->val);
- if(cur->left){
- q.push(cur->left);
- }
- if(cur->right){
- q.push(cur->right);
- }
- }
- v.push_back(ans);
- //二叉树层次遍历正序收集节点;如果要倒序收集,那么每次在首部位置插入即可
- }
- return v;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。