栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

递归和非递归方式实现二叉树的先序、中序和后序遍历

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

递归和非递归方式实现二叉树的先序、中序和后序遍历

1、二叉树的结构描述
class TreeNode {
public:
    V val;
    TreeNode *lchild;
    TreeNode *rchild;
};
2、二叉树的先序、中序、后序遍历概念
  • 先序:任何子树的处理顺序都是,先根节点、再左子树、然后右子树

  • 中序:任何子树的处理顺序都是,先左子树、再根节点、然后右子树

  • 后序:任何子树的处理顺序都是,先左子树、再右子树、然后根节点

3、递归方式实现二叉树的先序、中序、后序遍历
void f(TreeNode *root) {
    if (root == nullptr) return ;

    //1
    f(root->lchild);
    //2
    f(root->rchild);
    //3
}

如果打印行为放在 1 处,则是先序遍历;如果打印行为放在 2 处,则是中序遍历;如果打印行为放在 3 处,则是后序遍历。

为什么三种遍历都能由同一份代码该出来呢?因为它们都有一个最本质的东西,那就是 递归序。

3.1 理解递归序

对于如下的二叉树:

它的递归访问顺序:

递归序保证每个节点都会到达三次,通过递归序可以加工出先序、中序、后序遍历的顺序。

  • 第一次到达节点的时候打印,二三次到达的时候不做任何事,就是先序;(a,b,d,e,c,f,g)

  • 第二次到达节点的时候打印,一三次到达的时候不做任何事,就是中序;(d,b,e,a,f,c,g)

  • 第三次到达节点的时候打印,一二次到达的时候不做任何事,就是后序。(d,e,b,f,g,c,a)

3.2 代码实现 C++ 版

#include 
using namespace std;

class TreeNode {
public:
    int val;
    TreeNode *lchild;
    TreeNode *rchild;

    TreeNode(int v) : val(v) {  }
};

//先序遍历
void pre(TreeNode *root) {
    if (root == nullptr) return ;

    cout << root->val << " ";
    pre(root->lchild);
    pre(root->rchild);
}

//中序遍历
void in(TreeNode *root) {
    if (root == nullptr) return ;

    in(root->lchild);
    cout << root->val << " ";
    in(root->rchild);
}

//后序遍历
void post(TreeNode *root) {
    if (root == nullptr) return ;

    post(root->lchild);
    post(root->rchild);
    cout << root->val << " ";
}


int main() {
    TreeNode *root = new TreeNode(1);
    root->lchild = new TreeNode(2);
    root->rchild = new TreeNode(3);
    root->lchild->lchild = new TreeNode(4);
    root->lchild->rchild = new TreeNode(5);
    root->rchild->lchild = new TreeNode(6);
    root->rchild->rchild = new TreeNode(7);

    cout << "pre-order:";
    pre(root);
    cout << endl;
    cout << "============" << endl;


    cout << "in-order:";
    in(root);
    cout << endl;
    cout << "============" << endl;

    
    cout << "post-order:";
    post(root);
    cout << endl;
    cout << "============" << endl;

    return 0;
}
Java 版
public class RecursiveTraversalBT {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int v) {
			value = v;
		}
	}

	public static void f(Node head) {
		if (head == null) {
			return;
		}
		// 1
		f(head.left);
		// 2
		f(head.right);
		// 3
	}

	// 先序打印所有节点
	public static void pre(Node head) {
		if (head == null) {
			return;
		}
		System.out.println(head.value);
		pre(head.left);
		pre(head.right);
	}

	public static void in(Node head) {
		if (head == null) {
			return;
		}
		in(head.left);
		System.out.println(head.value);
		in(head.right);
	}

	public static void pos(Node head) {
		if (head == null) {
			return;
		}
		pos(head.left);
		pos(head.right);
		System.out.println(head.value);
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right.left = new Node(6);
		head.right.right = new Node(7);

		pre(head);
		System.out.println("========");
		in(head);
		System.out.println("========");
		pos(head);
		System.out.println("========");

	}
}
4、非递归方式实现二叉树的先序、中序、后序遍历

1)任何递归函数都可以改成非递归

2)自己设计压栈来实现

4.1 先序遍历流程

1)根节点入栈
2)栈顶元素出栈,记为 cur
3)如果cur 有右孩子,则右孩子入栈;如果有左孩子,则左孩子入栈;即先右后左
4)重复步骤 2) ~ 4)

