From 2d2a71121036b54f7ed1bdc0492a91781d57d930 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=A3=8A=EF=BC=88=E4=B8=8A=E6=B5=B7=EF=BC=89?= <1452491917@qq.com> Date: Thu, 10 Aug 2023 19:45:26 +0800 Subject: [PATCH 1/3] fix: fixed the bug of arrToTree function --- codes/javascript/modules/TreeNode.js | 23 +++++++++++---------- codes/typescript/modules/TreeNode.ts | 30 ++++++++++++++-------------- 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/codes/javascript/modules/TreeNode.js b/codes/javascript/modules/TreeNode.js index d879ef51c2..7c9d7f6342 100644 --- a/codes/javascript/modules/TreeNode.js +++ b/codes/javascript/modules/TreeNode.js @@ -25,23 +25,24 @@ class TreeNode { * @param arr * @return */ +// https://github.com/krahets/hello-algo/issues/678 function arrToTree(arr) { if (arr.length === 0) return null; - let root = new TreeNode(arr[0]); + const root = new TreeNode(arr[0]); let queue = [root]; let i = 0; while (queue.length) { - let node = queue.shift(); - if (++i >= arr.length) break; - if (arr[i] !== null) { - node.left = new TreeNode(arr[i]); - queue.push(node.left); - } - if (++i >= arr.length) break; - if (arr[i] !== null) { - node.right = new TreeNode(arr[i]); - queue.push(node.right); + const node = queue.shift(); + if (node) { + if (++i >= arr.length) break; + if (arr[i] !== null) node.left = new TreeNode(arr[i]); + if (++i >= arr.length) break; + if (arr[i] !== null) node.right = new TreeNode(arr[i]); + queue.push(node.left, node.right); + } else { + i += 2; + queue.push(null, null); } } diff --git a/codes/typescript/modules/TreeNode.ts b/codes/typescript/modules/TreeNode.ts index 275189e779..c99552f29a 100644 --- a/codes/typescript/modules/TreeNode.ts +++ b/codes/typescript/modules/TreeNode.ts @@ -30,27 +30,27 @@ class TreeNode { * @param arr * @return */ +// https://github.com/krahets/hello-algo/issues/678 function arrToTree(arr: (number | null)[]): TreeNode | null { - if (arr.length === 0) { - return null; - } + if (arr.length === 0) return null; - const root = new TreeNode(arr[0] as number); - const queue = [root]; + const root = new TreeNode(arr[0]); + let queue = [root]; let i = 0; while (queue.length) { - const node = queue.shift() as TreeNode; - if (++i >= arr.length) break; - if (arr[i] !== null) { - node.left = new TreeNode(arr[i] as number); - queue.push(node.left); - } - if (++i >= arr.length) break; - if (arr[i] !== null) { - node.right = new TreeNode(arr[i] as number); - queue.push(node.right); + const node = queue.shift(); + if (node) { + if (++i >= arr.length) break; + if (arr[i] !== null) node.left = new TreeNode(arr[i]); + if (++i >= arr.length) break; + if (arr[i] !== null) node.right = new TreeNode(arr[i]); + queue.push(node.left, node.right); + } else { + i += 2; + queue.push(null, null); } } + return root; } From cdffcc776008e3f4ccebb68934b2c9fe23149a67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=A3=8A=EF=BC=88=E4=B8=8A=E6=B5=B7=EF=BC=89?= <1452491917@qq.com> Date: Thu, 10 Aug 2023 19:48:04 +0800 Subject: [PATCH 2/3] feat(tree): Add the array representation of the binary tree(js,ts) --- .../chapter_tree/array_binary_tree.js | 147 +++++++++++++++++ .../chapter_tree/array_binary_tree.ts | 151 ++++++++++++++++++ 2 files changed, 298 insertions(+) create mode 100644 codes/javascript/chapter_tree/array_binary_tree.js create mode 100644 codes/typescript/chapter_tree/array_binary_tree.ts diff --git a/codes/javascript/chapter_tree/array_binary_tree.js b/codes/javascript/chapter_tree/array_binary_tree.js new file mode 100644 index 0000000000..e5a5a6003d --- /dev/null +++ b/codes/javascript/chapter_tree/array_binary_tree.js @@ -0,0 +1,147 @@ +/** + * File: array_binary_tree.js + * Created Time: 2023-08-06 + * Author: yuan0221 (yl1452491917@gmail.com) + */ + +const { arrToTree } = require('../modules/TreeNode'); +const { printTree } = require('../modules/PrintUtil'); + +/* 数组表示下的二叉树类 */ +class ArrayBinaryTree { + #tree; + + /* 构造方法 */ + constructor(arr) { + this.#tree = arr; + } + + /* 节点数量 */ + size() { + return this.#tree.length; + } + + /* 获取索引为 i 节点的值 */ + val(i) { + // 若索引越界,则返回 null ,代表空位 + if (i < 0 || i >= this.size()) return null; + return this.#tree[i]; + } + + /* 获取索引为 i 节点的左子节点的索引 */ + left(i) { + return 2 * i + 1; + } + + /* 获取索引为 i 节点的右子节点的索引 */ + right(i) { + return 2 * i + 2; + } + + /* 获取索引为 i 节点的父节点的索引 */ + parent(i) { + return (i - 1) / 2; + } + + /* 层序遍历 */ + levelOrder() { + let res = []; + // 直接遍历数组 + for (let i = 0; i < this.size(); i++) { + if (this.val(i) !== null) res.push(this.val(i)); + } + return res; + } + + /* 深度优先遍历 */ + #dfs(i, order, res) { + // 若为空位,则返回 + if (this.val(i) === null) return; + // 前序遍历 + if (order === 'pre') res.push(this.val(i)); + this.#dfs(this.left(i), order, res); + // 中序遍历 + if (order === 'in') res.push(this.val(i)); + this.#dfs(this.right(i), order, res); + // 后序遍历 + if (order === 'post') res.push(this.val(i)); + } + + /* 前序遍历 */ + preOrder() { + const res = []; + this.#dfs(0, 'pre', res); + return res; + } + + /* 中序遍历 */ + inOrder() { + const res = []; + this.#dfs(0, 'in', res); + return res; + } + + /* 后序遍历 */ + postOrder() { + const res = []; + this.#dfs(0, 'post', res); + return res; + } +} + +/* Driver Code */ +// 初始化二叉树 +// 这里借助了一个从数组直接生成二叉树的函数 +const arr = Array.of( + 1, + 2, + 3, + 4, + null, + 6, + 7, + 8, + 9, + null, + null, + 12, + null, + null, + 15 +); + +const root = arrToTree(arr); +console.log('\n初始化二叉树\n'); +console.log('二叉树的数组表示:'); +console.log(arr); +console.log('二叉树的链表表示:'); +printTree(root); + +// 数组表示下的二叉树类 +const abt = new ArrayBinaryTree(arr); + +// 访问节点 +const i = 1; +const l = abt.left(i); +const r = abt.right(i); +const p = abt.parent(i); +console.log('\n当前节点的索引为 ' + i + ' ,值为 ' + abt.val(i)); +console.log( + '其左子节点的索引为 ' + l + ' ,值为 ' + (l === null ? 'null' : abt.val(l)) +); +console.log( + '其右子节点的索引为 ' + r + ' ,值为 ' + (r === null ? 'null' : abt.val(r)) +); +console.log( + '其父节点的索引为 ' + p + ' ,值为 ' + (p === null ? 'null' : abt.val(p)) +); + +// 遍历树 +let res = abt.levelOrder(); +console.log('\n层序遍历为:' + res); +res = abt.preOrder(); +console.log('前序遍历为:' + res); +res = abt.inOrder(); +console.log('中序遍历为:' + res); +res = abt.postOrder(); +console.log('后序遍历为:' + res); diff --git a/codes/typescript/chapter_tree/array_binary_tree.ts b/codes/typescript/chapter_tree/array_binary_tree.ts new file mode 100644 index 0000000000..3687bc5416 --- /dev/null +++ b/codes/typescript/chapter_tree/array_binary_tree.ts @@ -0,0 +1,151 @@ +/** + * File: array_binary_tree.js + * Created Time: 2023-08-09 + * Author: yuan0221 (yl1452491917@gmail.com) + */ + +const { arrToTree } = require('../modules/TreeNode'); +const { printTree } = require('../modules/PrintUtil'); + +type Order = 'pre' | 'in' | 'post'; + +/* 数组表示下的二叉树类 */ +class ArrayBinaryTree { + #tree: (number | null)[]; + + /* 构造方法 */ + constructor(arr: (number | null)[]) { + this.#tree = arr; + } + + /* 节点数量 */ + size(): number { + return this.#tree.length; + } + + /* 获取索引为 i 节点的值 */ + val(i: number): number | null { + // 若索引越界,则返回 null ,代表空位 + if (i < 0 || i >= this.size()) return null; + return this.#tree[i]; + } + + /* 获取索引为 i 节点的左子节点的索引 */ + left(i: number): number { + return 2 * i + 1; + } + + /* 获取索引为 i 节点的右子节点的索引 */ + right(i: number): number { + return 2 * i + 2; + } + + /* 获取索引为 i 节点的父节点的索引 */ + parent(i: number): number { + return (i - 1) / 2; + } + + /* 层序遍历 */ + levelOrder(): number[] { + let res = []; + // 直接遍历数组 + for (let i = 0; i < this.size(); i++) { + if (this.val(i) !== null) res.push(this.val(i)); + } + return res; + } + + /* 深度优先遍历 */ + #dfs(i: number, order: Order, res: (number | null)[]): void { + // 若为空位,则返回 + if (this.val(i) === null) return; + // 前序遍历 + if (order === 'pre') res.push(this.val(i)); + this.#dfs(this.left(i), order, res); + // 中序遍历 + if (order === 'in') res.push(this.val(i)); + this.#dfs(this.right(i), order, res); + // 后序遍历 + if (order === 'post') res.push(this.val(i)); + } + + /* 前序遍历 */ + preOrder(): (number | null)[] { + const res = []; + this.#dfs(0, 'pre', res); + return res; + } + + /* 中序遍历 */ + inOrder(): (number | null)[] { + const res = []; + this.#dfs(0, 'in', res); + return res; + } + + /* 后序遍历 */ + postOrder(): (number | null)[] { + const res = []; + this.#dfs(0, 'post', res); + return res; + } +} + +/* Driver Code */ +// 初始化二叉树 +// 这里借助了一个从数组直接生成二叉树的函数 +const arr = Array.of( + 1, + 2, + 3, + 4, + null, + 6, + 7, + 8, + 9, + null, + null, + 12, + null, + null, + 15 +); + +const root = arrToTree(arr); +console.log('\n初始化二叉树\n'); +console.log('二叉树的数组表示:'); +console.log(arr); +console.log('二叉树的链表表示:'); +printTree(root); + +// 数组表示下的二叉树类 +const abt = new ArrayBinaryTree(arr); + +// 访问节点 +const i = 1; +const l = abt.left(i); +const r = abt.right(i); +const p = abt.parent(i); +console.log('\n当前节点的索引为 ' + i + ' ,值为 ' + abt.val(i)); +console.log( + '其左子节点的索引为 ' + l + ' ,值为 ' + (l === null ? 'null' : abt.val(l)) +); +console.log( + '其右子节点的索引为 ' + r + ' ,值为 ' + (r === null ? 'null' : abt.val(r)) +); +console.log( + '其父节点的索引为 ' + p + ' ,值为 ' + (p === null ? 'null' : abt.val(p)) +); + +// 遍历树 +let res = abt.levelOrder(); +console.log('\n层序遍历为:' + res); +res = abt.preOrder(); +console.log('前序遍历为:' + res); +res = abt.inOrder(); +console.log('中序遍历为:' + res); +res = abt.postOrder(); +console.log('后序遍历为:' + res); + +export {}; From 76d65c703281486aa067628fb70256726a59a11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=A2=81=E7=A3=8A=EF=BC=88=E4=B8=8A=E6=B5=B7=EF=BC=89?= <1452491917@qq.com> Date: Fri, 11 Aug 2023 09:30:48 +0800 Subject: [PATCH 3/3] refactor: Make the arrToTree method match the method in java --- codes/javascript/modules/TreeNode.js | 26 ++++++-------------------- codes/typescript/modules/TreeNode.ts | 26 ++++++-------------------- 2 files changed, 12 insertions(+), 40 deletions(-) diff --git a/codes/javascript/modules/TreeNode.js b/codes/javascript/modules/TreeNode.js index 7c9d7f6342..bdde3519d0 100644 --- a/codes/javascript/modules/TreeNode.js +++ b/codes/javascript/modules/TreeNode.js @@ -25,27 +25,13 @@ class TreeNode { * @param arr * @return */ -// https://github.com/krahets/hello-algo/issues/678 -function arrToTree(arr) { - if (arr.length === 0) return null; - - const root = new TreeNode(arr[0]); - let queue = [root]; - let i = 0; - while (queue.length) { - const node = queue.shift(); - if (node) { - if (++i >= arr.length) break; - if (arr[i] !== null) node.left = new TreeNode(arr[i]); - if (++i >= arr.length) break; - if (arr[i] !== null) node.right = new TreeNode(arr[i]); - queue.push(node.left, node.right); - } else { - i += 2; - queue.push(null, null); - } +function arrToTree(arr, i = 0) { + if (i < 0 || i >= arr.length || arr[i] === null) { + return null; } - + let root = new TreeNode(arr[i]); + root.left = arrToTree(arr, 2 * i + 1); + root.right = arrToTree(arr, 2 * i + 2); return root; } diff --git a/codes/typescript/modules/TreeNode.ts b/codes/typescript/modules/TreeNode.ts index c99552f29a..e91232db0c 100644 --- a/codes/typescript/modules/TreeNode.ts +++ b/codes/typescript/modules/TreeNode.ts @@ -30,27 +30,13 @@ class TreeNode { * @param arr * @return */ -// https://github.com/krahets/hello-algo/issues/678 -function arrToTree(arr: (number | null)[]): TreeNode | null { - if (arr.length === 0) return null; - - const root = new TreeNode(arr[0]); - let queue = [root]; - let i = 0; - while (queue.length) { - const node = queue.shift(); - if (node) { - if (++i >= arr.length) break; - if (arr[i] !== null) node.left = new TreeNode(arr[i]); - if (++i >= arr.length) break; - if (arr[i] !== null) node.right = new TreeNode(arr[i]); - queue.push(node.left, node.right); - } else { - i += 2; - queue.push(null, null); - } +function arrToTree(arr: (number | null)[], i: number = 0): TreeNode | null { + if (i < 0 || i >= arr.length || arr[i] === null) { + return null; } - + let root = new TreeNode(arr[i]); + root.left = arrToTree(arr, 2 * i + 1); + root.right = arrToTree(arr, 2 * i + 2); return root; }