媒介
本篇文章是在二叉排序树的基础上举行遍历、查找、与删除结点。
那末起首来看一下什么是二叉排序树?
二叉排序树
定义
二叉排序树,又称二叉查找树、二叉搜刮树。
- 若左子树不为空,左子树上一切结点均小于它的根结点的值;
- 若右子树不为空,右子树上一切结点均大于它的根结点的值;
- 摆布子树也分别为二叉排序树。
插进去算法
我们知道了什么是二叉排序树,如今来看下它的详细算法完成。
// 构建二叉树
function BinaryTree() {
// 定义结点
let Node = function(key) {
this.key = key
this.left = left
this.right = right
}
// 定义根结点
let root = null
// 取得整棵树
this.getRoot = function() {
return this.root
}
// 定义插进去结点算法
let insertNode = function(node, newNode) {
// 比较要插进去结点与当前结点值的大小,若大于当前结点,插进去左子树,反之,插进去右子树
if(newNode.key < node.key) {
if(node.left === null) {
node.left = newNode
} else {
insertNode(node.left, newNode)
}
} else {
if(node.right === null) {
node.right = newNode
} else {
insertNode(node.right, newNode)
}
}
}
// 定义二叉排序树插进去算法
this.insert = function(key) {
let newNode = new Node(key)
if(root === null) {
root = newNode
} else {
insertNode(root, newNode)
}
}
}
let nodes = [8,3,30,1,6,14,4,7,13]
// 建立立实例
let tree = new BinaryTree()
nodes.forEach(function(key) {
tree.insert(key)
})
console.log("建立的二叉树是:", tree.getRoot())
至此,一棵二叉排序树就组织完啦。接下来我们依据组织的这颗二叉树举行响应遍历、查找与删除操纵。
遍历二叉树
二叉树的遍历分为深度优先遍历和广度优先遍历。
深度优先遍历
深度优先遍历(Depth First Search)是指沿着树的深度举行遍历树的结点。个中深度优先遍历又分为三种:前序遍历、中序遍历、后序遍历。
这里前序、中序、后序是依据根结点的递次定名的。
1、前序遍历
定义
前序遍历也叫做先根遍历、先序遍历、前序漫游,记做 根摆布。
- 先接见根结点;
- 前序遍历左子树;
- 前序遍历右子树。
前序遍历的作用是能够复制已有的二叉树,且比从新组织的二叉树的效率高。
下面我们来看它的算法完成。分为递归与非递归两种。
要领一 递归完成
function BinaryTree() {
// 这里省略了二叉排序树的构建要领
// 定义前序遍历算法
let preOrderTraverseNode = function(node, callback) {
if(node !== null) {
callback(node.key) // 先接见当前根结点
preOrderTraverseNode(node.left, callback) // 接见左子树
preOrderTraverseNode(node.right, callback) // 接见右子树
}
}
// 定义前序遍历要领
this.preOrderTraverse = function(callback) {
preOrderTraverseNode(root, callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key) {
tree.insert(key) // 组织二叉树
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.preOrderTraverse(callback) // 8 3 1 6 4 7 10 14 13
要领二 非递归完成
function BinaryTree() {
// ...
// 定义前序遍历算法
let preOrderTraverseNode = function(node, callback) {
let stack = []
if(node !== null) {
stack.push(node)
}
while(stack.length) {
let temp = stack.pop()
callback(temp.key)
// 这里先放右侧再放左侧是因为取出来的递次相反
if(temp.right !== null) {
stack.push(temp.right)
}
if(temp.left !== null) {
stack.push(temp.left)
}
}
}
// 定义前序遍历要领
this.preOrderTraverse = function(callback) {
preOrderTraverseNode(root, callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key) {
tree.insert(key) // 组织二叉树
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.preOrderTraverse(callback) //8 3 1 6 4 7 10 14 13
2、中序遍历
定义
中序遍历也叫做中根遍历、中序漫游,记做 左根右。
- 若左子树不为空,则先中序遍历左子树;
- 接见根结点;
- 若右子树不为空,则中序遍历右子树。
中序遍历二叉排序树,获得的数组是有序的且是升序的。
下面我们来看中序遍历算法的完成。分为递归和非递归两种。
要领一 递归完成
function BinaryTree() {
// 省略二叉排序树的建立
// 定义中序遍历算法
let inOrderTraverseNode = function(node, callback) {
if(node !== null) {
inOrderTraverseNode(node.left, callback) // 先接见左子树
callback(node.key) // 再接见当前根结点
inOrderTraverseNode(node.right, callback) // 接见右子树
}
}
// 定义中序遍历要领
this.inOrderTraverse = function(callback) {
inOrderTraverseNode(root, callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key) {
tree.insert(key) // 组织二叉树
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.inOrderTraverse(callback) // 1 3 4 6 7 8 10 13 14
要领二 非递归完成
借助于栈,先将左子树悉数放进栈中,以后输出,末了处置惩罚右子树。
function BinaryTree() {
// 省略二叉排序树的构建要领
// 定义中序遍历算法
let inOrderTraverseNode = function(node, callback) {
let stack = []
while(true) {
// 将当前结点的左子树推入栈
while(node !== null) {
stack.push(node)
node = node.left
}
// 定义停止前提
if(stack.length === 0) {
break
}
let temp = stack.pop()
callback(temp.key)
node = temp.right
}
}
this.inOrderTraverse = function(callback) {
inOrderTraverseNode(root, callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key) {
tree.insert(key) // 组织二叉树
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.inOrderTraverse(callback) // 1 3 4 6 7 8 10 13 14
3、后序遍历
定义
后序遍历也叫做后根遍历、后序漫游,记做 摆布根。
- 若左子树不为空,后序遍历左子树;
- 若右子树不为空,后序遍历右子树;
- 接见根结点。
后序遍历的作用用于文件体系途径中,或将一般表达式变成逆波兰表达式。
下面我们来看后序遍历算法的完成。分为递归和非递归两种。
要领一 递归完成
// 先组织一棵二叉树
function BinaryTree() {
// 省略二叉排序树的构建要领
// 定义后序遍历算法
let postOrderTraverseNode = function(node, callback) {
if(node !== null) {
postOrderTraverseNode(node.left, callback) // 遍历左子树
postOrderTraverseNode(node.right, callback) // 再遍历右子树
callback(node.key) // 接见根结点
}
}
// 定义后序遍历要领
this.postOrderTraverse = function(callback) {
postOrderTraverseNode(root, callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key){
tree.insert(key)
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.postOrderTraverse(callback) // 1 4 7 6 3 13 14 10 8
要领二 非递归完成
// 先组织一棵二叉树
function BinaryTree() {
// 省略二叉排序树的构建要领
// 定义后序遍历算法
let postOrderTraverseNode = function(node, callback) {
let stack = []
let res = []
stack.push(node)
while(stack.length) {
let temp = stack.pop()
res.push(temp.key)
if(temp.left !== null) {
stack.push(temp.left)
}
if(temp.right !== null) {
stack.push(temp.right)
}
}
callback(res.reverse())
}
// 定义后序遍历要领
this.postOrderTraverse = function(callback) {
postOrderTraverseNode(root, callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key){
tree.insert(key)
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.postOrderTraverse(callback) // 1 4 7 6 3 13 14 10 8
广度优先遍历
广度优先遍历(Breadth First Search),又叫做宽度优先遍历、条理遍历,是指从根结点沿着树的宽度搜刮遍历。
下面来看它的完成道理
要领一 递归
function BinaryTree() {
// 省略二叉排序树的构建
let wideOrderTraverseNode = function(root) {
let stack = [root] // 先将要遍历的树压入栈
return function bfs(callback) {
let node = stack.shift()
if(node) {
callback(node.key)
if(node.left) stack.push(node.left);
if(node.right) stack.push(node.right);
bfs(callback)
}
}
}
this.wideOrderTraverse = function(callback) {
wideOrderTraverseNode(root)(callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key) {
tree.insert(key)
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.wideOrderTraverse(callback) // 8,3,10,1,6,14,4,7,13
要领二 非递归
运用栈完成,未接见的元素入栈,接见后则出栈,并将其leve摆布元素入栈,直到恭弘=叶 恭弘子元素完毕。
function BinaryTree() {
// 省略二叉排序树的构建
let wideOrderTraverseNode = function(node, callback) {
let stack = []
if(node === null) {
return []
}
stack.push(node)
while(stack.length) {
// 每一层的结点数
let level = stack.length
// 遍历每一层元素
for(let i = 0; i < level; i++) {
// 当前接见的结点出栈
let temp = stack.shift()
// 出栈结点的孩子入栈
temp.left ? queue.push(temp.left) : ''
temp.right ? queue.push(temp.right) : ''
callback(temp.key)
}
}
}
this.wideOrderTraverse = function(callback) {
wideOrderTraverseNode(root, callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key) {
tree.insert(key)
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.wideOrderTraverse(callback) // 8,3,10,1,6,14,4,7,13
要领三 非递归
function BinaryTree() {
// 省略二叉排序树的构建
let wideOrderTraverseNode = function(node, callback) {
let stack = []
if(node === null) {
return []
}
stack.push(node)
while(stack.length) {
let temp = stack.shift()
callback(temp.key)
if(temp.left) {
stack.push(temp.left)
}
if(temp.right) {
stack.push(temp.right)
}
}
}
this.wideOrderTraverse = function(callback) {
wideOrderTraverseNode(root, callback)
}
}
let nodes = [8,3,10,1,6,14,4,7,13]
let tree = new BinaryTree()
nodes.forEach(function(key) {
tree.insert(key)
})
// 定义回调函数
let callback = function(key) {
console.log(key)
}
tree.wideOrderTraverse(callback) // 8,3,10,1,6,14,4,7,13
鉴于篇幅太长,二叉树结点的查找和删除会在下一篇文章内~