//先序遍历:根 左 右
void pre(TreeNode *root) {
    cout << "pre-order:";
    if (root == nullptr) return ;

    stack sta;
    sta.push(root); //根节点入栈
    while (!sta.empty()) { 
        root = sta.top();  // 复用root 
        sta.pop(); //弹出栈顶
        cout << root->val << " ";
        if (root->rchild != nullptr) { //右孩子入栈
            sta.push(root->rchild);
        }

        if (root->lchild != nullptr) { //左孩子入栈
            sta.push(root->lchild);
        }
    }

    cout << endl;
}
4.2 后序遍历流程

根据先序遍历的流程,可以加工出 “根-右-左” 的遍历顺序,无非就是先左孩子入栈,然后右孩子入栈。要是再准备一个栈,弹出的节点不立即打印,而是放入该栈中,最后所有节点都放入该栈后,再弹出节点进行打印,那么得到的顺序就是 **“左-右-根”**的遍历顺序,这就是后序遍历的顺序。

//使用两个栈实现后序遍历:左、右、根
void post(TreeNode *cur) {
    cout << "post-order:";
    if (cur == nullptr) return ;
	//准备两个栈
    stack sta1;
    stack sta2;
    sta1.push(cur);
    while (!sta1.empty()) { //弹出栈的顺序是:根、右、左
        cur = sta1.top();
        sta1.pop();
        sta2.push(cur); //弹出的节点放到另一个栈中
        if (cur->lchild != nullptr) { //左节点入栈
            sta1.push(cur->lchild);
        }

        if (cur->rchild != nullptr) { //右节点入栈
            sta1.push(cur->rchild);
        }
    }

    while (!sta2.empty()) { //弹出栈中的顺序是:左、右、根,就是后序遍历顺序
        cout << sta2.top()->val << " ";
        sta2.pop();
    }

    cout << endl;
}
4.3 中序遍历流程

1)当前节点 cur,cur 为根的树,整条左边界入栈,直到遇到空节点。即先将根节点开始的所有左孩子入栈,然后转 2)
2)栈中弹出节点打印,cur 变成节点的右孩子,转 1)
3)栈为空停止

//中序遍历
void in(TreeNode *cur) {
    cout << "in-order:";
    if (cur == nullptr) return ;

    stack sta;
    while (!sta.empty() || cur != nullptr) {
        if (cur != nullptr) {
            sta.push(cur);
            cur = cur->lchild;
        } else {
            cur = sta.top();
            sta.pop();
            cout << cur->val << " ";
            cur = cur->rchild;
        }
    }
    cout << endl;
}

这个原理就是每棵树都能由左树进行分解,当前节点出栈,一定是左子树被处理完毕,才会到当前节点,所以最终得到的顺序是 “左-根-右”,即中序遍历顺序。

4.4 完整代码实现 C++ 版

#include 
#include 
using namespace std;

class TreeNode {
public:
    int val;
    TreeNode *lchild;
    TreeNode *rchild;

    TreeNode(int v) : val(v) {  }
};

//先序遍历:根 左 右
void pre(TreeNode *root) {
    cout << "pre-order:";
    if (root == nullptr) return ;

    stack sta;
    sta.push(root); //根节点入栈
    while (!sta.empty()) { 
        root = sta.top();  // 复用root 
        sta.pop(); //弹出栈顶
        cout << root->val << " ";
        if (root->rchild != nullptr) { //右孩子入栈
            sta.push(root->rchild);
        }

        if (root->lchild != nullptr) { //左孩子入栈
            sta.push(root->lchild);
        }
    }

    cout << endl;
}

//中序遍历
void in(TreeNode *cur) {
    cout << "in-order:";
    if (cur == nullptr) return ;

    stack sta;
    while (!sta.empty() || cur != nullptr) {
        if (cur != nullptr) {
            sta.push(cur);
            cur = cur->lchild;
        } else {
            cur = sta.top();
            sta.pop();
            cout << cur->val << " ";
            cur = cur->rchild;
        }
    }
    cout << endl;
}


