Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit fd7da22

Browse files
committed
增加二叉搜索树的封装
1 parent d858d11 commit fd7da22

File tree

3 files changed

+317
-1
lines changed

3 files changed

+317
-1
lines changed

‎src/Tree/index.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { BinarySearchTree } from './tree';
2+
// ---------------- 封装的树结构测试 ---------------- //
3+
console.log('// ----- 树结构测试 START -----//');
4+
5+
// 二叉搜索树测试
6+
// insert() 插入
7+
const binarySearchTree = new BinarySearchTree();
8+
binarySearchTree.insert(11);
9+
binarySearchTree.insert(7);
10+
binarySearchTree.insert(5);
11+
binarySearchTree.insert(3);
12+
binarySearchTree.insert(9);
13+
binarySearchTree.insert(8);
14+
binarySearchTree.insert(10);
15+
binarySearchTree.insert(15);
16+
binarySearchTree.insert(13);
17+
binarySearchTree.insert(12);
18+
binarySearchTree.insert(14);
19+
binarySearchTree.insert(20);
20+
binarySearchTree.insert(18);
21+
binarySearchTree.insert(25);
22+
binarySearchTree.insert(19);
23+
console.log(binarySearchTree);
24+
25+
26+
console.log('前序遍历', binarySearchTree.preorderTraversal());
27+
console.log('中序遍历', binarySearchTree.inorderTraversal());
28+
console.log('后序遍历', binarySearchTree.postorderTraversal());
29+
console.log('min', binarySearchTree.min());
30+
console.log('max', binarySearchTree.max());
31+
console.log('search(98)-递归实现', binarySearchTree.search(98));
32+
console.log('search(10)-递归实现', binarySearchTree.search(10));
33+
34+
console.log('search(98)-while循环实现', binarySearchTree.search2(98));
35+
console.log('search(10)-while循环实现', binarySearchTree.search2(10));
36+
37+
console.log('remove(20)');
38+
binarySearchTree.remove(20);
39+
console.log(binarySearchTree);
40+
console.log(binarySearchTree.inorderTraversal());
41+
42+
console.log('// -----树结构测试 END -----//');
43+
44+

