Skip to content

Commit e883613

Browse files
committed
init
0 parents  commit e883613

22 files changed

+2230
-0
lines changed

.gitignore

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
.DS_Store
2+
node_modules/
3+
dist/
4+
CONTRIBUTING.md
5+
npm-debug.log
6+
yarn-debug.log*
7+
yarn-error.log*
8+
yarn.lock
9+
package-lock.json
10+
test/unit/coverage
11+
test/e2e/reports
12+
selenium-debug.log
13+
14+
# Editor directories and files
15+
.idea
16+
.vscode
17+
*.suo
18+
*.ntvs*
19+
*.njsproj
20+
*.sln
21+

BinarySearchTree.js

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

O(n).jpg

141 KB
Loading

demo.html

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<!--
2+
* @Descripttion:
3+
* @version:
4+
* @Author: wenlan
5+
* @Date: 2022-03-22 17:00:05
6+
* @LastEditors: wenlan
7+
* @LastEditTime: 2022-03-24 22:49:01
8+
-->
9+
<!DOCTYPE html>
10+
<html lang="en">
11+
<head>
12+
<meta charset="UTF-8" />
13+
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
14+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
15+
<title>Document</title>
16+
</head>
17+
<body>
18+
<!-- <script src="./stack的封装.js"></script> -->
19+
<!-- <script src="./queue封装.js"></script> -->
20+
<!-- <script src="./双向链表.js"></script> -->
21+
<!-- <script src="./hash表封装.js"></script> -->
22+
<script src="./BinarySearchTree.js"></script>
23+
</body>
24+
</html>

0 commit comments

Comments
 (0)