//使用两个栈实现后序遍历:左、右、根
void post(TreeNode *cur) {
    cout << "post-order:";
    if (cur == nullptr) return ;

    stack sta1;
    stack sta2;
    sta1.push(cur);
    while (!sta1.empty()) { //弹出栈的顺序是:根、右、左
        cur = sta1.top();
        sta1.pop();
        sta2.push(cur); //弹出的节点放到另一个栈中
        if (cur->lchild != nullptr) { //左节点入栈
            sta1.push(cur->lchild);
        }

        if (cur->rchild != nullptr) { //右节点入栈
            sta1.push(cur->rchild);
        }
    }

    while (!sta2.empty()) { //弹出栈中的顺序是:左、右、根,就是后序遍历顺序
        cout << sta2.top()->val << " ";
        sta2.pop();
    }

    cout << endl;
}

//使用一个栈实现后序遍历
void post2(TreeNode *root) {
    cout << "post-order2:";
    if (root == nullptr) return ;

    stack sta;
    sta.push(root);
    TreeNode *cur = nullptr;
    while (!sta.empty()) {
        cur = sta.top();
        if (cur->lchild != nullptr && root != cur->lchild && root != cur->rchild) {
            sta.push(cur->lchild);
        } else if (cur->rchild != nullptr && root != cur->rchild) {
            sta.push(cur->rchild);
        } else {
            cout << sta.top()->val << " ";
            sta.pop();
            root = cur;
        }
    }
    cout << endl;
}

int main() {
    TreeNode *root = new TreeNode(1);
    root->lchild = new TreeNode(2);
    root->rchild = new TreeNode(3);
    root->lchild->lchild = new TreeNode(4);
    root->lchild->rchild = new TreeNode(5);
    root->rchild->lchild = new TreeNode(6);
    root->rchild->rchild = new TreeNode(7);

    pre(root);
    cout << "============" << endl;

    in(root);
    cout << "============" << endl;


    post(root);
    cout << "============" << endl;

    post2(root);
    cout << "============" << endl;

    return 0;
}
Java 版
import java.util.Stack;

public class UnRecursiveTraversalBT {

	public static class Node {
		public int value;
		public Node left;
		public Node right;

		public Node(int v) {
			value = v;
		}
	}

	public static void pre(Node head) {
		System.out.print("pre-order: ");
		if (head != null) {
			Stack stack = new Stack();
			stack.add(head);
			while (!stack.isEmpty()) {
				head = stack.pop();
				System.out.print(head.value + " ");
				if (head.right != null) {
					stack.push(head.right);
				}
				if (head.left != null) {
					stack.push(head.left);
				}
			}
		}
		System.out.println();
	}

	public static void in(Node cur) {
		System.out.print("in-order: ");
		if (cur != null) {
			Stack stack = new Stack();
			while (!stack.isEmpty() || cur != null) {
				if (cur != null) {
					stack.push(cur);
					cur = cur.left;
				} else {
					cur = stack.pop();
					System.out.print(cur.value + " ");
					cur = cur.right;
				}
			}
		}
		System.out.println();
	}

	public static void pos1(Node head) {
		System.out.print("pos-order: ");
		if (head != null) {
			Stack s1 = new Stack();
			Stack s2 = new Stack();
			s1.push(head);
			while (!s1.isEmpty()) {
				head = s1.pop(); // 头 右 左
				s2.push(head);
				if (head.left != null) {
					s1.push(head.left);
				}
				if (head.right != null) {
					s1.push(head.right);
				}
			}
			// 左 右 头
			while (!s2.isEmpty()) {
				System.out.print(s2.pop().value + " ");
			}
		}
		System.out.println();
	}

	public static void pos2(Node h) {
		System.out.print("pos-order: ");
		if (h != null) {
			Stack stack = new Stack();
			stack.push(h);
			Node c = null;
			while (!stack.isEmpty()) {
				c = stack.peek();
				if (c.left != null && h != c.left && h != c.right) {
					stack.push(c.left);
				} else if (c.right != null && h != c.right) {
					stack.push(c.right);
				} else {
					System.out.print(stack.pop().value + " ");
					h = c;
				}
			}
		}
		System.out.println();
	}

	public static void main(String[] args) {
		Node head = new Node(1);
		head.left = new Node(2);
		head.right = new Node(3);
		head.left.left = new Node(4);
		head.left.right = new Node(5);
		head.right.left = new Node(6);
		head.right.right = new Node(7);

		pre(head);
		System.out.println("========");
		in(head);
		System.out.println("========");
		pos1(head);
		System.out.println("========");
		pos2(head);
		System.out.println("========");
	}
}
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/983800.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号