‎src/Tree/tree.js

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
1+
// 节点类
2+
class Node {
3+
4+
constructor(key) {
5+
this.key = key;
6+
this.left = null;
7+
this.right = null;
8+
}
9+
10+
}
11+
12+
13+
// 封装二叉搜索树(特点:左子树节点值 < 根节点,右子树节点值 > 根节点)
14+
export class BinarySearchTree {
15+
16+
constructor() {
17+
this.root = null;
18+
}
19+
20+
// insert(key) 插入数据
21+
insert(key) {
22+
const newNode = new Node(key);
23+
24+
if (this.root === null) {
25+
this.root = newNode;
26+
} else {
27+
this.insertNode(this.root, newNode);
28+
}
29+
30+
}
31+
32+
insertNode(root, node) {
33+
34+
if (node.key < root.key) { // 往左边查找插入
35+
36+
if (root.left === null) {
37+
root.left = node;
38+
} else {
39+
this.insertNode(root.left, node);
40+
}
41+
42+
} else { // 往右边查找插入
43+
44+
if (root.right === null) {
45+
root.right = node;
46+
} else {
47+
this.insertNode(root.right, node);
48+
}
49+
50+
}
51+
52+
}
53+
54+
// ----------- 二叉树遍历 ----------- //
55+
// 先序遍历(根左右 DLR)
56+
preorderTraversal() {
57+
const result = [];
58+
this.preorderTraversalNode(this.root, result);
59+
return result;
60+
}
61+
62+
preorderTraversalNode(node, result) {
63+
if (node === null) return result;
64+
result.push(node.key);
65+
this.preorderTraversalNode(node.left, result);
66+
this.preorderTraversalNode(node.right, result);
67+
}
68+
69+
// 中序遍历(左根右 LDR)
70+
inorderTraversal() {
71+
const result = [];
72+
this.inorderTraversalNode(this.root, result);
73+
return result;
74+
}
75+
76+
inorderTraversalNode(node, result) {
77+
if (node === null) return result;
78+
this.inorderTraversalNode(node.left, result);
79+
result.push(node.key);
80+
this.inorderTraversalNode(node.right, result);
81+
}
82+
83+
// 后序遍历(左右根 LRD)
84+
postorderTraversal() {
85+
const result = [];
86+
this.postorderTraversalNode(this.root, result);
87+
return result;
88+
}
89+
90+
postorderTraversalNode(node, result) {
91+
if (node === null) return result;
92+
this.postorderTraversalNode(node.left, result);
93+
this.postorderTraversalNode(node.right, result);
94+
result.push(node.key);
95+
}
96+
97+
// min() 获取二叉搜索树最小值
98+
min() {
99+
if (!this.root) return null;
100+
let node = this.root;
101+
while (node.left !== null) {
102+
node = node.left;
103+
}
104+
return node.key;
105+
}
106+
107+
// max() 获取二叉搜索树最大值
108+
max() {
109+
if (!this.root) return null;
110+
let node = this.root;
111+
while (node.right !== null) {
112+
node = node.right;
113+
}
114+
return node.key;
115+
}
116+
117+
// search(key) 查找二叉搜索树中是否有相同的key,存在返回 true,否则返回 false
118+
search(key) {
119+
return this.searchNode(this.root, key);
120+
}
121+
122+
// 通过递归实现
123+
searchNode(node, key) {
124+
if (node === null) return false;
125+
if (key < node.key) {
126+
return this.searchNode(node.left, key);
127+
} else if (key > node.key) {
128+
return this.searchNode(node.right, key);
129+
} else {
130+
return true;
131+
}
132+
}
133+
134+
// 通过 while 循环实现
135+
search2(key) {
136+
137+
let node = this.root;
138+
139+
while (node !== null) {
140+
if (key < node.key) {
141+
node = node.left;
142+
} else if (key > node.key) {
143+
node = node.right;
144+
} else {
145+
return true;
146+
}
147+
}
148+
149+
return false;
150+
151+
}
152+
153+
// 删除节点
154+
remove(key) {
155+
156+
let currentNode = this.root;
157+
let parentNode = null;
158+
let isLeftChild = true;
159+
160+
// 循环查找到要删除的节点 currentNode,以及它的 parentNode、isLeftChild
161+
while (currentNode.key !== key) {
162+
163+
parentNode = currentNode;
164+
165+
// 小于,往左查找
166+
if (key < currentNode.key) {
167+
isLeftChild = true;
168+
currentNode = currentNode.left;
169+
170+
} else { // 否则往右查找
171+
isLeftChild = false;
172+
currentNode = currentNode.right;
173+
}
174+
175+
// 找到最后都没找到相等的节点,返回 false
176+
if (currentNode === null) {
177+
return false;
178+
}
179+
180+
}
181+
182+
183+
// 1、删除的是叶子节点的情况
184+
if (currentNode.left === null && currentNode.right === null) {
185+
186+
if (currentNode === this.root) {
187+
this.root = null;
188+
} else if (isLeftChild) {
189+
parentNode.left = null;
190+
} else {
191+
parentNode.right = null;
192+
}
193+
194+
195+
// 2、删除的是只有一个子节点的节点
196+
} else if (currentNode.right === null) { // currentNode 只存在左节点
197+
//-- 2.1、currentNode 只存在<左节点>的情况
198+
//---- 2.1.1、currentNode 等于 root
199+
//---- 2.1.2、parentNode.left 等于 currentNode
200+
//---- 2.1.3、parentNode.right 等于 currentNode
201+
202+
if (currentNode === this.root) {
203+
this.root = currentNode.left;
204+
} else if (isLeftChild) {
205+
parentNode.left = currentNode.left;
206+
} else {
207+
parentNode.right = currentNode.left;
208+
}
209+
210+
} else if (currentNode.left === null) { // currentNode 只存在右节点
211+
//-- 2.2、currentNode 只存在<右节点>的情况
212+
//---- 2.1.1 currentNode 等于 root
213+
//---- 2.1.1 parentNode.left 等于 currentNode
214+
//---- 2.1.1 parentNode.right 等于 currentNode
215+
216+
if (currentNode === this.root) {
217+
this.root = currentNode.right;
218+
} else if (isLeftChild) {
219+
parentNode.left = currentNode.right;
220+
} else {
221+
parentNode.right = currentNode.right;
222+
}
223+
224+
225+
// 3、删除的是有两个子节点的节点
226+
} else {
227+
228+
// 1、找到后续节点
229+
let successor = this.getSuccessor(currentNode);
230+
231+
// 2、判断是否为根节点
232+
if (currentNode === this.root) {
233+
this.root = successor;
234+
} else if (isLeftChild) {
235+
parentNode.left = successor;
236+
} else {
237+
parentNode.right = successor;
238+
}
239+
240+
// 3、将后续的左节点改为被删除的左节点
241+
successor.left = currentNode.left;
242+
}
243+
}
244+
245+
// 获取后续节点,即从要删除的节点的右边开始查找最小的值
246+
getSuccessor(delNode) {
247+
248+
// 定义变量,保存要找到的后续
249+
let successor = delNode;
250+
let current = delNode.right;
251+
let successorParent = delNode;
252+
253+
// 循环查找 current 的右子树节点
254+
while (current !== null) {
255+
successorParent = successor;
256+
successor = current;
257+
current = current.left;
258+
}
259+
260+
// 判断寻找到的后续节点是否直接就是要删除节点的 right
261+
if (successor !== delNode.right) {
262+
successorParent.left = successor.right;
263+
successor.right = delNode.right;
264+
}
265+
return successor;
266+
}
267+
268+
269+
}

‎src/index.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,7 @@
2020
// import './Map'
2121

2222
// 导入哈希表结构的封装及测试代码
23-
import './HashTable';
23+
// import './HashTable';
24+
25+
// 导入树结构的封装及测试代码
26+
import './Tree';

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /