JS二叉树的存储如何理解,二叉树相关算法有哪些
Admin 2022-08-08 群英技术资讯 1843 次浏览
这篇文章主要介绍了JS二叉树的存储如何理解,二叉树相关算法有哪些相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇JS二叉树的存储如何理解,二叉树相关算法有哪些文章都会有所收获,下面我们一起来看看吧。二叉树是每个节点最多只能有两个子节点的树,如下图所示:

一个二叉树具有以下几个特质:
i层的节点最有只有2^(i-1)个;k,那二叉树最多有2^k-1个节点;n0表示叶子节点的个数,n2是度为2的非叶子节点的个数,那么两者满足关系n0 = n2 + 1。如果在一个二叉树中,除了叶子节点,其余的节点的每个度都是2,则说明该二叉树是一个满二叉树,
如下图所示:

满二叉树除了满足普通二叉树特质,还具有如下几个特质:
n层具有2^(n-1)个节点;k的满二叉树一定存在2^k-1个节点,叶子节点的个数为2^(k-1);n个节点的满二叉树的深度为log_2^(n+1)。如果一个二叉树去掉最后一次层是满二叉树,且最后一次的节点是依次从左到右分布的,则这个二叉树是一个完全二叉树,
如下图所示:

存储二叉树的常见方式分为两种,一种是使用数组存储,另一种使用链表存储。
使用数组存储二叉树,如果遇到完全二叉树,存储顺序从上到下,从左到右,如下图所示:

如果是一个非完全二叉树,如下图所示:

需要先将其转换为完全二叉树,然后在进行存储,如下图所示:

可以很明显的看到存储空间的浪费。
使用链表存储通常将二叉树中的分为3个部分,如下图:

这三个部分依次是左子树的引用,该节点包含的数据,右子树的引用,存储方式如下图所示:

以下算法中遍历用到的树如下:
// tree.js
const bt = {
val: 'A',
left: {
val: 'B',
left: { val: 'D', left: null, right: null },
right: { val: 'E', left: null, right: null },
},
right: {
val: 'C',
left: {
val: 'F',
left: { val: 'H', left: null, right: null },
right: { val: 'I', left: null, right: null },
},
right: { val: 'G', left: null, right: null },
},
}
module.exports = bt
二叉树的深度优先遍历与树的深度优先遍历思路一致,思路如下:
leftright实现代码如下:
const bt = {
val: 'A',
left: {
val: 'B',
left: { val: 'D', left: null, right: null },
right: { val: 'E', left: null, right: null },
},
right: {
val: 'C',
left: {
val: 'F',
left: { val: 'H', left: null, right: null },
right: { val: 'I', left: null, right: null },
},
right: { val: 'G', left: null, right: null },
},
}
function dfs(root) {
if (!root) return
console.log(root.val)
root.left && dfs(root.left)
root.right && dfs(root.right)
}
dfs(bt)
/** 结果
A B D E C F H I G
*/
实现思路如下:
left和right依次入队实现代码如下:
function bfs(root) {
if (!root) return
const queue = [root]
while (queue.length) {
const node = queue.shift()
console.log(node.val)
node.left && queue.push(node.left)
node.right && queue.push(node.right)
}
}
bfs(bt)
/** 结果
A B C D E F G H I
*/
二叉树的先序遍历实现思想如下:
如下图所示:

递归方式实现如下:
const bt = require('./tree')
function preorder(root) {
if (!root) return
console.log(root.val)
preorder(root.left)
preorder(root.right)
}
preorder(bt)
/** 结果
A B D E C F H I G
*/
迭代方式实现如下:
// 非递归版
function preorder(root) {
if (!root) return
// 定义一个栈,用于存储数据
const stack = [root]
while (stack.length) {
const node = stack.pop()
console.log(node.val)
/* 由于栈存在先入后出的特性,所以需要先入右子树才能保证先出左子树 */
node.right && stack.push(node.right)
node.left && stack.push(node.left)
}
}
preorder(bt)
/** 结果
A B D E C F H I G
*/
二叉树的中序遍历实现思想如下:
如下图所示:

递归方式实现如下:
const bt = require('./tree')
// 递归版
function inorder(root) {
if (!root) return
inorder(root.left)
console.log(root.val)
inorder(root.right)
}
inorder(bt)
/** 结果
D B E A H F I C G
*/
迭代方式实现如下:
// 非递归版
function inorder(root) {
if (!root) return
const stack = []
// 定义一个指针
let p = root
// 如果栈中有数据或者p不是null,则继续遍历
while (stack.length || p) {
// 如果p存在则一致将p入栈并移动指针
while (p) {
// 将 p 入栈,并以移动指针
stack.push(p)
p = p.left
}
const node = stack.pop()
console.log(node.val)
p = node.right
}
}
inorder(bt)
/** 结果
D B E A H F I C G
*/
二叉树的后序遍历实现思想如下:
如下图所示:

递归方式实现如下:
const bt = require('./tree')
// 递归版
function postorder(root) {
if (!root) return
postorder(root.left)
postorder(root.right)
console.log(root.val)
}
postorder(bt)
/** 结果
D E B H I F G C A
*/
迭代方式实现如下:
// 非递归版
function postorder(root) {
if (!root) return
const outputStack = []
const stack = [root]
while (stack.length) {
const node = stack.pop()
outputStack.push(node)
// 这里先入left需要保证left后出,在stack中后出,就是在outputStack栈中先出
node.left && stack.push(node.left)
node.right && stack.push(node.right)
}
while (outputStack.length) {
const node = outputStack.pop()
console.log(node.val)
}
}
postorder(bt)
/** 结果
D E B H I F G C A
*/
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:mmqy2019@163.com进行举报,并提供相关证据,查实之后,将立刻删除涉嫌侵权内容。
猜你喜欢
一.使用插件1.NodeJs自带的加密插件:crypto文档:https://nodejs.org/api/crypto.html可以用来将用户密码加密再存入数据库//随机生成加密token的密匙,用于jwt加密密匙lettokenSecret=crypto.randomBytes(16).toString('hex'), 2.用于生成token的插件:jwt-si
这篇文章主要介绍了网址URL中特殊字符转义编码,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
这篇文章主要介绍了原生js XMLhttprequest请求onreadystatechange执行两次的解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
目录前言????目标????搭建开发环境????️生成模板????CSS预处理器????eslint????组件库编译⚡️vite的打包配置⚡️自动生成ts类型文件⚡️样式懒加载与全量加载????文档❤️npm 发布与发布前的测试????测试前言日常使用开源的组件库时我们或多或少的都会做一些自定义的配置来符合实际的设计,当这些设计形成一定规模时,设计狮们就会形成一套
目录根据条件判断按钮是否可以点击方法一:使用v-if 、v-else 来判断方法二:增加一个变量,判断vue判断点击当前元素需要判断你是点击了遮罩层还是form表单接下来是分别对e.currentTarget、e.target打印根据条件判断按钮是否可以点击按钮当在特定环境下不可点击,需要根据判断来控制点击事件。方法一
成为群英会员,开启智能安全云计算之旅
立即注册关注或联系群英网络
7x24小时售前:400-678-4567
7x24小时售后:0668-2555666
24小时QQ客服
群英微信公众号
CNNIC域名投诉举报处理平台
服务电话:010-58813000
服务邮箱:service@cnnic.cn
投诉与建议:0668-2555555
Copyright © QY Network Company Ltd. All Rights Reserved. 2003-2020 群英 版权所有
增值电信经营许可证 : B1.B2-20140078 ICP核准(ICP备案)粤ICP备09006778号 域名注册商资质 粤 D3.1-20240008