这是第六周的练习题,最近加班比较多,上周主要完成一篇 GraphQL入门教程 ,有兴趣的小伙伴可以看下哈。

下面是之前分享的链接:

欢迎关注我的 个人主页 && 个人博客 && 个人知识库 && 微信公众号“前端自习课”

本周练习内容:数据结构与算法 —— Tree

这些都是数据结构与算法,一部分方法是团队其他成员实现的,一部分我自己做的,有什么其他实现方法或错误,欢迎各位大佬指点,感谢。

一、什么是树?

1.树有什么特点,什么是二叉树和二叉搜索树(BST: Binary Search Tree)?

2.生活中常见的例子有哪些?


解析:

  1. 树有什么特点,什么是二叉树和二叉搜索树:
  • 是一种非线性的数据结构,以分层方式存储数据,用来表示有层级关系的数据

  • 每棵树至多只有一个根结点根结点会有很多子节点,每个子节点只有一个父结点

  • 父结点子节点是相对的。

  1. 生活中的例子:

    如:家谱、公司组织架构图。

二、请实现二叉搜索树(BST),并实现以下方法:

  • insert(key):向树中插入一个新的键;
  • search(key):树中查找一个键,如果节点存在返回true,不存在返回false;
  • min():返回树中最小的值/键;
  • max():返回树中最大的值/键;
  • remove(key):移除某个键;

提示:所谓的键对应于之前章节所学的节点(Node)

class Node {
constructor(key){
this.key = key
this.left = null
this.right = null
}
}
class BST {
constructor(){
this.root = null
}
/**
* 插入一个节点
* @param {*} node 插入的位置节点
* @param {*} newNode 插入的节点
*/
insertNode (node, newNode){
if(newNode.key < node.key){
if(node.left === null && node.right === null){
node.left = newNode
}else if(node.left !== null && node.right === null){
node.right = newNode
}else{
this.insertNode(node.left, newNode)
}
}else{
if(node.left === null && node.right === null){
node.left = newNode
}else if(node.left !== null && node.right === null){
node.right = newNode
}else{
this.insertNode(node.right, newNode)
}
}
}
/**
* 插入操作
* @param {*} key
*/
insert (key){
let newNode = new Node(key)
if(this.root === null){
this.root = newNode
}else{
this.insertNode(this.root, newNode)
}
}
searchNode (node, key){
if(node === null) return false
if(key < node.key){
return this.searchNode(node.left, key)
}else if(key > node.key){
return this.searchNode(node.right, key)
}else{
return true
}
}
/**
* 搜索操作
* @param {*} key
*/
search (key){
return this.searchNode(this.root, key)
}
/**
* 最小值的节点
*/
min (){
let node = this.root
if(node === null) return null
while(node && node.left !== null){
node = node.left
}
return node.key
}
/**
* 最大值的节点
*/
max (){
let node = this.root
if(node === null) return null
while(node && node.right !== null){
node = node.right
}
return node.key
}
/**
* 找到最小节点
* @param {*} node
*/
findMinNode (node){
if(node === null) return null
while(node && node.left !== null){
node = node.left
}
return node
}
/**
* 删除一个节点
* @param {*} node
* @param {*} key
*/
removeNode (node, key){
if(node === null) return null
if(key < node.key){
node.left = this.removeNode(node.left, key)
return node
}else if(key > node.key){
node.right = this.removeNode(node.right, key)
return node
}else{
// 1.叶节点
if(node.left === null && node.right === null){
node = null
return node
}
// 2.只有一个子节点
if(node.left === null){
node = node.right
return node
}else if(node.right === null){
node = node.left
}
// 3.有两个子节点
let curNode = this.findMinNode(node.right)
node.key = curNode.key
node.right = this.removeNode(node.right, curNode.key)
return node
}
}
/**
* 删除一个节点
* @param {*} key
*/
remove (key){
if(this.root === null) return null
this.root = this.removeNode(this.root, key)
}
}

三、基于题二实现二叉搜索树扩展以下方法:

  • preOrderTraverse(): 通过先序遍历方式遍历所有节点;
  • inOrderTraverse(): 通过中序遍历方式遍历所有节点;
  • postOrderTraverse(): 通过后序遍历方式遍历所有节点;

提示:

  • 先序:先访问根节点,然后以同样方式访问左子树和右子树;(根==>左==>右)

输出 =》 11 7 5 3 6 9 8 10 15 13 12 14 20 18 25

  • 中序:先访问左子树,再访问根节点,最后访问右字数;以升序访问所有节点;(左==>根==>右)

输出 =》 3 5 6 7 8 9 10 11 12 13 14 15 18 20 25

  • 后序:先访问叶子节点,从左子树到右子树,再到根节点。(左==>右==>根)

