forked from krahets/hello-algo
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request krahets#113 from justin-tse/master
Add the TypeScript code and docs for Chapter of Tree
- Loading branch information
Showing
8 changed files
with
617 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,172 @@ | ||
/** | ||
* File: binary_search_tree.ts | ||
* Created Time: 2022-12-14 | ||
* Author: Justin ([email protected]) | ||
*/ | ||
|
||
import { TreeNode } from '../module/TreeNode'; | ||
import { printTree } from '../module/PrintUtil'; | ||
|
||
/* 二叉搜索树 */ | ||
let root: TreeNode | null; | ||
|
||
function BinarySearchTree(nums: number[]): void { | ||
nums.sort((a, b) => a - b); // 排序数组 | ||
root = buildTree(nums, 0, nums.length - 1); // 构建二叉搜索树 | ||
} | ||
|
||
/* 获取二叉树根结点 */ | ||
function getRoot(): TreeNode | null { | ||
return root; | ||
} | ||
|
||
/* 构建二叉搜索树 */ | ||
function buildTree(nums: number[], i: number, j: number): TreeNode | null { | ||
if (i > j) { | ||
return null; | ||
} | ||
// 将数组中间结点作为根结点 | ||
let mid = Math.floor((i + j) / 2); | ||
let root = new TreeNode(nums[mid]); | ||
// 递归建立左子树和右子树 | ||
root.left = buildTree(nums, i, mid - 1); | ||
root.right = buildTree(nums, mid + 1, j); | ||
return root; | ||
} | ||
|
||
/* 查找结点 */ | ||
function search(num: number): TreeNode | null { | ||
let cur = root; | ||
// 循环查找,越过叶结点后跳出 | ||
while (cur !== null) { | ||
if (cur.val < num) { | ||
cur = cur.right; // 目标结点在 root 的右子树中 | ||
} else if (cur.val > num) { | ||
cur = cur.left; // 目标结点在 root 的左子树中 | ||
} else { | ||
break; // 找到目标结点,跳出循环 | ||
} | ||
} | ||
// 返回目标结点 | ||
return cur; | ||
} | ||
|
||
/* 插入结点 */ | ||
function insert(num: number): TreeNode | null { | ||
// 若树为空,直接提前返回 | ||
if (root === null) { | ||
return null; | ||
} | ||
let cur = root, | ||
pre: TreeNode | null = null; | ||
// 循环查找,越过叶结点后跳出 | ||
while (cur !== null) { | ||
if (cur.val === num) { | ||
return null; // 找到重复结点,直接返回 | ||
} | ||
pre = cur; | ||
if (cur.val < num) { | ||
cur = cur.right as TreeNode; // 插入位置在 root 的右子树中 | ||
} else { | ||
cur = cur.left as TreeNode; // 插入位置在 root 的左子树中 | ||
} | ||
} | ||
// 插入结点 val | ||
let node = new TreeNode(num); | ||
if (pre!.val < num) { | ||
pre!.right = node; | ||
} else { | ||
pre!.left = node; | ||
} | ||
return node; | ||
} | ||
|
||
/* 删除结点 */ | ||
function remove(num: number): TreeNode | null { | ||
// 若树为空,直接提前返回 | ||
if (root === null) { | ||
return null; | ||
} | ||
let cur = root, | ||
pre: TreeNode | null = null; | ||
// 循环查找,越过叶结点后跳出 | ||
while (cur !== null) { | ||
// 找到待删除结点,跳出循环 | ||
if (cur.val === num) { | ||
break; | ||
} | ||
pre = cur; | ||
if (cur.val < num) { | ||
cur = cur.right as TreeNode; // 待删除结点在 root 的右子树中 | ||
} else { | ||
cur = cur.left as TreeNode; // 待删除结点在 root 的左子树中 | ||
} | ||
} | ||
// 若无待删除结点,则直接返回 | ||
if (cur === null) { | ||
return null; | ||
} | ||
// 子结点数量 = 0 or 1 | ||
if (cur.left === null || cur.right === null) { | ||
// 当子结点数量 = 0 / 1 时, child = null / 该子结点 | ||
let child = cur.left !== null ? cur.left : cur.right; | ||
// 删除结点 cur | ||
if (pre!.left === cur) { | ||
pre!.left = child; | ||
} else { | ||
pre!.right = child; | ||
} | ||
} | ||
// 子结点数量 = 2 | ||
else { | ||
// 获取中序遍历中 cur 的下一个结点 | ||
let next = min(cur.right); | ||
let tmp = next!.val; | ||
// 递归删除结点 nex | ||
remove(next!.val); | ||
// 将 nex 的值复制给 cur | ||
cur.val = tmp; | ||
} | ||
return cur; | ||
} | ||
|
||
/* 获取最小结点 */ | ||
function min(root: TreeNode | null): TreeNode | null { | ||
if (root === null) { | ||
return null; | ||
} | ||
// 循环访问左子结点,直到叶结点时为最小结点,跳出 | ||
while (root.left !== null) { | ||
root = root.left; | ||
} | ||
return root; | ||
} | ||
|
||
/* Driver Code */ | ||
/* 初始化二叉搜索树 */ | ||
const nums = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]; | ||
BinarySearchTree(nums); | ||
console.log('\n初始化的二叉树为\n'); | ||
printTree(getRoot()); | ||
|
||
/* 查找结点 */ | ||
let node = search(5); | ||
console.log('\n查找到的结点对象为 ' + node + ',结点值 = ' + node!.val); | ||
|
||
/* 插入结点 */ | ||
node = insert(16); | ||
console.log('\n插入结点 16 后,二叉树为\n'); | ||
printTree(getRoot()); | ||
|
||
/* 删除结点 */ | ||
remove(1); | ||
console.log('\n删除结点 1 后,二叉树为\n'); | ||
printTree(getRoot()); | ||
remove(2); | ||
console.log('\n删除结点 2 后,二叉树为\n'); | ||
printTree(getRoot()); | ||
remove(4); | ||
console.log('\n删除结点 4 后,二叉树为\n'); | ||
printTree(getRoot()); | ||
|
||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
/** | ||
* File: binary_tree.ts | ||
* Created Time: 2022-12-13 | ||
* Author: Justin ([email protected]) | ||
*/ | ||
|
||
import { TreeNode } from '../module/TreeNode'; | ||
import { printTree } from '../module/PrintUtil'; | ||
|
||
/* 初始化二叉树 */ | ||
// 初始化结点 | ||
let n1 = new TreeNode(1), | ||
n2 = new TreeNode(2), | ||
n3 = new TreeNode(3), | ||
n4 = new TreeNode(4), | ||
n5 = new TreeNode(5); | ||
// 构建引用指向(即指针) | ||
n1.left = n2; | ||
n1.right = n3; | ||
n2.left = n4; | ||
n2.right = n5; | ||
console.log('\n初始化二叉树\n'); | ||
printTree(n1); | ||
|
||
/* 插入与删除结点 */ | ||
const P = new TreeNode(0); | ||
// 在 n1 -> n2 中间插入结点 P | ||
n1.left = P; | ||
P.left = n2; | ||
console.log('\n插入结点 P 后\n'); | ||
printTree(n1); | ||
// 删除结点 P | ||
n1.left = n2; | ||
console.log('\n删除结点 P 后\n'); | ||
printTree(n1); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
/** | ||
* File: binary_tree_bfs.ts | ||
* Created Time: 2022-12-14 | ||
* Author: Justin ([email protected]) | ||
*/ | ||
|
||
import { type TreeNode } from '../module/TreeNode'; | ||
import { arrToTree } from '../module/TreeNode'; | ||
import { printTree } from '../module/PrintUtil'; | ||
|
||
/* 层序遍历 */ | ||
function hierOrder(root: TreeNode | null): number[] { | ||
// 初始化队列,加入根结点 | ||
const queue = [root]; | ||
// 初始化一个列表,用于保存遍历序列 | ||
const list: number[] = []; | ||
while (queue.length) { | ||
let node = queue.shift() as TreeNode; // 队列出队 | ||
list.push(node.val); // 保存结点 | ||
if (node.left) { | ||
queue.push(node.left); // 左子结点入队 | ||
} | ||
if (node.right) { | ||
queue.push(node.right); // 右子结点入队 | ||
} | ||
} | ||
return list; | ||
} | ||
|
||
/* Driver Code */ | ||
/* 初始化二叉树 */ | ||
// 这里借助了一个从数组直接生成二叉树的函数 | ||
var root = arrToTree([1, 2, 3, 4, 5, 6, 7, null, null, null, null, null, null, null, null]); | ||
console.log('\n初始化二叉树\n'); | ||
printTree(root); | ||
|
||
/* 层序遍历 */ | ||
const list = hierOrder(root); | ||
console.log('\n层序遍历的结点打印序列 = ' + list); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/** | ||
* File: binary_tree_dfs.ts | ||
* Created Time: 2022-12-14 | ||
* Author: Justin ([email protected]) | ||
*/ | ||
|
||
import { type TreeNode } from '../module/TreeNode'; | ||
import { arrToTree } from '../module/TreeNode'; | ||
import { printTree } from '../module/PrintUtil'; | ||
|
||
// 初始化列表,用于存储遍历序列 | ||
const list: number[] = []; | ||
|
||
/* 前序遍历 */ | ||
function preOrder(root: TreeNode | null): void { | ||
if (root === null) { | ||
return; | ||
} | ||
// 访问优先级:根结点 -> 左子树 -> 右子树 | ||
list.push(root.val); | ||
preOrder(root.left); | ||
preOrder(root.right); | ||
} | ||
|
||
/* 中序遍历 */ | ||
function inOrder(root: TreeNode | null): void { | ||
if (root === null) { | ||
return; | ||
} | ||
// 访问优先级:左子树 -> 根结点 -> 右子树 | ||
inOrder(root.left); | ||
list.push(root.val); | ||
inOrder(root.right); | ||
} | ||
|
||
/* 后序遍历 */ | ||
function postOrder(root: TreeNode | null): void { | ||
if (root === null) { | ||
return; | ||
} | ||
// 访问优先级:左子树 -> 右子树 -> 根结点 | ||
postOrder(root.left); | ||
postOrder(root.right); | ||
list.push(root.val); | ||
} | ||
|
||
/* Driver Code */ | ||
/* 初始化二叉树 */ | ||
// 这里借助了一个从数组直接生成二叉树的函数 | ||
const root = arrToTree([1, 2, 3, 4, 5, 6, 7, null, null, null, null, null, null, null, null]); | ||
console.log('\n初始化二叉树\n'); | ||
printTree(root); | ||
|
||
/* 前序遍历 */ | ||
list.length = 0; | ||
preOrder(root); | ||
console.log('\n前序遍历的结点打印序列 = ' + list); | ||
|
||
/* 中序遍历 */ | ||
list.length = 0; | ||
inOrder(root); | ||
console.log('\n中序遍历的结点打印序列 = ' + list); | ||
|
||
/* 后序遍历 */ | ||
list.length = 0; | ||
postOrder(root); | ||
console.log('\n后序遍历的结点打印序列 = ' + list); |
Oops, something went wrong.