From 04f1f7712e2bee04ad1371c8f9d25b133de2e7e3 Mon Sep 17 00:00:00 2001
From: kevin <18392136187@163.com>
Date: Mon, 8 May 2023 23:20:53 +0800
Subject: [PATCH] =?UTF-8?q?docs:=20=E4=BF=AE=E6=94=B9=E5=86=B2=E7=AA=81=20?=
=?UTF-8?q?feat:=20add=20BinaryTree=20(#50)?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
* docs: 修改(prettier/prettier) 报错
* docs: update README.md
* docs: update no-console 报 error
* docs: update no-constant-condition 报 error
* docs: update no-constant-condition 报 error
* docs: 添加 IPv6 正则表达式
* docs: 添加 IPv6 正则表达式
* docs: delete no-console
* docs: dele ipv6
* feat: 添加数据脱敏
* feat: 添加数据脱敏
* feat: 添加数据脱敏
* feat: 添加 双向链表
* fix: 修改冲突
* feat: add 表单数据转成JSON
* feat: add 表单数据转成JSON
* fix: 修改build报错
* docs: prefer-const
* docs: add BothLinkedList index.md
* feat: add BinaryTree
* feat: add BinaryTree
---
.eslintrc | 2 +-
src/BinaryTree/index.md | 50 +++++++++
src/BinaryTree/index.ts | 206 ++++++++++++++++++++++++++++++++++++
src/BothLinkedList/index.md | 44 ++++++++
src/BothLinkedList/index.ts | 175 ++++++++++++++++++++++++++++++
src/index.ts | 3 +-
test/format.test.js | 22 +++-
7 files changed, 499 insertions(+), 3 deletions(-)
create mode 100644 src/BinaryTree/index.md
create mode 100644 src/BinaryTree/index.ts
create mode 100644 src/BothLinkedList/index.md
create mode 100644 src/BothLinkedList/index.ts
diff --git a/.eslintrc b/.eslintrc
index 139395b..262c2ed 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -20,7 +20,7 @@
"@typescript-eslint/no-explicit-any": "off",
"no-constant-condition": "off",
"@typescript-eslint/no-this-alias": "off",
- "prefer-const": "off",
+ "prefer-const": "off"
},
"ignorePatterns": ["**/*.test.js"]
}
diff --git a/src/BinaryTree/index.md b/src/BinaryTree/index.md
new file mode 100644
index 0000000..0c1b0e2
--- /dev/null
+++ b/src/BinaryTree/index.md
@@ -0,0 +1,50 @@
+---
+title: BinaryTree - 二叉树
+nav:
+ title: 使用文档
+ path: /lib
+group:
+ path: /format
+ title: 数据结构相关
+ order: 2
+---
+
+## BinaryTree
+
+> 二叉树
+>
+> bt.insert(param): param 是 需要插入的元素
+> bt.find(param): param 是 需要寻找的元素,返回值为所找到的节点
+> bt.removeNode(param): param 需要删除的元素
+> bt.getRoot(): 获取二叉树的根节点
+> bt.getMinNode(): 获取二叉树 某个节点的最小值
+> bt.getMaxNode(): 获取二叉树 某个节点的最小值
+> bt.preOrderTraversal(bt.getRoot()): 需要传入进行遍历的节点, 遍历结束之后, 可以通过 bt.getRoot().preOrder 获取先序遍历的结果集
+> bt.centerOrderTraversal(bt.getRoot()): 需要传入进行遍历的节点, 遍历结束之后, 可以通过 bt.getRoot().centerOrder 获取中序遍历的结果集
+> bt.postOrderTraversal(bt.getRoot()): 需要传入进行遍历的节点, 遍历结束之后, 可以通过 bt.getRoot().postOrder 获取后序遍历的结果集
+
+Demo:
+
+```tsx | pure
+import { BinaryTree } from 'xijs';
+const bt = new BinaryTree();
+bt.insert(1);
+bt.insert(2);
+bt.insert(0);
+// bt.insert(4);
+// bt.insert(-1);
+
+const res = bt.find(2);
+console.log('find: ', res)
+bt.removeNode(2)
+console.log('getRoot: ', bt.getRoot())
+console.log('getMinNode: ', bt.getMinNode())
+console.log('getMaxNode: ', bt.getMaxNode())
+bt.preOrderTraversal(bt.getRoot())
+bt.centerOrderTraversal(bt.getRoot())
+bt.postOrderTraversal(bt.getRoot())
+console.log(`preOrder: `, bt.getRoot().preOrder)
+console.log(`centerOrder: `, bt.getRoot().centerOrder)
+console.log(`postOrder: `, bt.getRoot().postOrder)
+
+```
diff --git a/src/BinaryTree/index.ts b/src/BinaryTree/index.ts
new file mode 100644
index 0000000..180126c
--- /dev/null
+++ b/src/BinaryTree/index.ts
@@ -0,0 +1,206 @@
+/**
+ * 定义二叉树的结构
+ */
+class TreeNode {
+ data: T;
+ left: TreeNode | undefined;
+ right: TreeNode | undefined;
+ count = 0;
+ preOrder: Array = [];
+ centerOrder: Array = [];
+ postOrder: Array = [];
+ constructor(
+ data: T,
+ left: TreeNode | undefined,
+ right: TreeNode | undefined,
+ ) {
+ this.data = data;
+ this.left = left;
+ this.right = right;
+ }
+}
+
+/**
+ * 定义二叉树的操作
+ */
+class BinaryTree {
+ root: TreeNode | undefined;
+
+ constructor() {
+ this.root = undefined;
+ }
+
+ insert(data: T): void {
+ const newTreeNode: TreeNode = new TreeNode(data, undefined, undefined);
+ if (this.root === undefined) {
+ this.root = newTreeNode;
+ this.root.count++;
+ } else {
+ let curNode = this.root;
+ let parentNode = undefined;
+ while (true) {
+ parentNode = curNode;
+ if (curNode.data > data) {
+ curNode = curNode.left!;
+ if (!curNode) {
+ parentNode.left = newTreeNode;
+ this.root.count++;
+ break;
+ }
+ } else if (curNode.data < data) {
+ curNode = curNode.right!;
+ if (!curNode) {
+ parentNode.right = newTreeNode;
+ this.root.count++;
+ break;
+ }
+ } else if (newTreeNode.data === curNode.data) {
+ // 如果给定的数据再次出现,就更新计数值
+ curNode.count++;
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * 根据元素值 寻找 节点
+ * @param data
+ */
+ find(data: T): TreeNode | undefined {
+ let currNode: TreeNode | undefined = this.root;
+ while (currNode) {
+ if (currNode.data == data) {
+ return currNode;
+ } else if (data < currNode.data) {
+ currNode = currNode.left;
+ } else {
+ currNode = currNode.right;
+ }
+ }
+ return undefined;
+ }
+
+ /**
+ * 获取根节点
+ */
+ getRoot(): TreeNode | undefined {
+ return this.root;
+ }
+
+ /**
+ * 删除节点
+ */
+ removeNode(data: T) {
+ this._removeNode(this.root, data);
+ }
+ _removeNode(
+ curNode: TreeNode | undefined,
+ data: T,
+ ): TreeNode | undefined {
+ if (curNode === undefined) {
+ return undefined;
+ }
+ if (curNode.data === data) {
+ /**
+ * 左子树和右子树都为空,说明是叶子节点,可以直接删除
+ */
+ if (curNode.left === undefined && curNode.right === undefined) {
+ return undefined;
+ }
+ if (curNode.left === undefined) {
+ return curNode.right;
+ }
+ if (curNode.right === undefined) {
+ return curNode.left;
+ }
+ /**
+ * 如果两个节点都存在,则需要寻找右子树上的最小值,因为二叉树从左子树到根节点再到右子树,是从小到大排序
+ */
+ let tmpNode = this.getMinNode(curNode.right);
+ curNode.data = tmpNode.data;
+ curNode.right = this._removeNode(curNode.right, tmpNode.data);
+ this.root!.count--;
+ return curNode;
+ } else if (curNode.data > data) {
+ /**
+ * 如果当前节点值 > 需要寻找的 data,则需要在左子树继续寻找
+ */
+ curNode.left = this._removeNode(curNode.left, data);
+ this.root!.count--;
+ return curNode;
+ } else if (curNode.data < data) {
+ /**
+ * 如果当前节点值 < 需要寻找的 data,则需要在右子树继续寻找
+ */
+ curNode.right = this._removeNode(curNode.right, data);
+ this.root!.count--;
+ return curNode;
+ }
+ }
+
+ /**
+ * 获取最大节点
+ * @param curNode
+ */
+ getMaxNode(node = this.root!) {
+ let curNode = node;
+ while (curNode.right) {
+ curNode = curNode.right;
+ }
+ return curNode;
+ }
+
+ /**
+ * 获取最小节点
+ * @param curNode
+ */
+ getMinNode(node = this.root!) {
+ let curNode = node;
+ while (curNode.left) {
+ curNode = curNode.left;
+ }
+ return curNode;
+ }
+
+ /**
+ * 先序遍历,遍历结束之后,可以通过 bt.getRoot().preOrder 获取遍历以后的元素数组
+ * @param root
+ */
+ preOrderTraversal(root: TreeNode) {
+ if (root === undefined) {
+ return undefined;
+ }
+ this.preOrderTraversal(root.left!);
+ this.root!.preOrder.push(root.data);
+ this.preOrderTraversal(root.right!);
+ }
+
+ /**
+ * 中序遍历,遍历结束之后,可以通过 bt.getRoot().centerOrder 获取遍历以后的元素数组
+ * @param root
+ */
+ centerOrderTraversal(root: TreeNode) {
+ if (root === undefined) {
+ return undefined;
+ }
+ this.root!.centerOrder.push(root.data);
+ this.centerOrderTraversal(root.left!);
+ this.centerOrderTraversal(root.right!);
+ }
+
+ /**
+ * 后序遍序遍历,遍历结束之后,可以通过 bt.getRoot().postOrder 获取遍历以后的元素数组
+ * @param root
+ */
+ postOrderTraversal(root: TreeNode) {
+ if (root === undefined) {
+ return undefined;
+ }
+ this.postOrderTraversal(root.left!);
+ this.postOrderTraversal(root.right!);
+ this.root!.postOrder.push(root.data);
+ }
+}
+
+export default BinaryTree;
diff --git a/src/BothLinkedList/index.md b/src/BothLinkedList/index.md
new file mode 100644
index 0000000..5a4387d
--- /dev/null
+++ b/src/BothLinkedList/index.md
@@ -0,0 +1,44 @@
+---
+title: bothLinkedList - 双向链表
+nav:
+ title: 使用文档
+ path: /lib
+group:
+ path: /format
+ title: 数据结构相关
+ order: 2
+---
+
+## bothLinkedList
+
+> 双向链表
+>
+> bothLinkedList.insertHead(param): param 是 需要插入的元素,插入到元素链表尾部
+> bothLinkedList.insertIndex(param, index): param 是 需要插入的元素,index: 需要插入的位置
+> bothLinkedList.getHead(): 从头开始遍历链表
+> bothLinkedList.getTail(): 从尾开始遍历链表
+> bothLinkedList.getData(index): index: 通过索引获取元素值
+> bothLinkedList.getSize(): 获取链表长度
+> bothLinkedList.deleteFrom(index): index 通过索引删除元素节点
+> bothLinkedList.deleteData(param): index 通过元素值删除元素节点
+>
+> 返回值:Node 类型:
+>
+> { data: 1, next: undefined, prev: undefined }
+
+Demo:
+
+```tsx | pure
+import { BothLinkedList } from 'xijs';
+
+let bothLinkedList = new BothLinkedList()
+bothLinkedList.insertHead(1);
+bothLinkedList.insertHead(2);
+// bothLinkedList.insertHead(3)
+console.log(bothLinkedList.getHead())
+bothLinkedList.deleteFrom(1)
+bothLinkedList.deleteData(1)
+console.log(bothLinkedList.getHead())
+// console.log(bothLinkedList.getTail())
+// console.log(bothLinkedList.getData(3))
+```
diff --git a/src/BothLinkedList/index.ts b/src/BothLinkedList/index.ts
new file mode 100644
index 0000000..ab7867a
--- /dev/null
+++ b/src/BothLinkedList/index.ts
@@ -0,0 +1,175 @@
+/**
+ * 定义链表结构
+ * @param data
+ * @param next
+ * @constructor
+ */
+class Node {
+ data: T;
+ next: Node | undefined;
+ prev: Node | undefined;
+
+ constructor(data: T) {
+ this.data = data;
+ }
+}
+class BothLinkedList {
+ private head: Node | undefined;
+ private tail: Node | undefined;
+ private size = 0;
+
+ /**
+ * 插入元素 采用尾插法
+ * @param data
+ */
+ insertHead(data: T): void {
+ const node = new Node(data);
+ if (this.size === 0) {
+ this.head = node;
+ this.tail = node;
+ } else {
+ node.prev = this.tail;
+ this.tail!.next = node;
+ this.tail = node;
+ }
+ this.size++;
+ }
+
+ /**
+ * 根据索引插入元素
+ * @param data
+ * @param index
+ */
+ insertIndex(data: T, index: number): void {
+ if (index < 0 || index > this.size) {
+ throw new Error('要插入的索引已经超过了链表的最大长度');
+ }
+ const node = new Node(data);
+ /**
+ * 如果链表为空,直接插入
+ */
+ if (this.head === null) {
+ this.head = node;
+ this.tail = node;
+ }
+ /**
+ * 如果 index === 0 则插入的位置是头
+ * 如果 index === this.size 则插入的位置是尾
+ */
+ if (index === 0) {
+ node.next = this.head;
+ this.head!.prev = node;
+ this.head = node;
+ } else if (index === this.size) {
+ node.prev = this.tail;
+ this.tail!.next = node;
+ this.tail = node;
+ } else {
+ let current = this.head!;
+ for (let i = 0; i < index - 1; i++) {
+ current = current.next!;
+ }
+ node.prev = current;
+ node.next = current.next;
+ current.next!.prev = node;
+ current.next = node;
+ }
+ this.size++;
+ }
+
+ /**
+ * 删除元素(根据元素值进行删除)
+ */
+ deleteData(data: T): void {
+ if (this.size === 0) {
+ throw Error('双向链表为空,不能删除');
+ }
+ let current = this.head!;
+ while (current) {
+ if (current.data === data) {
+ if (this.size === 1) {
+ this.head = undefined;
+ this.tail = undefined;
+ } else if (current === this.head) {
+ this.head = this.head!.next;
+ this.head!.prev = undefined;
+ } else if (current === this.tail) {
+ this.tail = this.tail!.prev;
+ this.tail!.next = undefined;
+ } else {
+ current.prev!.next = current.next;
+ current.next!.prev = current.prev;
+ }
+
+ this.size--;
+ return;
+ }
+ current = current!.next!;
+ }
+ }
+
+ /**
+ * 根据元素索引删除
+ * @param index
+ */
+ deleteFrom(index: number): void {
+ if (index < 0 || index >= this.size) {
+ throw new Error('双向链表越界');
+ }
+ if (this.size === 1) {
+ this.head = undefined;
+ this.tail = undefined;
+ } else if (index === 0) {
+ this.head = this.head!.next!;
+ this.head!.prev = undefined;
+ } else if (index === this.size - 1) {
+ this.tail = this.tail!.prev;
+ this.tail!.next = undefined;
+ } else {
+ let current = this.head!;
+ for (let i = 0; i < index; i++) {
+ current = current.next!;
+ }
+ current.prev!.next = current.next;
+ current.next!.prev = current.prev;
+ }
+ this.size--;
+ }
+
+ /**
+ * 正向遍历
+ */
+ getHead(): Node | undefined {
+ return this.head;
+ }
+
+ /**
+ * 反向遍历
+ */
+ getTail(): Node | undefined {
+ return this.tail;
+ }
+
+ /**
+ * 获取链表长度
+ */
+ getSize(): number {
+ return this.size;
+ }
+
+ /**
+ * 更具索引,获取元素值
+ * @param index
+ */
+ getData(index: number): T | undefined {
+ if (index < 0 || index >= this.size) {
+ throw Error('要查找的索引已经超过了链表的最大长度');
+ }
+ let current = this.head;
+ for (let i = 0; i < index; i++) {
+ current = current!.next;
+ }
+ return current!.data;
+ }
+}
+export default BothLinkedList;
diff --git a/src/index.ts b/src/index.ts
index 7740452..e39aca4 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -75,8 +75,9 @@ export { default as completeIp } from './completeIp';
export { default as capitalizedAmount } from './capitalizedAmount';
export { default as dataDesensitization } from './dataDesensitization';
-// export { default as BothLinkedList } from './BothLinkedList';
+export { default as BothLinkedList } from './BothLinkedList';
export { default as XCookie } from './XCookie';
export { default as formDataToJson } from './formDataToJson';
+export { default as BinaryTree } from './BinaryTree';
diff --git a/test/format.test.js b/test/format.test.js
index 9c24eff..8803fcf 100644
--- a/test/format.test.js
+++ b/test/format.test.js
@@ -10,7 +10,8 @@ import {
dateCalculate,
timeSub,
timeCutStr,
- formDataToJson
+ formDataToJson,
+ BinaryTree
} from '../src/index';
describe('数据结构相关测试', () => {
test('数据深拷贝', () => {
@@ -280,4 +281,23 @@ describe('数据结构相关测试', () => {
const data1 = new FormData();
expect(formDataToJson(data1)).toEqual('{}');
})
+
+ test('二叉树', () => {
+ const bt = new BinaryTree();
+ expect(bt.insert(1)).toEqual();
+ expect(bt.getRoot()).toEqual({"centerOrder": [], "count": 1, "data": 1, "left": undefined, "postOrder": [], "preOrder": [], "right": undefined});
+ expect(bt.insert(2)).toEqual();
+ expect(bt.insert(0)).toEqual();
+ expect(bt.find(2)).toEqual({"centerOrder": [], "count": 0, "data": 2, "left": undefined, "postOrder": [], "preOrder": [], "right": undefined});
+ expect(bt.getMinNode(bt.getRoot())).toEqual({"centerOrder": [], "count": 0, "data": 0, "left": undefined, "postOrder": [], "preOrder": [], "right": undefined});
+ expect(bt.getMaxNode(bt.getRoot())).toEqual({"centerOrder": [], "count": 0, "data": 2, "left": undefined, "postOrder": [], "preOrder": [], "right": undefined});
+ expect(bt.removeNode(2)).toEqual(undefined);
+ bt.insert(2)
+ bt.preOrderTraversal(bt.getRoot())
+ bt.centerOrderTraversal(bt.getRoot())
+ bt.postOrderTraversal(bt.getRoot())
+ expect(bt.getRoot().preOrder).toEqual([0, 1, 2]);
+ expect(bt.getRoot().centerOrder).toEqual([1, 0, 2]);
+ expect(bt.getRoot().postOrder).toEqual([0, 2, 1]);
+ })
});