使用javascript实现排序二叉树(2)
上一篇文章我们构造了基本的一个排序二叉树的数据结构,但是仅仅是定义了一个insert方法去创建二叉排序树,今天我们来给我们的数据结构添加一些遍历的功能。
二叉树的三种遍历方式(以根节点为准来定义前、中、后)的介绍及其应用场景:
-
前序遍历
- 顺序:根节点 => 左子树 => 右子树
- 应用:可以用来构建文件的目录结构,输出所有目录并分层
-
中序遍历
- 顺序:左子树 => 根节点 => 右子树
- 应用:可以进行排序,输出的结果是一个递增的序列
-
后续遍历
- 顺序:左子树 => 右子树 => 根节点
- 应用:后续遍历是先遍历子树,最后到根节点,可以实现统计节点数、计算文件夹大小的功能
思考 :
- 遍历的方法是给谁用的,是否需要暴露出去
- 如果暴露出去,怎样设计才能让调用者能够获取到每一个节点并且进行对应的操作
结论 :
- 肯定是要暴露出去给别人调用的
- 给别人调用,具体的逻辑是不确定的,所以应该是调用者传入一个函数,我们在遍历的时候把每一次的节点都传给这个函数,并且去调用这个函数,这样我们不用管具体函数的逻辑,反正已经把它想要的 节点 给他了,具体怎样操作我们不用管。
分析完毕之后,依然是上次的代码,我们给他添加前序中序和后续遍历的方法:
function BinaryTree(){
var root = null; //根节点默认为null
//节点类型的构造函数
function Node(key){
this.key = key;
this.left = null;
this.right = null;
}
//插入方法
this.insert = function(key){
var newNode = new Node(key);
if(root === null){
root = newNode;
}else{
insertNode(root,newNode)
}
}
var insertNode = function(node,newNode){
if(newNode.key < node.key){
if(node.left === null){
node.left = newNode;
}else{
insertNode(node.left,newNode)
}
}else{
if(newNode.key > node.key){
if(node.right === null){
node.right = newNode;
}else{
insertNode(node.right,newNode)
}
}
}
}
/*--------------------------------------------------------*/
/*
前序遍历: 根节点 => 左子树 => 右子树
*/
this.preTravel = function(callback){
//和上面插入操作类似,都用一个内部的函数来实现具体的逻辑,因为需要使用root
preTravelNode(root,callback);
}
/*
逻辑:
1. 判断传入的节点是否为null,如果为null就直接return
2. 如果不为null,则继续对该节点下的left和right进行递归调用
3. 具体的调用顺序根据为 根节点 => 左子树 => 右子树
*/
function preTravelNode(node,callback){
if(node !== null){
callback(node.key);
preTravelNode(node.left,callback);
preTravelNode(node.right,callback);
}
}
//中序遍历
this.middleTravel = function(callback){
middleTravelNode(root,callback);
}
function middleTravelNode(node,callback){
if(node !== null){
middleTravelNode(node.left,callback);
callback(node.key);
middleTravelNode(node.right,callback);
}
}
//后续遍历
this.nextTravel = function(callback){
nextTravelNode(root,callback);
}
function nextTravelNode(node,callback){
if(node !== null){
nextTravelNode(node.left,callback);
nextTravelNode(node.right,callback);
callback(node.key);
}
}
}
var nodes = [8,7,3,4,6,5,2,9,12]
var binaryTree = new BinaryTree();
nodes.forEach((item)=>{
binaryTree.insert(item)
})
//测试前序遍历
binaryTree.beforeTravel((key)=>{
console.log(key) // 8,7,3,2,4,6,5,9,10
})
console.log('--------------------')
//中序遍历
binaryTree.middleTravel((key)=>{
console.log(key) // 2,3,4,5,6,7,8,9,10
})
console.log('--------------------')
//后续遍历
binaryTree.nextTravel((key)=>{
console.log(key) // 2,5,6,4,3,7,10,9,8
})
具体的逻辑 :
- 判断传入的节点是否为null,如果为null就直接return
- 如果不为null,则继续对该节点下的left和right进行递归调用
- 具体的调用顺序根据前序、中序、后序、的访问节点顺序去修改调用的顺序
还是放上这个二叉树的图,根据图去对比测试的遍历结果更直观:
重点 :
- 怎样设计遍历方法,调用者传什么东西进来,我们要暴露什么东西出去,这个地方得想明白
下期内容 :
- 实现二叉树的节点查找功能
- 实现二叉树中节点的删除功能
- 实现一个二叉树的一个小游戏
上期内容 :
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。