二叉树遍历

原创 2016年08月29日 09:57:38

二叉树是一棵树,其中每个节点不多于两个儿子。二叉树是有顺序的,左孩子的值小于根节点的值小于右孩子的值,次序 不能改变。正因为这个特点才可以方便快捷的查找。

class BinaryNode{
	Object element; //节点值
	BinaryNode left; //左孩子
	BinaryNode right; //右孩子
}

对于二叉树的定义如上。

二叉树遍历通常有三种包含有先序、中序、后序三种顺序。还有层次遍历,类似与广度优先。



此图的ABCD仅仅表示这个点,不表示大小先后。

先序遍历顺序是:根节点->左孩子->右孩子

中序遍历顺序是:左孩子->根节点->右孩子

后序遍历顺序是:左孩子->右孩子->根节点

还原二叉树只需 先序|后序+中序,便可以完成重构。对于真二叉树(所有节点度数是偶数,即0或2),先序+后序也可以,但是如果不是真二叉树不行,因为有可能左孩子右孩子是空,会出现歧义。

先序遍历递归方法:

private void PreTraverse(BinaryNode x,Visit visit){
	if(!x = null) //递归一定要有基准情况
		return;
	Visit(x); //根节点
	PreTraverse(x.left,visit);  //递归访问左孩子
	PreTraverse(x.right,visit);//递归访问右孩子
}

一般来说递归的量少还好,数据量大的话递归是很难实现的。遍历的迭代方法依靠栈实现。

先序遍历迭代方法:

private void goLeft(BinaryNode x,Visit visit,Stack<BinaryNode> s){
	while(x){
		Visit(x);
		S.push(x.right); //右孩子入栈
		x = x.left; //沿左链向下
	}
}
private void PreIterTraverse(BinaryNode x,Visit visit){
	goLeft(x,visit,s);  //访问左子树,右子树入栈
	if(s.empty()) break;//直到所有节点处理完
	x = s.pop(); //访问右子树
}

这种方法采用的思想很独特,先是从根节点出发,沿左链一次向下遍历左孩子,同时将右孩子入栈,当左孩子都访问完了,弹出栈顶元素即右孩子继续访问,和上述情况一样直到栈空为止。



就像这张图一样,黑色代表访问顺序,红色代表入栈。(图画的较丑,凑合看看)先访问ABC,将FD依次入栈,C之后没有左孩子,即执行弹出栈操作,先弹出D,E入栈,在弹出栈顶的E,因为没有孩子,所以访问E之后继续弹出F,右孩子G入栈,出栈,访问结束。

第二种先序迭代方法:

private void PreIterTraverse2(BinaryNode x,Visit visit){
	Stacks<BinaryNode> s;
	if(x) s.push(x);
	while(!s.empty()){ // 栈变空之前反复
		x = s.pop();//根节点入栈
		Visit(x);
	if(HasRChild(x))  s.push(x.right);//右孩子入栈
	if(HasLChild(x))  s.push(x.left); //左孩子入栈
	}
}

注意左右孩子的入栈顺序,因为采用的是栈,先进后出,所以右孩子先入栈。

中序遍历的递归方法就是先序遍历换一下访问顺序,就不赘述了。

中序遍历的迭代方法:

private void goLeft(BinaryNode x,Stacks){
	while(x)
		s.push(x);  //沿左分支深入依次入栈
		x = x.left;
}

private void InIterTraverse(BinaryNode x,Visit visit){
	Stack<BinaryNode> s;
	goLeft(x,s);
	if(s.empty()) break;//直到所有节点处理完
	x = s.pop();
	vitit(x);
	x = x.right;
}

有了上面的先序遍历思路,这个应该不难理解,先是goLeft沿左子树不断向下,左子树依次入栈,栈为空终止,不为空弹出栈顶元素,访问并将他的右子树在goleft.

以上图为例,先是ABC入栈,C没有左子树所以执行弹出栈顶元素,即为C弹出,访问C之后,没有右子树,所以弹出B,访问B且X=D,把D入栈,在弹出D,访问D,D的右子树E赋给X,X=E,E入栈,出栈,访问,当E结束之后没有子树了,就继续弹栈,现在栈只有A,即弹出A,访问A,将F入栈,后F没有左子树,将F弹出,访问F,并X=G,G没有子树,所以最后弹出访问,栈为空,结束遍历。以每一个节点为根的树都是按照左中右结构遍历的。

后序遍历同理不赘述了。

最后来说一下层次遍历,类似于广度优先,把这一层的同一深度的遍历完再遍历下一层的,依靠队列实现。

private void LevelTraverse(Visit visit){
	Queueq <BinaryNode> q;
	q.enqueue(this);  // 根节点入队
	while(!q.empty){
		BinaryNode x = q.dequeue(); //取出节点
		visit(x);
		if(HasLChild)	s.enqueue(x.left); //左孩子入队
		if(HasRChild(x))  s.enqueue(x.right); //右孩子入队
	}	
}


版权声明:本文为博主原创文章,未经博主允许不得转载。

相关文章推荐

二叉树遍历的通用非递归算法.pdf

  • 2007年12月12日 23:01
  • 403KB
  • 下载

二叉树遍历源代码

  • 2015年06月21日 13:05
  • 1KB
  • 下载

二叉树遍历的非递归实现 java版本

前序非递归遍历基本思想: 首先从访问节点,访问完后将节点入栈,如果节点有左孩子,则变量指向左孩子重复以上顺序当左孩子为空时,则出栈,获得栈顶元素的右孩子(所有入栈的元素及其左孩子元素都是被访问过...

二叉树遍历——前中后序

  • 2016年07月18日 09:38
  • 906KB
  • 下载

二叉树遍历序列还原

  • 2016年01月29日 23:47
  • 2KB
  • 下载

Morris二叉树遍历算法

Morris二叉树遍历算法

二叉树遍历前序非递归算法

  • 2015年06月09日 16:00
  • 2KB
  • 下载

二叉树遍历(数据结构课程使用)

  • 2011年07月09日 21:32
  • 176KB
  • 下载

二叉树遍历的递归和非递归实现

LeetCode上有三题是直接分别对应二叉树的非递归遍历实现:144/94/145 前序遍历:非递归和递归的方式差不多,主要是要注意左右子节点的入栈顺序和递归时恰好相反 /** * Defini...
  • xl2432
  • xl2432
  • 2016年08月09日 21:19
  • 204

二叉树遍历输出

  • 2012年04月03日 10:35
  • 2KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:二叉树遍历
举报原因:
原因补充:

(最多只允许输入30个字)