ps:这部分 视频可在 b战和知乎看到
1、介绍
2、深度优先遍历 简写 dfs
-
那么怎么进行 `深度优先 遍历呢 `` ?
-
上代码 尝试 实现一下
// 新建树 利用 Object和Array
var tree = {
val: 'a',
children: [{
val: 'b',
children: [{
val: 'd',
children: []
},
{
val: 'e',
children: [],
}
],
},
{
val: 'c',
children: [{
val: 'f',
children: []
},
{
val: 'g',
children: [],
}
],
}
]
}
// 深度优先遍历 简写 dfs
var dfs = function (root) {
// 1、访问根节点
console.log(root.val); // a b d e c f g
// 2、对根节点的 children挨个进行深度优先遍历
// root.children.forEach((child) => {
// dfs(child)
// })
// 遍历第二种方式
dfs(n.left)
dfs(n.right)
//简化一下代码
root.children.forEach(dfs)
}
var test = dfs(tree)
- 遍历结果 是可预期的
3、广度优先遍历 简写 bfs
-
这个又应该怎么操作一下 ?
-
上代码 注意 此处的 tree 就是 上面的tree
// 新建树 利用 Object和Array
var tree = {
val: 'a',
children: [{
val: 'b',
children: [{
val: 'd',
children: []
},
{
val: 'e',
children: [],
}
],
},
{
val: 'c',
children: [{
val: 'f',
children: []
},
{
val: 'g',
children: [],
}
],
}
]
}
// 简写 bfs
var bfs = function (root) {
if(!root) {return 0}
// 1、新建队列
const q = [root]
while (q.length) {
// 2、 队头出队 并访问
const n = q.shift()
console.log(n.val)
// 3、队头 children 入队
n.children.forEach((child) => {
q.push(child)
})
//遍历第二种方法
//if(n.left) q.push(n.left)
//if(n.right) q.push(n.right)
}
}
// test
var test = bfs(tree)
- 结果也是可以 预期的 ,可预期性 可是个好的趋势哦
4、二叉树
5、二叉树先序(前序)遍历
-
这一部分非常重要 所以分开 方便展示
-
话不多说 上代码 展示一下这个事情
-
不要着急 我们先建立一个二叉树 方便 后续 展示这三种遍历方式
-
磨刀不误砍柴功(我是真的砍过柴 磨过刀)
-
先种下(新建) 一棵二叉树 新建文件二叉树.js
const bt = {
val: 1,
left: {
val: 2,
left: {
val: 4,
left: null,
right: null,
},
right: {
val: 5,
left: null,
right: null,
},
},
right: {
val: 3,
left: {
val: 6,
left: null,
right: null,
},
right: {
val: 7,
left: null,
right: null,
},
},
};
// module.exports = bt;
- 这是一个非常简单的模型 不过为了方便大家看这个模型 我把它画出来
- 使用 它并实现 先序遍历
<!-- 引入 新建的二叉树 因为这是一个html文件-->
<!-- 如果这个地方新建的是一个js文件 直接 const bt = require('./二叉树.js') -->
<script src="./3.二叉树.js"></script>
<script>
var pre = function (root) {
// 防错 节点不为空 return 不再往下走
if (!root) {
return;
}
console.log(root.val)
pre(root.left)
pre(root.right)
}
// 测试一下
var test = pre(bt)
</script>
- 结果 符合预期 非常nice
5、二叉树中序遍历
-
我相信你还不过瘾 那我们再看看中序遍历
-
代码演示一下 这个过程会很明显
<!-- 引入 新建的二叉树 因为这是一个html文件-->
<!-- 如果这个地方新建的是一个js文件 直接 const bt = require('./二叉树.js') -->
<script src="./3.二叉树.js"></script>
<script>
var ino = function (root) {
if (!root) {
return
}
ino(root.left)
console.log(root.val)
ino(root.right)
}
//test
var test = ino(bt)
</script>
-
结果也是可以预期的呢
-
非常好 这个时候 你已经学会了 前序 和 中序遍历的方式
6、二叉树后序遍历
- 话不多说 我们 赶紧上代码演示一下
<!-- 引入 新建的二叉树 因为这是一个html文件-->
<!-- 如果这个地方新建的是一个js文件 直接 const bt = require('./二叉树.js') -->
<script src="./3.二叉树.js"></script>
<script>
var bed = function (root) {
if (!root) {
return
}
bed(root.left)
bed(root.right)
console.log(root.val)
}
// test
var test = bed(bt)
</script>
-
预期结果 在我们控制之中 很nice
-
可以去转一圈了 (不是摸鱼)
7、先序遍历 非递归版本 使用栈
- 标题也说了 非递归版本
面试特别重要 需要学会 - 代码演示一下 怎么解决问题 ?
<!-- 引入 新建的二叉树 因为这是一个html文件-->
<!-- 如果这个地方新建的是一个js文件 直接 const bt = require('./二叉树.js') -->
<script src="./3.二叉树.js"></script>
<script>
// 递归版本
/*
var pre = function (root) {
// 防错 节点不为空 return 不再往下走
if (!root) {
return;
}
console.log(root.val)
pre(root.left)
pre(root.right)
} */
// 非递归版本
var pre = function (root) {
if (!root) {
return;
}
// 新建一个栈里面放的是根节点
var stack = [root]
while (stack.length) {
// 弹出根节点 并访问根节点
var n = stack.pop()
console.log(n.val)
// 栈是后进先出的结构 先推入右节点 后推入左节点
if (n.right) stack.push(n.right)
if (n.left) stack.push(n.left)
}
}
// 测试一下
var test = pre(bt)
</script>
- 先序遍历相当于 从前往后看书 结果也是可预期的
8、中序遍历 非递归版本 使用栈
- 中序遍历 你是否还记得呢 ?
- 不记得 请往上看看就行
<!-- 引入 新建的二叉树 因为这是一个html文件-->
<!-- 如果这个地方新建的是一个js文件 直接 const bt = require('./二叉树.js') -->
<script src="./3.二叉树.js"></script>
<script>
//递归版本
/*
var ino = function (root) {
if (!root) {
return
}
ino(root.left)
console.log(root.val)
ino(root.right)
}
*/
// 非递归版本
var ino = function (root) {
if (!root) {
return
}
// 新建栈
const stack = []
//新建指针
var p = root
while (stack.length || p) {
while (p) {
//将左节点放入栈中
stack.push(p)
p = p.left
}
//访问根节点
const n = stack.pop()
console.log(n.val)
//将右节点放入栈中
p = n.right
}
}
//test
var test = ino(bt)
</script>
9、后序遍历 非递归版本 使用栈
- 有个技巧 我们发现后续遍历 递归版本是这样的
左---》右 ---》根
递归版本
var bed = function (root) {
if (!root) {
return
}
bed(root.left)
bed(root.right)
console.log(root.val)
}
- 先序遍历的版本是这样的
根--》左---》右
var pre = function (root) {
// 防错 节点不为空 return 不再往下走
if (!root) {
return;
}
console.log(root.val)
pre(root.left)
pre(root.right)
}
- 实现技巧 在于
将后序遍历 倒过来 然后复用先序遍历的代码
<!-- 引入 新建的二叉树 因为这是一个html文件-->
<!-- 如果这个地方新建的是一个js文件 直接 const bt = require('./二叉树.js') -->
<script src="./3.二叉树.js"></script>
<script>
// 递归版本
// var bed = function (root) {
// if (!root) {
// return
// }
// bed(root.left)
// bed(root.right)
// console.log(root.val)
// }
// 非递归版本
var bed = function (root) {
if (!root) {
return
}
//新建两个栈
const stack = [root]
const outputStack = []
while (stack.length) {
// 访问根节点
const n = stack.pop()
// 根节点放入输出栈中
outputStack.push(n)
// 分别对左节点和右节点入栈操作 这个刚好和先序遍历相反
if (n.left) stack.push(n.left)
if (n.right) stack.push(n.right)
}
// 将结果出栈
while (outputStack.length) {
var n = outputStack.pop()
console.log(n.val)
}
}
// test
var test = bed(bt)
</script>
10、小结
- 先序遍历
根 --》 左 ---》 右注意在非递归栈中 根 右 左 - 中序遍历
左 --》 根 ---》 右 - 后序遍历
左 --》 右 ---》 根注意使用 先序遍历复用 - 看到这里 可以和作者一起喝一杯 卡布奇诺 欢迎来