输出 =》 3 6 5 8 10 9 7 12 14 13 18 25 20 15 11


解析:

// 1. 先序
BST.prototype.preOrderTraverseNode = function(node, callback){
if(node !== null){
callback(node.key)
this.preOrderTraverseNode(node.left, callback)
this.preOrderTraverseNode(node.right, callback)
}
}
BST.prototype.preOrderTraverse = function(callback){
this.preOrderTraverseNode(this.root, callback)
} // 2. 中序
BST.prototype.inOrderTraverseNode = function(node, callback){
if(node !== null){
this.inOrderTraverseNode(node.left, callback)
callback(node.key)
this.inOrderTraverseNode(node.right, callback)
}
}
BST.prototype.inOrderTraverse = function(callback){
this.inOrderTraverseNode(this.root, callback)
} // 3. 后序
BST.prototype.postOrderTraverseNode = function(node, callback){
if(node !== null){
this.postOrderTraverseNode(node.left, callback)
this.postOrderTraverseNode(node.right, callback)
callback(node.key)
}
}
BST.prototype.postOrderTraverse = function(callback){
this.postOrderTraverseNode(this.root, callback)
}

四、请实现从上往下打印二叉树

给定的二叉树为:[3, 9 , 20, null, null, 15, 7]

    3
/ \
9 20
/ \
15 7

请实现一个 printLevelOrder 方法,输出以下结果:

[
[3],
[9, 20],
[15, 7]
]

来源:102.二叉树的层次遍历

解析:

  • 方法一:
BST.prototype.printLevelOrder = function (root, arr = [], i = 0){
if (root && (root.key || root.key === 0)) {
!arr[i] && (arr[i] = [])
arr[i].push(root.key)
i++
root.left && this.printLevelOrder(root.left, arr, i)
root.right && this.printLevelOrder(root.right, arr, i)
}
return arr
}
  • 方法二:
BST.prototype.printLevelOrder = function (){
if(this.root === null) return []
let result = [], queue = [this.root]
while(true){
let len = queue.length, arr = []
while(len > 0){
console.log(queue)
let node = queue.shift()
len -= 1
arr.push(node.key)
if(node.left !== null) queue.push(node.left)
if(node.right !== null) queue.push(node.right)
}
if(arr.length === 0) return result
result.push([...arr])
}
}

五、给定一个二叉树,判断其是否是一个有效的二叉搜索树。

假设一个二叉搜索树具有如下特征:

  • 节点的左子树只包含小于当前节点的数。
  • 节点的右子树只包含大于当前节点的数。
  • 所有左子树和右子树自身必须也是二叉搜索树。

示例 1:

输入:
2
/ \
1 3
输出: true

示例 2:

输入:
5
/ \
1 4
/ \
3 6
输出: false
解释: 输入为: [5,1,4,null,null,3,6]。
根节点的值为 5 ,但是其右子节点值为 4 。

代码实现:

/**
* 二叉树节点定义
*/
function TreeNode(val) {
this.val = val;
this.left = this.right = null;
} /**
- @param {TreeNode} root
- @return {boolean}
*/
function isValidBST(root) {};

来源:99.验证二叉搜索树

解析:

function isValidBST(root) {
let arr = []
function inOrderTraverse(node){
if(node === null) return;
node.left && inOrderTraverse(node.left);
arr.push(node.val);
node.right && inOrderTraverse(node.right);
}
inOrderTraverse(root)
for(let i = 0; i < arr.length - 1; i++){
if(arr[i] >= arr[i+1]) return false
}
return true
};

每周一练 之 数据结构与算法(Tree)的更多相关文章

  1. 每周一练 之 数据结构与算法(Dictionary 和 HashTable)

    这是第五周的练习题,上周忘记发啦,这周是复习 Dictionary 和 HashTable. 下面是之前分享的链接: 1.每周一练 之 数据结构与算法(Stack) 2.每周一练 之 数据结构与算法( ...

  2. 每周一练 之 数据结构与算法(LinkedList)

    这是第三周的练习题,原本应该先发第二周的,因为周末的时候,我的母亲大人来看望她的宝贝儿子,哈哈,我得带她看看厦门这座美丽的城市呀. 这两天我抓紧整理下第二周的题目和答案,下面我把之前的也列出来: 1. ...

  3. 每周一练 之 数据结构与算法(Set)

    这是第四周的练习题,五一放假结束,该收拾好状态啦. 下面是之前分享的链接: 1.每周一练 之 数据结构与算法(Stack) 2.每周一练 之 数据结构与算法(LinkedList) 2.每周一练 之 ...

  4. 每周一练 之 数据结构与算法(Queue)

    这是第二周的练习题,这里补充下咯,五一节马上就要到了,自己的计划先安排上了,开发一个有趣的玩意儿. 下面是之前分享的链接: 1.每周一练 之 数据结构与算法(Stack) 2.每周一练 之 数据结构与 ...

  5. 每周一练 之 数据结构与算法(Stack)

    最近公司内部在开始做前端技术的技术分享,每周一个主题的 每周一练,以基础知识为主,感觉挺棒的,跟着团队的大佬们学习和复习一些知识,新人也可以多学习一些知识,也把团队内部学习氛围营造起来. 我接下来会开 ...

  6. 【算法】273-每周一练 之 数据结构与算法(Tree)

    这是第六周的练习题,最近加班比较多. 下面是之前分享的链接: [算法]200-每周一练 之 数据结构与算法(Stack) [算法]213-每周一练 之 数据结构与算法(LinkedList) [算法] ...

  7. 【算法】272-每周一练 之 数据结构与算法(Dictionary 和 HashTable)

    这是第五周的练习题,上周忘记发啦,这周是复习 Dictionary 和 HashTable. 下面是之前分享的链接: [算法]200-每周一练 之 数据结构与算法(Stack) [算法]213-每周一 ...

  8. JavaScript 数据结构与算法之美 - 非线性表中的树、堆是干嘛用的 ?其数据结构是怎样的 ?

    1. 前言 想学好前端,先练好内功,内功不行,就算招式练的再花哨,终究成不了高手. 非线性表(树.堆),可以说是前端程序员的内功,要知其然,知其所以然. 笔者写的 JavaScript 数据结构与算法 ...

  9. 【转】MySQL索引背后的数据结构及算法原理

    摘要 本文以MySQL数据库为研究对象,讨论与数据库索引相关的一些话题.特别需要说明的是,MySQL支持诸多存储引擎,而各种存储引擎对索引的支持也各不相同,因此MySQL数据库支持多种索引类型,如BT ...

随机推荐

  1. nyoj 117 求逆序数 (归并(merge)排序)

    求逆序数 时间限制:2000 ms  |  内存限制:65535 KB 难度:5   描述 在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序.一个排列中 ...

  2. HTML5之worker开启JS多线程模式及window.postMessage跨域

    worker概述 worker基本使用 window下的postMessage worker多线程的应用 一.worker概述 web worker实际上是开启js异步执行的一种方式.在html5之前 ...

  3. 多线程编程(3)——synchronized原理以及使用

    一.对象头 通常在java中一个对象主要包含三部分: 对象头 主要包含GC的状态..类型.类的模板信息(地址).synchronization状态等,在后面介绍. 实例数据:程序代码中定义的各种类型的 ...

  4. 关于IP网段划分

    IP地址分类(A类 B类 C类 D类 E类)     IP地址由四段组成,每个字段是一个字节,8位,最大值是255,, IP地址由两部分组成,即网络地址和主机地址.网络地址表示其属于互联网的哪一个网络 ...

  5. 在linux系统下进行pip升级注意事项

    今天鼓捣爬虫的时候需要用pip安装beautifulsoup4,但是出现了错误,说我的pip版本太低,需要升级一下.刚开始我用了下面这段代码: pip install --upgrade pip 显示 ...

  6. Composer依赖管理 – PHP的利器

    别再到处搜PHP类扩展包了,对于现代语言而言,包管理器基本上是标配.Java 有 Maven,Python 有 pip,Ruby 有 gem,Nodejs 有 npm.PHP 的则是 PEAR,不过 ...

  7. 🙈羞,Spring Bean 初始化/销毁竟然有这么多姿势

    文章来源:http://1t.click/bfHN 一.前言 日常开发过程有时需要在应用启动之后加载某些资源,或者在应用关闭之前释放资源.Spring 框架提供相关功能,围绕 Spring Bean ...

  8. 串烧 JavaCAS相关知识

    JMM与问题引入 为啥先说JMM,因为CAS的实现类中维护的变量都被volatile修饰, 这个volatile 是遵循JMM规范(不是百分百遵循,下文会说)实现的保证多线程并发访问某个变量实现线程安 ...

  9. Swoft 源码剖析 - Swoole和Swoft的那些事 (Http/Rpc服务篇)

    前言 Swoft在PHPer圈中是一个门槛较高的Web框架,不仅仅由于框架本身带来了很多新概念和前沿的设计,还在于Swoft是一个基于Swoole的框架.Swoole在PHPer圈内学习成本最高的工具 ...

  10. 树莓派SSH篇

    开启好树莓派后发现一个问题,怎么才可以输入进树莓派里面呢? 一.你需要和我一样准备一个无线(有线)键盘