数据结构之二叉树创建及遍历

二叉树是一种比较特殊的树型数据结构,这一次来学习一下如何递归创建二叉树,以及如何递归遍历二叉树,同时最后以前序遍历为例子,非递归遍历二叉树。

要写出代码来,要心中有数,二叉树的结构相较于前面的链表、队列、栈要复杂些,所以,在没底的时候多画图来理解。

由上图可知二叉树的基本结构是一个数据域和两个指针域,^代表为null,因此我们创建二叉树的结点构造函数如下:

//内部类,保存左右指针和数据域
function TreeNode(data){
	this.data=data;
	this.left=null;
	this.right=null;
}

一、递归创建二叉树

 对于上面这一个二叉树来说,如果采用递归的方式来创建,你可以采用一个一个结点的方式来创建,不过比较麻烦,因为你还要花时间精力判断新结点需要插在哪里,如果你采用左子树小于右子树的方式去插入,那或许简单点,这种二叉树就是后面会讲到的“二叉排序树”,这一次我们创建的就是一颗普通的二叉树,所以我们根据二叉树的前序遍历结果来构造二叉树。

上图的二叉树前序遍历结果就是:AB#D##C##,#代表为空结点。

如果我们知道了一颗二叉树的前序遍历结果,如何构造这个二叉树呢?很简单,以递归的方式来说:根据字符串AB#D##C##,第一个创建A结点,创建后递归创建A结点的left结点B,再递归得到一个“#”即空结点,空姐点直接返回到B结点,所以B的left是null,再递归B的右结点,得到D,再依次递归D的左右子树,均是null,所以一层一层返回,知道返回到根节点,再访问根节点的右子树,由此一颗二叉树构造完成。

代码演示:

BinaryTree.prototype.createTree=function(node){
	let index=wm.get(this)[this.index]++; //index私有变量保持对字符串的索引
	const data=this.treeStr.split('')[index];
	if(index<this.treeStr.split('').length){
		if (data === '#') {
			node = null;
		} else {
			node = new TreeNode(data);
			node.left = this.createTree(node.left);
			node.right = this.createTree(node.right);
		}
	}
	return node;
}

 二、返回二叉树深度

 返回深度的算法同样采用递归实现,先递归树的左子树,当左子树为空时,判断是否有右子树,有就去递归,否则返回0,通过i变量去检测左子树,j检测右子树,返回max(i,j)+1

代码实现:

/**
 * 返回二叉树深度
 * */
BinaryTree.prototype.treeDepth=function(tree){
	let i,j;
	if(!tree){
		return 0;
	}
	
	if(tree.left){
		i=this.treeDepth(tree.left);
	}else{
		i=0;
	}

	if(tree.right){
		j=this.treeDepth(tree.right);
	}else{
		j=0;
	}

	return i>j ? i+1 : j+1;
}

三、非递归前序遍历

非递归遍历,采用一个数组栈去存储结点的引用,以前序为例:前序遍历是根左右,所以先将A结点入栈,再输出A结点的data,再不断遍历左子树,遍历一个结点就将这个结点入栈并输出,直到左子树为空,此时遍历结点的变量也一定是null,所以此时出栈,也就是退一格到上一个结点,此时去遍历该结点的右子树,不管为不为空,如果为空就再次出栈至倒数第二个结点,期间一直是一个循环控制,当元素全部出栈或树为空则循环结束。

代码演示:

/**
 * 非递归前序查找结点
 * */
BinaryTree.prototype.preTraversalByStack=function(tree){
	let stack=new Array(); //初始化一个栈数组
	while(stack.length>0 || tree){
		
		while(tree){  //当左子树不为空一直入栈并输出
			console.log(tree.data);
			stack.unshift(tree);
			tree=tree.left;
		}

		/**
		 * 左子树完成遍历后,出栈至上一个引用查找是否含有右子树
		 * */
		if(stack.length>0){
			tree=stack.shift();
			tree=tree.right;
		}
	}
}

递归遍历算法简单,不再赘述。

完整源码:

'use strict'
//二叉树
const BinaryTree=function(){
	const wm=new WeakMap();

	//二叉树构造函数
	function BinaryTree(treeStr=""){
		this.treeStr=treeStr;

		this.index=Symbol('private');
		const privateMembers=wm.get(this) || {};
		privateMembers[this.index]=0;
		wm.set(this,privateMembers);

		const node=null;
		this.tree=this.createTree(node);
	}

	//内部类,保存左右指针和数据域
	function TreeNode(data){
		this.data=data;
		this.left=null;
		this.right=null;
	}

	/**
	 * 递归创建树
	 * 对于#视为null
	 * */
	BinaryTree.prototype.createTree=function(node){
		let index=wm.get(this)[this.index]++;
		const data=this.treeStr.split('')[index];
		if(index<this.treeStr.split('').length){
			if (data === '#') {
				node = null;
			} else {
				node = new TreeNode(data);
				node.left = this.createTree(node.left);
				node.right = this.createTree(node.right);
			}
		}
		return node;
	}

	/**
	 * 返回二叉树深度
	 * */
	BinaryTree.prototype.treeDepth=function(tree){
		let i,j;
		if(!tree){
			return 0;
		}
		
		if(tree.left){
			i=this.treeDepth(tree.left);
		}else{
			i=0;
		}

		if(tree.right){
			j=this.treeDepth(tree.right);
		}else{
			j=0;
		}

		return i>j ? i+1 : j+1;
	}

	/**
	 * 二叉树前序遍历
	 * */
	BinaryTree.prototype.preTraversal=function(tree){
		if(tree){
			console.log(tree.data);
			tree.left=this.preTraversal(tree.left);
			tree.right=this.preTraversal(tree.right);
		}
		return tree;
	}

	/**
	 * 中序遍历
	 * */
	BinaryTree.prototype.midTraversal=function(tree){
		if (tree) {
			tree.left =this.midTraversal(tree.left);
			console.log(tree.data);
			tree.right=this.midTraversal(tree.right);
		}
		return tree;
	}

	/**
	 * 后序遍历
	 * */
	BinaryTree.prototype.postTraversal=function(tree){
		if (tree) {
			tree.left = this.postTraversal(tree.left);
			tree.right = this.postTraversal(tree.right);
			console.log(tree.data);
		}
		return tree;
	}

	/**
	 * 非递归前序查找结点
	 * */
	BinaryTree.prototype.preTraversalByStack=function(tree){
		let stack=new Array(); //初始化一个栈数组
		while(stack.length>0 || tree){
			
			while(tree){  //当左子树不为空一直入栈并输出
				console.log(tree.data);
				stack.unshift(tree);
				tree=tree.left;
			}

			/**
			 * 左子树完成遍历后,出栈至上一个引用查找是否含有右子树
			 * */
			if(stack.length>0){
				tree=stack.shift();
				tree=tree.right;
			}
		}
	}

	return BinaryTree;
}();

const tree=new BinaryTree('ABDH#K###E##CFI###G#J##');
console.log(tree);
tree.postTraversal(tree.tree);
console.log(tree.treeDepth(tree.tree));
tree.preTraversalByStack(tree.tree);

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值