mirror of
https://github.com/zrwusa/data-structure-typed.git
synced 2024-11-23 12:54:04 +00:00
Merge branch 'main' into rbtree
This commit is contained in:
commit
a0c9c17345
|
@ -3,6 +3,7 @@ module.exports = {
|
|||
"plugin:@typescript-eslint/recommended",
|
||||
"prettier"
|
||||
],
|
||||
ignorePatterns: ["lib/", "dist/", "umd/", "coverage/", "docs/"],
|
||||
"rules": {
|
||||
"import/no-anonymous-default-export": "off",
|
||||
"@typescript-eslint/no-unused-vars": "error",
|
||||
|
|
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
38
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. iOS]
|
||||
- Browser [e.g. chrome, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Smartphone (please complete the following information):**
|
||||
- Device: [e.g. iPhone6]
|
||||
- OS: [e.g. iOS8.1]
|
||||
- Browser [e.g. stock browser, safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
10
.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
10
.github/ISSUE_TEMPLATE/custom.md
vendored
Normal file
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
name: Custom issue template
|
||||
about: Describe this issue template's purpose here.
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
19
.github/workflows/ci.yml
vendored
19
.github/workflows/ci.yml
vendored
|
@ -35,20 +35,5 @@ jobs:
|
|||
- name: Install dependencies
|
||||
run: npm install
|
||||
|
||||
- name: Print Environment Variables
|
||||
run: env
|
||||
|
||||
- name: Lint
|
||||
run: npm run lint
|
||||
|
||||
- name: Build and documentation
|
||||
run: npm run build
|
||||
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
|
||||
- name: Fetch Tags
|
||||
run: git fetch --tags
|
||||
|
||||
- name: Changelog
|
||||
run: npm run changelog
|
||||
- name: Combined ci commands together
|
||||
run: npm run ci
|
||||
|
|
|
@ -10,8 +10,7 @@
|
|||
/backup
|
||||
|
||||
/webpack.config.js
|
||||
|
||||
/rename_clear_files.sh
|
||||
/scripts
|
||||
/tsconfig.prod.json
|
||||
|
||||
/docs
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
src/types/data-structures/abstract-binary-tree.ts
|
||||
src/types/data-structures/binary-tree.ts
|
||||
src/types/data-structures/bst.ts
|
||||
src/types/data-structures/avl-tree.ts
|
||||
src/types/data-structures/tree-multiset.ts
|
||||
src/types/data-structures/rb-tree.ts
|
||||
src/types/data-structures/tree-multiset.ts
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "19"
|
||||
- "19.9.0"
|
||||
install:
|
||||
- npm build
|
||||
- npm install
|
||||
script:
|
||||
- npm run lint
|
||||
- npm run test
|
||||
- npm run ci
|
||||
deploy:
|
||||
provider: npm
|
||||
email: zrwusa@gmail.com
|
||||
|
|
17
CHANGELOG.md
17
CHANGELOG.md
|
@ -8,7 +8,22 @@ All notable changes to this project will be documented in this file.
|
|||
- [Semantic Versioning](https://semver.org/spec/v2.0.0.html)
|
||||
- [`auto-changelog`](https://github.com/CookPete/auto-changelog)
|
||||
|
||||
## [v1.34.5](https://github.com/zrwusa/data-structure-typed/compare/v1.34.1...main) (upcoming)
|
||||
## [v1.36.5](https://github.com/zrwusa/data-structure-typed/compare/v1.35.0...main) (upcoming)
|
||||
|
||||
### Changes
|
||||
|
||||
- [trie] renamed ambiguous methods and add comments to all methods. [`#12`](https://github.com/zrwusa/data-structure-typed/pull/12)
|
||||
- [binarytree] modified the getDepth method to adhere to the proper def… [`#11`](https://github.com/zrwusa/data-structure-typed/pull/11)
|
||||
- Trie [`#10`](https://github.com/zrwusa/data-structure-typed/pull/10)
|
||||
- [tree] getHeight returns faulty height bug fixed [`#9`](https://github.com/zrwusa/data-structure-typed/pull/9)
|
||||
- [trie] support casesensitivity. getWords bug fixed [`#8`](https://github.com/zrwusa/data-structure-typed/pull/8)
|
||||
- [binary-tree, graph] In order to optimize the design of Binary Trees,… [`#7`](https://github.com/zrwusa/data-structure-typed/pull/7)
|
||||
- [BinaryTree, Heap] In abstract classes, only retain abstract methods.… [`#6`](https://github.com/zrwusa/data-structure-typed/pull/6)
|
||||
- [heap] test [`#5`](https://github.com/zrwusa/data-structure-typed/pull/5)
|
||||
- [heap, priority queue] Heap improved. References #123: redesigned [`#4`](https://github.com/zrwusa/data-structure-typed/pull/4)
|
||||
- test [`#3`](https://github.com/zrwusa/data-structure-typed/pull/3)
|
||||
|
||||
## [v1.35.0](https://github.com/zrwusa/data-structure-typed/compare/v1.34.1...v1.35.0) (11 October 2023)
|
||||
|
||||
## [v1.34.1](https://github.com/zrwusa/data-structure-typed/compare/v1.33.4...v1.34.1) (6 October 2023)
|
||||
|
||||
|
|
18
CONTRIBUTING.md
Normal file
18
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,18 @@
|
|||
## Contributing
|
||||
|
||||
**General Rules**
|
||||
|
||||
- As much as possible, try to follow the existing format of markdown and code.
|
||||
- Don't forget to run `npm run lint` and `npm test` before submitting pull requests.
|
||||
- Make sure that **100%** of your code is covered by tests.
|
||||
|
||||
|
||||
**Contributing New Data Structures**
|
||||
|
||||
- Make your pull requests to be **specific** and **focused**. Instead of
|
||||
contributing "several data structures" all at once contribute them all
|
||||
one by one separately (i.e. one pull request for "RBTree", another one
|
||||
for "AATree" and so on).
|
||||
- Provide **README.md** for each of the data structure **with explanations** of
|
||||
the algorithm and **with links** to further readings.
|
||||
- Describe what you do in code using **comments**.
|
396
README.md
396
README.md
|
@ -1,18 +1,20 @@
|
|||
# Data Structure Typed
|
||||
|
||||
![NPM](https://img.shields.io/npm/l/data-structure-typed)
|
||||
![GitHub top language](https://img.shields.io/github/languages/top/zrwusa/data-structure-typed)
|
||||
![npm](https://img.shields.io/npm/dw/data-structure-typed)
|
||||
![eslint](https://aleen42.github.io/badges/src/eslint.svg)
|
||||
![npm package minimized gzipped size (select exports)](https://img.shields.io/bundlejs/size/data-structure-typed)
|
||||
![npm bundle size](https://img.shields.io/bundlephobia/min/data-structure-typed)
|
||||
![npm](https://img.shields.io/npm/v/data-structure-typed)
|
||||
|
||||
|
||||
Data Structures of Javascript & TypeScript.
|
||||
|
||||
Do you envy C++ with [std](), Python with [collections](), and Java with [java.util]() ? Well, no need to envy anymore! JavaScript and TypeScript now have [data-structure-typed]().
|
||||
|
||||
Now you can use this library in Node.js and browser environments in CommonJS(require export.modules = ), ESModule(import export), Typescript(import export), UMD(var Queue = dataStructureTyped.Queue)
|
||||
|
||||
The size after packaging is 69 kB.
|
||||
|
||||
![License](https://img.shields.io/badge/License-MIT-blue.svg)
|
||||
![Language](https://img.shields.io/github/languages/top/zrwusa/data-structure-typed)
|
||||
![GitHub release (latest by date)](https://img.shields.io/github/v/release/zrwusa/data-structure-typed)
|
||||
![npm](https://aleen42.github.io/badges/src/npm.svg)
|
||||
![eslint](https://aleen42.github.io/badges/src/eslint.svg)
|
||||
|
||||
[//]: # (![Branches](https://img.shields.io/badge/branches-55.47%25-red.svg?style=flat))
|
||||
|
||||
|
@ -33,7 +35,7 @@ Floyd-Warshall Algorithm, Tarjan's Algorithm.
|
|||
### npm
|
||||
|
||||
```bash
|
||||
npm i data-structure-typed
|
||||
npm i data-structure-typed --save
|
||||
```
|
||||
|
||||
### yarn
|
||||
|
@ -107,7 +109,7 @@ bst.getLeftMost()?.id === 1; // true
|
|||
bst.remove(6);
|
||||
bst.get(6); // null
|
||||
bst.isAVLBalanced(); // true
|
||||
bst.BFS()[0] === 11; // true
|
||||
bst.bfs()[0] === 11; // true
|
||||
|
||||
const objBST = new BST<BSTNode<{id: number, keyA: number}>>();
|
||||
objBST.add(11, {id: 11, keyA: 11});
|
||||
|
@ -143,7 +145,7 @@ expect(leftMost?.id).toBe(1);
|
|||
bst.remove(6);
|
||||
bst.get(6); // null
|
||||
bst.isAVLBalanced(); // true or false
|
||||
const bfsIDs = bst.BFS();
|
||||
const bfsIDs = bst.bfs();
|
||||
bfsIDs[0] === 11; // true
|
||||
expect(bfsIDs[0]).toBe(11);
|
||||
|
||||
|
@ -424,178 +426,215 @@ Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id) // ['A', 'B', 'D
|
|||
|
||||
### Standard library data structure comparison
|
||||
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Data Structure</th>
|
||||
<th>C++ std</th>
|
||||
<th>Data Structure Typed</th>
|
||||
<th>java.util</th>
|
||||
<th>Python collections</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>Data Structure</th>
|
||||
<th>Data Structure Typed</th>
|
||||
<th>C++ std</th>
|
||||
<th>java.util</th>
|
||||
<th>Python collections</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Dynamic Array</td>
|
||||
<td>std::vector<T></td>
|
||||
<td>Array<E></td>
|
||||
<td>ArrayList<E></td>
|
||||
<td>list</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linked List</td>
|
||||
<td>std::list<T></td>
|
||||
<td>DoublyLinkedList<E></td>
|
||||
<td>LinkedList<E></td>
|
||||
<td>deque</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Set</td>
|
||||
<td>std::set<T></td>
|
||||
<td>Set<E></td>
|
||||
<td>HashSet<E></td>
|
||||
<td>set</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Map</td>
|
||||
<td>std::map<K, V></td>
|
||||
<td>Map<K, V></td>
|
||||
<td>HashMap<K, V></td>
|
||||
<td>dict</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unordered Set</td>
|
||||
<td>std::unordered_set<T></td>
|
||||
<td>N/A</td>
|
||||
<td>HashSet<E></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unordered Map</td>
|
||||
<td>std::unordered_map<K, V></td>
|
||||
<td>HashMap<K, V></td>
|
||||
<td>HashMap<K, V></td>
|
||||
<td>defaultdict</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Queue</td>
|
||||
<td>std::queue<T></td>
|
||||
<td>Queue<E></td>
|
||||
<td>Queue<E></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Priority Queue</td>
|
||||
<td>std::priority_queue<T></td>
|
||||
<td>PriorityQueue<E></td>
|
||||
<td>PriorityQueue<E></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack</td>
|
||||
<td>std::stack<T></td>
|
||||
<td>Stack<E></td>
|
||||
<td>Stack<E></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bitset</td>
|
||||
<td>std::bitset<N></td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deque</td>
|
||||
<td>std::deque<T></td>
|
||||
<td>Deque<E></td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multiset</td>
|
||||
<td>std::multiset<T></td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multimap</td>
|
||||
<td>std::multimap<K, V></td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unordered Multiset</td>
|
||||
<td>std::unordered_multiset</td>
|
||||
<td>N/A</td>
|
||||
<td>Counter</td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ordered Dictionary</td>
|
||||
<td>N/A</td>
|
||||
<td>Map<K, V></td>
|
||||
<td>N/A</td>
|
||||
<td>OrderedDict</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linked Hash Set</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>LinkedHashSet<E></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linked Hash Map</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>LinkedHashMap<K, V></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sorted Set</td>
|
||||
<td>N/A</td>
|
||||
<td>AVLTree</td>
|
||||
<td>TreeSet<E></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sorted Map</td>
|
||||
<td>N/A</td>
|
||||
<td>AVLTree</td>
|
||||
<td>TreeMap<K, V></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tree Set</td>
|
||||
<td>std::set</td>
|
||||
<td>AVLTree</td>
|
||||
<td>TreeSet<E></td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Persistent Collections</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>unordered multiset</td>
|
||||
<td>unordered multiset<T></td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unordered Multimap</td>
|
||||
<td>std::unordered_multimap<K, V></td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
<td>N/A</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Dynamic Array</td>
|
||||
<td>Array<E></td>
|
||||
<td>vector<T></td>
|
||||
<td>ArrayList<E></td>
|
||||
<td>list</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linked List</td>
|
||||
<td>DoublyLinkedList<E></td>
|
||||
<td>list<T></td>
|
||||
<td>LinkedList<E></td>
|
||||
<td>deque</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Singly Linked List</td>
|
||||
<td>SinglyLinkedList<E></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Set</td>
|
||||
<td>Set<E></td>
|
||||
<td>set<T></td>
|
||||
<td>HashSet<E></td>
|
||||
<td>set</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Map</td>
|
||||
<td>Map<K, V></td>
|
||||
<td>map<K, V></td>
|
||||
<td>HashMap<K, V></td>
|
||||
<td>dict</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ordered Dictionary</td>
|
||||
<td>Map<K, V></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>OrderedDict</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Queue</td>
|
||||
<td>Queue<E></td>
|
||||
<td>queue<T></td>
|
||||
<td>Queue<E></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Priority Queue</td>
|
||||
<td>PriorityQueue<E></td>
|
||||
<td>priority_queue<T></td>
|
||||
<td>PriorityQueue<E></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Heap</td>
|
||||
<td>Heap<V></td>
|
||||
<td>priority_queue<T></td>
|
||||
<td>PriorityQueue<E></td>
|
||||
<td>heapq</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Stack</td>
|
||||
<td>Stack<E></td>
|
||||
<td>stack<T></td>
|
||||
<td>Stack<E></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Deque</td>
|
||||
<td>Deque<E></td>
|
||||
<td>deque<T></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Trie</td>
|
||||
<td>Trie</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unordered Map</td>
|
||||
<td>HashMap<K, V></td>
|
||||
<td>unordered_map<K, V></td>
|
||||
<td>HashMap<K, V></td>
|
||||
<td>defaultdict</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multiset</td>
|
||||
<td>-</td>
|
||||
<td>multiset<T></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Multimap</td>
|
||||
<td>-</td>
|
||||
<td>multimap<K, V></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Binary Tree</td>
|
||||
<td>BinaryTree<K, V></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Binary Search Tree</td>
|
||||
<td>BST<K, V></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Directed Graph</td>
|
||||
<td>DirectedGraph<V, E></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Undirected Graph</td>
|
||||
<td>UndirectedGraph<V, E></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unordered Multiset</td>
|
||||
<td>-</td>
|
||||
<td>unordered_multiset</td>
|
||||
<td>-</td>
|
||||
<td>Counter</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linked Hash Set</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>LinkedHashSet<E></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linked Hash Map</td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
<td>LinkedHashMap<K, V></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sorted Set</td>
|
||||
<td>AVLTree<E></td>
|
||||
<td>-</td>
|
||||
<td>TreeSet<E></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Sorted Map</td>
|
||||
<td>AVLTree<K, V></td>
|
||||
<td>-</td>
|
||||
<td>TreeMap<K, V></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Tree Set</td>
|
||||
<td>AVLTree<E></td>
|
||||
<td>set</td>
|
||||
<td>TreeSet<E></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unordered Multimap</td>
|
||||
<td>-</td>
|
||||
<td>unordered_multimap<K, V></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Bitset</td>
|
||||
<td>-</td>
|
||||
<td>bitset<N></td>
|
||||
<td>-</td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Unordered Set</td>
|
||||
<td>-</td>
|
||||
<td>unordered_set<T></td>
|
||||
<td>HashSet<E></td>
|
||||
<td>-</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
@ -868,3 +907,4 @@ optimal approach to data structure design.
|
|||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
|
|
240
package-lock.json
generated
240
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "data-structure-typed",
|
||||
"version": "1.34.5",
|
||||
"version": "1.36.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "data-structure-typed",
|
||||
"version": "1.34.5",
|
||||
"version": "1.36.5",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/benchmark": "^2.1.3",
|
||||
|
@ -15,17 +15,17 @@
|
|||
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
||||
"@typescript-eslint/parser": "^6.7.4",
|
||||
"auto-changelog": "^2.4.0",
|
||||
"avl-tree-typed": "^1.34.1",
|
||||
"avl-tree-typed": "^1.36.4",
|
||||
"benchmark": "^2.1.4",
|
||||
"binary-tree-typed": "^1.34.1",
|
||||
"bst-typed": "^1.34.1",
|
||||
"binary-tree-typed": "^1.36.4",
|
||||
"bst-typed": "^1.36.4",
|
||||
"dependency-cruiser": "^14.1.0",
|
||||
"eslint": "^8.50.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"heap-typed": "^1.34.1",
|
||||
"heap-typed": "^1.36.4",
|
||||
"istanbul-badges-readme": "^1.8.5",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.0.3",
|
||||
|
@ -129,18 +129,18 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/compat-data": {
|
||||
"version": "7.22.20",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.22.20.tgz",
|
||||
"integrity": "sha512-BQYjKbpXjoXwFW5jGqiizJQQT/aC7pFm9Ok1OWssonuguICi264lbgMzRp2ZMmRSlfkX6DsWDDcsrctK8Rwfiw==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz",
|
||||
"integrity": "sha512-0S9TQMmDHlqAZ2ITT95irXKfxN9bncq8ZCoJhun3nHL/lLUxd2NKBJYoNGWH7S0hz6fRQwWlAWn/ILM0C70KZQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/core": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.0.tgz",
|
||||
"integrity": "sha512-97z/ju/Jy1rZmDxybphrBuI+jtJjFVoz7Mr9yUQVVVi+DNZE333uFQeMOqcCIy1x3WYBIbWftUSLmbNXNT7qFQ==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.2.tgz",
|
||||
"integrity": "sha512-n7s51eWdaWZ3vGT2tD4T7J6eJs3QoBXydv7vkUM06Bf1cbVD2Kc2UrkzhiQwobfV7NwOnQXYL7UBJ5VPU+RGoQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.0",
|
||||
|
@ -148,10 +148,10 @@
|
|||
"@babel/generator": "^7.23.0",
|
||||
"@babel/helper-compilation-targets": "^7.22.15",
|
||||
"@babel/helper-module-transforms": "^7.23.0",
|
||||
"@babel/helpers": "^7.23.0",
|
||||
"@babel/helpers": "^7.23.2",
|
||||
"@babel/parser": "^7.23.0",
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/traverse": "^7.23.0",
|
||||
"@babel/traverse": "^7.23.2",
|
||||
"@babel/types": "^7.23.0",
|
||||
"convert-source-map": "^2.0.0",
|
||||
"debug": "^4.1.0",
|
||||
|
@ -342,13 +342,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.23.1",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.1.tgz",
|
||||
"integrity": "sha512-chNpneuK18yW5Oxsr+t553UZzzAs3aZnFm4bxhebsNTeshrC95yA7l5yl7GBAG+JG1rF0F7zzD2EixK9mWSDoA==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
|
||||
"integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.22.15",
|
||||
"@babel/traverse": "^7.23.0",
|
||||
"@babel/traverse": "^7.23.2",
|
||||
"@babel/types": "^7.23.0"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -629,9 +629,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@babel/traverse": {
|
||||
"version": "7.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.0.tgz",
|
||||
"integrity": "sha512-t/QaEvyIoIkwzpiZ7aoSKK8kObQYeF7T2v+dazAYCb8SXtp58zEVkWW7zAnju8FNKNdr4ScAOEDmMItbyOmEYw==",
|
||||
"version": "7.23.2",
|
||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
|
||||
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.22.13",
|
||||
|
@ -1594,9 +1594,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/eslint": {
|
||||
"version": "8.44.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.3.tgz",
|
||||
"integrity": "sha512-iM/WfkwAhwmPff3wZuPLYiHX18HI24jU8k1ZSH7P8FHwxTjZ2P6CoX2wnF43oprR+YXJM6UUxATkNvyv/JHd+g==",
|
||||
"version": "8.44.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.44.4.tgz",
|
||||
"integrity": "sha512-lOzjyfY/D9QR4hY9oblZ76B90MYTB3RrQ4z2vBIJKj9ROCRqdkYl2gSUx1x1a4IWPjKJZLL4Aw1Zfay7eMnmnA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "*",
|
||||
|
@ -1675,10 +1675,13 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "20.8.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.3.tgz",
|
||||
"integrity": "sha512-jxiZQFpb+NlH5kjW49vXxvxTjeeqlbsnTAdBTKpzEdPs9itay7MscYXz3Fo9VYFEsfQ6LJFitHad3faerLAjCw==",
|
||||
"dev": true
|
||||
"version": "20.8.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.6.tgz",
|
||||
"integrity": "sha512-eWO4K2Ji70QzKUqRy6oyJWUeB7+g2cRagT3T/nxYibYcT4y2BDL8lqolRXjTHmkZCdJfIPaY73KbJAZmcryxTQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~5.25.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/semver": {
|
||||
"version": "7.5.3",
|
||||
|
@ -1708,16 +1711,16 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||
"version": "6.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.4.tgz",
|
||||
"integrity": "sha512-DAbgDXwtX+pDkAHwiGhqP3zWUGpW49B7eqmgpPtg+BKJXwdct79ut9+ifqOFPJGClGKSHXn2PTBatCnldJRUoA==",
|
||||
"version": "6.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.7.5.tgz",
|
||||
"integrity": "sha512-JhtAwTRhOUcP96D0Y6KYnwig/MRQbOoLGXTON2+LlyB/N35SP9j1boai2zzwXb7ypKELXMx3DVk9UTaEq1vHEw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/regexpp": "^4.5.1",
|
||||
"@typescript-eslint/scope-manager": "6.7.4",
|
||||
"@typescript-eslint/type-utils": "6.7.4",
|
||||
"@typescript-eslint/utils": "6.7.4",
|
||||
"@typescript-eslint/visitor-keys": "6.7.4",
|
||||
"@typescript-eslint/scope-manager": "6.7.5",
|
||||
"@typescript-eslint/type-utils": "6.7.5",
|
||||
"@typescript-eslint/utils": "6.7.5",
|
||||
"@typescript-eslint/visitor-keys": "6.7.5",
|
||||
"debug": "^4.3.4",
|
||||
"graphemer": "^1.4.0",
|
||||
"ignore": "^5.2.4",
|
||||
|
@ -1743,15 +1746,15 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/parser": {
|
||||
"version": "6.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.4.tgz",
|
||||
"integrity": "sha512-I5zVZFY+cw4IMZUeNCU7Sh2PO5O57F7Lr0uyhgCJmhN/BuTlnc55KxPonR4+EM3GBdfiCyGZye6DgMjtubQkmA==",
|
||||
"version": "6.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.7.5.tgz",
|
||||
"integrity": "sha512-bIZVSGx2UME/lmhLcjdVc7ePBwn7CLqKarUBL4me1C5feOd663liTGjMBGVcGr+BhnSLeP4SgwdvNnnkbIdkCw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/scope-manager": "6.7.4",
|
||||
"@typescript-eslint/types": "6.7.4",
|
||||
"@typescript-eslint/typescript-estree": "6.7.4",
|
||||
"@typescript-eslint/visitor-keys": "6.7.4",
|
||||
"@typescript-eslint/scope-manager": "6.7.5",
|
||||
"@typescript-eslint/types": "6.7.5",
|
||||
"@typescript-eslint/typescript-estree": "6.7.5",
|
||||
"@typescript-eslint/visitor-keys": "6.7.5",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1771,13 +1774,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/scope-manager": {
|
||||
"version": "6.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.4.tgz",
|
||||
"integrity": "sha512-SdGqSLUPTXAXi7c3Ob7peAGVnmMoGzZ361VswK2Mqf8UOYcODiYvs8rs5ILqEdfvX1lE7wEZbLyELCW+Yrql1A==",
|
||||
"version": "6.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.7.5.tgz",
|
||||
"integrity": "sha512-GAlk3eQIwWOJeb9F7MKQ6Jbah/vx1zETSDw8likab/eFcqkjSD7BI75SDAeC5N2L0MmConMoPvTsmkrg71+B1A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.7.4",
|
||||
"@typescript-eslint/visitor-keys": "6.7.4"
|
||||
"@typescript-eslint/types": "6.7.5",
|
||||
"@typescript-eslint/visitor-keys": "6.7.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
|
@ -1788,13 +1791,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/type-utils": {
|
||||
"version": "6.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.4.tgz",
|
||||
"integrity": "sha512-n+g3zi1QzpcAdHFP9KQF+rEFxMb2KxtnJGID3teA/nxKHOVi3ylKovaqEzGBbVY2pBttU6z85gp0D00ufLzViQ==",
|
||||
"version": "6.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.7.5.tgz",
|
||||
"integrity": "sha512-Gs0qos5wqxnQrvpYv+pf3XfcRXW6jiAn9zE/K+DlmYf6FcpxeNYN0AIETaPR7rHO4K2UY+D0CIbDP9Ut0U4m1g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/typescript-estree": "6.7.4",
|
||||
"@typescript-eslint/utils": "6.7.4",
|
||||
"@typescript-eslint/typescript-estree": "6.7.5",
|
||||
"@typescript-eslint/utils": "6.7.5",
|
||||
"debug": "^4.3.4",
|
||||
"ts-api-utils": "^1.0.1"
|
||||
},
|
||||
|
@ -1815,9 +1818,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/types": {
|
||||
"version": "6.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.4.tgz",
|
||||
"integrity": "sha512-o9XWK2FLW6eSS/0r/tgjAGsYasLAnOWg7hvZ/dGYSSNjCh+49k5ocPN8OmG5aZcSJ8pclSOyVKP2x03Sj+RrCA==",
|
||||
"version": "6.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.7.5.tgz",
|
||||
"integrity": "sha512-WboQBlOXtdj1tDFPyIthpKrUb+kZf2VroLZhxKa/VlwLlLyqv/PwUNgL30BlTVZV1Wu4Asu2mMYPqarSO4L5ZQ==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": "^16.0.0 || >=18.0.0"
|
||||
|
@ -1828,13 +1831,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/typescript-estree": {
|
||||
"version": "6.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.4.tgz",
|
||||
"integrity": "sha512-ty8b5qHKatlNYd9vmpHooQz3Vki3gG+3PchmtsA4TgrZBKWHNjWfkQid7K7xQogBqqc7/BhGazxMD5vr6Ha+iQ==",
|
||||
"version": "6.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.7.5.tgz",
|
||||
"integrity": "sha512-NhJiJ4KdtwBIxrKl0BqG1Ur+uw7FiOnOThcYx9DpOGJ/Abc9z2xNzLeirCG02Ig3vkvrc2qFLmYSSsaITbKjlg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.7.4",
|
||||
"@typescript-eslint/visitor-keys": "6.7.4",
|
||||
"@typescript-eslint/types": "6.7.5",
|
||||
"@typescript-eslint/visitor-keys": "6.7.5",
|
||||
"debug": "^4.3.4",
|
||||
"globby": "^11.1.0",
|
||||
"is-glob": "^4.0.3",
|
||||
|
@ -1855,17 +1858,17 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/utils": {
|
||||
"version": "6.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.4.tgz",
|
||||
"integrity": "sha512-PRQAs+HUn85Qdk+khAxsVV+oULy3VkbH3hQ8hxLRJXWBEd7iI+GbQxH5SEUSH7kbEoTp6oT1bOwyga24ELALTA==",
|
||||
"version": "6.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.7.5.tgz",
|
||||
"integrity": "sha512-pfRRrH20thJbzPPlPc4j0UNGvH1PjPlhlCMq4Yx7EGjV7lvEeGX0U6MJYe8+SyFutWgSHsdbJ3BXzZccYggezA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@eslint-community/eslint-utils": "^4.4.0",
|
||||
"@types/json-schema": "^7.0.12",
|
||||
"@types/semver": "^7.5.0",
|
||||
"@typescript-eslint/scope-manager": "6.7.4",
|
||||
"@typescript-eslint/types": "6.7.4",
|
||||
"@typescript-eslint/typescript-estree": "6.7.4",
|
||||
"@typescript-eslint/scope-manager": "6.7.5",
|
||||
"@typescript-eslint/types": "6.7.5",
|
||||
"@typescript-eslint/typescript-estree": "6.7.5",
|
||||
"semver": "^7.5.4"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -1880,12 +1883,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@typescript-eslint/visitor-keys": {
|
||||
"version": "6.7.4",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.4.tgz",
|
||||
"integrity": "sha512-pOW37DUhlTZbvph50x5zZCkFn3xzwkGtNoJHzIM3svpiSkJzwOYr/kVBaXmf+RAQiUDs1AHEZVNPg6UJCJpwRA==",
|
||||
"version": "6.7.5",
|
||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.7.5.tgz",
|
||||
"integrity": "sha512-3MaWdDZtLlsexZzDSdQWsFQ9l9nL8B80Z4fImSpyllFC/KLqWQRdEcB+gGGO+N3Q2uL40EsG66wZLsohPxNXvg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@typescript-eslint/types": "6.7.4",
|
||||
"@typescript-eslint/types": "6.7.5",
|
||||
"eslint-visitor-keys": "^3.4.1"
|
||||
},
|
||||
"engines": {
|
||||
|
@ -2393,12 +2396,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/avl-tree-typed": {
|
||||
"version": "1.34.5",
|
||||
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.34.5.tgz",
|
||||
"integrity": "sha512-MlFgQHU0RYJJwTI2aXGRxFapjDODYqpZr+V5OGHS/NSbIQkwyJIN5Qg9YngWhqJGkQ/gdRP8zi4weFBVSwXrWA==",
|
||||
"version": "1.36.4",
|
||||
"resolved": "https://registry.npmjs.org/avl-tree-typed/-/avl-tree-typed-1.36.4.tgz",
|
||||
"integrity": "sha512-iUTsr9dfxTb4aGBxv93Teh77cCEZBsJpk7MgzvTfUwIgdO3qskj3H8xmgAxzkeRSJqIvfEGC4jil6BNP6NfSBA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"data-structure-typed": "^1.34.5"
|
||||
"data-structure-typed": "^1.36.4"
|
||||
}
|
||||
},
|
||||
"node_modules/babel-jest": {
|
||||
|
@ -2583,12 +2586,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/binary-tree-typed": {
|
||||
"version": "1.34.5",
|
||||
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.34.5.tgz",
|
||||
"integrity": "sha512-hADhuYpkUK1FogYAu2DI+X9RWwA5Jj/FU3lwghN+Mgua7i3DnEdDla5ZwtxnpGwXF1yAfzQo73+HgHW3Y67ksA==",
|
||||
"version": "1.36.4",
|
||||
"resolved": "https://registry.npmjs.org/binary-tree-typed/-/binary-tree-typed-1.36.4.tgz",
|
||||
"integrity": "sha512-fDoK2eAm+rdur+oJMBJvyjjjiQ12GpnMmbT+Bgce3tz4wnrQca6sVSEXo1uuAKTIMgDEGeVtsJmD+J6xQLqH/A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"data-structure-typed": "^1.34.5"
|
||||
"data-structure-typed": "^1.36.4"
|
||||
}
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
|
@ -2667,12 +2670,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/bst-typed": {
|
||||
"version": "1.34.5",
|
||||
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.34.5.tgz",
|
||||
"integrity": "sha512-+SlQtIyjca0YevEMSgvjODHZ//lBGX54k6HARyAPSBeK8NID0m5Zh/DXhU3BNvSwrccKy7RHvsb55JLW7Xx9vw==",
|
||||
"version": "1.36.4",
|
||||
"resolved": "https://registry.npmjs.org/bst-typed/-/bst-typed-1.36.4.tgz",
|
||||
"integrity": "sha512-3soCZc7lJV5ZhC4owO8PLx6VlHrbaFuwOWcpuiQtIDpeVh/mgAHH3M/r/YCiAxLVWXjewerG7TB4T8CBhpo1AA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"data-structure-typed": "^1.34.5"
|
||||
"data-structure-typed": "^1.36.4"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-from": {
|
||||
|
@ -2713,9 +2716,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001546",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001546.tgz",
|
||||
"integrity": "sha512-zvtSJwuQFpewSyRrI3AsftF6rM0X80mZkChIt1spBGEvRglCrjTniXvinc8JKRoqTwXAgvqTImaN9igfSMtUBw==",
|
||||
"version": "1.0.30001549",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001549.tgz",
|
||||
"integrity": "sha512-qRp48dPYSCYaP+KurZLhDYdVE+yEyht/3NlmcJgVQ2VMGt6JL36ndQ/7rgspdZsJuxDPFIo/OzBT2+GmIJ53BA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -3024,9 +3027,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/data-structure-typed": {
|
||||
"version": "1.34.5",
|
||||
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.34.5.tgz",
|
||||
"integrity": "sha512-5JtTtvzMHadRzNWHiC+jlaSIHmyC4E4Q9P4ShdnT4SfLQkHWjHFTNfrB8VEdKrQa+mZqqGPHMKEdUWCVGXG10Q==",
|
||||
"version": "1.36.4",
|
||||
"resolved": "https://registry.npmjs.org/data-structure-typed/-/data-structure-typed-1.36.4.tgz",
|
||||
"integrity": "sha512-mX+KiaCJ9apd+X7M1dJhtxvUZlV15S36QGawoQhsmhwkHdDsBT06/sGca4vE7I20pZdoX5b34GW+3z4fUJI+/g==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/debug": {
|
||||
|
@ -3076,9 +3079,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/define-data-property": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.0.tgz",
|
||||
"integrity": "sha512-UzGwzcjyv3OtAvolTj1GoyNYzfFR+iqbGjcnBEENZVCpM4/Ng1yhGNvS3lR/xDS74Tb2wGG9WzNSNIOS9UVb2g==",
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.1.tgz",
|
||||
"integrity": "sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"get-intrinsic": "^1.2.1",
|
||||
|
@ -3209,9 +3212,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.4.544",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.544.tgz",
|
||||
"integrity": "sha512-54z7squS1FyFRSUqq/knOFSptjjogLZXbKcYk3B0qkE1KZzvqASwRZnY2KzZQJqIYLVD38XZeoiMRflYSwyO4w==",
|
||||
"version": "1.4.554",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.554.tgz",
|
||||
"integrity": "sha512-Q0umzPJjfBrrj8unkONTgbKQXzXRrH7sVV7D9ea2yBV3Oaogz991yhbpfvo2LMNkJItmruXTEzVpP9cp7vaIiQ==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/emittery": {
|
||||
|
@ -4015,10 +4018,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
|
||||
"dev": true
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||
"integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/function.prototype.name": {
|
||||
"version": "1.1.6",
|
||||
|
@ -4356,12 +4362,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/heap-typed": {
|
||||
"version": "1.34.5",
|
||||
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.34.5.tgz",
|
||||
"integrity": "sha512-6THYA+LcDp6peKWQ4lg/xLPBiQBTc/Ym0frGiH43lKfINK8ilXnEYy5/KrCK6SBO9Marj7CXDuTzHXo4wbbJWw==",
|
||||
"version": "1.36.4",
|
||||
"resolved": "https://registry.npmjs.org/heap-typed/-/heap-typed-1.36.4.tgz",
|
||||
"integrity": "sha512-A5gAttFYkaXXnAjNl7gIyulmoEYB4+usGhsb1QDD2LeHGfe1Pd0wNc/mX5iLFO2feIRcl3hbRw70SQoC+/V3Fg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"data-structure-typed": "^1.34.5"
|
||||
"data-structure-typed": "^1.36.4"
|
||||
}
|
||||
},
|
||||
"node_modules/html-escaper": {
|
||||
|
@ -6514,9 +6520,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.12.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.3.tgz",
|
||||
"integrity": "sha512-geUvdk7c+eizMNUDkRpW1wJwgfOiOeHbxBR/hLXK1aT6zmVSO0jsQcs7fj6MGw89jC/cjGfLcNOrtMYtGqm81g==",
|
||||
"version": "1.13.0",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.0.tgz",
|
||||
"integrity": "sha512-HQ4J+ic8hKrgIt3mqk6cVOVrW2ozL4KdvHlqpBv9vDYWx9ysAgENAdvy4FoGF+KFdhR7nQTNm5J0ctAeOwn+3g==",
|
||||
"dev": true,
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
|
@ -7024,9 +7030,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.6",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.6.tgz",
|
||||
"integrity": "sha512-njhxM7mV12JfufShqGy3Rz8j11RPdLy4xi15UurGJeoHLfJpVXKdh3ueuOqbYUcDZnffr6X739JBo5LzyahEsw==",
|
||||
"version": "1.22.8",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||
"integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"is-core-module": "^2.13.0",
|
||||
|
@ -7348,9 +7354,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/shiki": {
|
||||
"version": "0.14.4",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.4.tgz",
|
||||
"integrity": "sha512-IXCRip2IQzKwxArNNq1S+On4KPML3Yyn8Zzs/xRgcgOWIr8ntIK3IKzjFPfjy/7kt9ZMjc+FItfqHRBg8b6tNQ==",
|
||||
"version": "0.14.5",
|
||||
"resolved": "https://registry.npmjs.org/shiki/-/shiki-0.14.5.tgz",
|
||||
"integrity": "sha512-1gCAYOcmCFONmErGTrS1fjzJLA7MGZmKzrBNX7apqSwhyITJg2O102uFzXUeBxNnEkDA9vHIKLyeKq0V083vIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"ansi-sequence-parser": "^1.1.0",
|
||||
|
@ -8209,6 +8215,12 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.25.3",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz",
|
||||
"integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/update-browserslist-db": {
|
||||
"version": "1.0.13",
|
||||
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
|
||||
|
@ -8315,9 +8327,9 @@
|
|||
"dev": true
|
||||
},
|
||||
"node_modules/webpack": {
|
||||
"version": "5.88.2",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.88.2.tgz",
|
||||
"integrity": "sha512-JmcgNZ1iKj+aiR0OvTYtWQqJwq37Pf683dY9bVORwVbUrDhLhdn/PlO2sHsFHPkj7sHNQF3JwaAkp49V+Sq1tQ==",
|
||||
"version": "5.89.0",
|
||||
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz",
|
||||
"integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/eslint-scope": "^3.7.3",
|
||||
|
|
22
package.json
22
package.json
|
@ -1,12 +1,16 @@
|
|||
{
|
||||
"name": "data-structure-typed",
|
||||
"version": "1.34.5",
|
||||
"version": "1.36.5",
|
||||
"description": "Data Structures of Javascript & TypeScript. Binary Tree, BST, Graph, Heap, Priority Queue, Linked List, Queue, Deque, Stack, AVL Tree, Tree Multiset, Trie, Directed Graph, Undirected Graph, Singly Linked List, Doubly Linked List, Max Heap, Max Priority Queue, Min Heap, Min Priority Queue.",
|
||||
"main": "dist/index.js",
|
||||
"module": "lib/index.js",
|
||||
"types": "lib/index.d.ts",
|
||||
"source": "src/index.ts",
|
||||
"umd:main": "umd/bundle.min.js",
|
||||
"exports": {
|
||||
"import": "./lib/index.js",
|
||||
"require": "./dist/index.js"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "npm run build:es6 && npm run build:commonjs && npm run build:umd && npm run build:docs",
|
||||
"build:es6": "rm -rf lib && tsc",
|
||||
|
@ -22,19 +26,19 @@
|
|||
"fix:src": "npm run lint:src && npm run format:src",
|
||||
"fix:test": "npm run lint:test && npm run format:test",
|
||||
"fix": "npm run fix:src && npm run fix:test",
|
||||
"update:test-deps": "npm i avl-tree-typed binary-tree-typed bst-typed heap-typed --save-dev",
|
||||
"update-all:test-deps": "npm i avl-tree-typed binary-tree-typed bst-typed deque-typed directed-graph-typed doubly-linked-list-typed graph-typed heap-typed linked-list-typed max-heap-typed max-priority-queue-typed min-heap-typed min-priority-queue-typed priority-queue-typed singly-linked-list-typed stack-typed tree-multiset-typed trie-typed undirected-graph-typed queue-typed --save-dev",
|
||||
"update:individuals": "npm i avl-tree-typed binary-tree-typed bst-typed heap-typed --save-dev",
|
||||
"install:individuals": "npm i avl-tree-typed binary-tree-typed bst-typed deque-typed directed-graph-typed doubly-linked-list-typed graph-typed heap-typed linked-list-typed max-heap-typed max-priority-queue-typed min-heap-typed min-priority-queue-typed priority-queue-typed singly-linked-list-typed stack-typed tree-multiset-typed trie-typed undirected-graph-typed queue-typed --save-dev",
|
||||
"test": "jest",
|
||||
"check:deps": "dependency-cruiser src",
|
||||
"changelog": "auto-changelog",
|
||||
"coverage:badge": "istanbul-badges-readme",
|
||||
"ci": "env && npm run lint && npm run build && npm run test && git fetch --tags && npm run changelog"
|
||||
"ci": "env && npm run lint && npm run build && npm run update:individuals && npm run test && git fetch --tags && npm run changelog"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/zrwusa/data-structure-typed.git"
|
||||
},
|
||||
"author": "Tyler Zeng zrwusa@gmail.com",
|
||||
"author": "Tyler Zeng <zrwusa@gmail.com>",
|
||||
"license": "MIT",
|
||||
"publishConfig": {
|
||||
"@zrwusa:registry": "https://npm.pkg.github.com"
|
||||
|
@ -50,17 +54,17 @@
|
|||
"@typescript-eslint/eslint-plugin": "^6.7.4",
|
||||
"@typescript-eslint/parser": "^6.7.4",
|
||||
"auto-changelog": "^2.4.0",
|
||||
"avl-tree-typed": "^1.34.1",
|
||||
"avl-tree-typed": "^1.36.4",
|
||||
"benchmark": "^2.1.4",
|
||||
"binary-tree-typed": "^1.34.1",
|
||||
"bst-typed": "^1.34.1",
|
||||
"binary-tree-typed": "^1.36.4",
|
||||
"bst-typed": "^1.36.4",
|
||||
"dependency-cruiser": "^14.1.0",
|
||||
"eslint": "^8.50.0",
|
||||
"eslint-config-prettier": "^9.0.0",
|
||||
"eslint-import-resolver-alias": "^1.1.2",
|
||||
"eslint-import-resolver-typescript": "^3.6.1",
|
||||
"eslint-plugin-import": "^2.28.1",
|
||||
"heap-typed": "^1.34.1",
|
||||
"heap-typed": "^1.36.4",
|
||||
"istanbul-badges-readme": "^1.8.5",
|
||||
"jest": "^29.7.0",
|
||||
"prettier": "^3.0.3",
|
||||
|
|
66
scripts/publish_all_subs.sh
Executable file
66
scripts/publish_all_subs.sh
Executable file
|
@ -0,0 +1,66 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Function to prompt for a directory path with a default value
|
||||
prompt_for_directory() {
|
||||
local message="$1"
|
||||
local default_path="$2"
|
||||
read -p "$message [$default_path]: " user_path
|
||||
echo "${user_path:-$default_path}"
|
||||
}
|
||||
|
||||
# Prompt for the source directory path
|
||||
source_dir=$(prompt_for_directory "Enter the source directory" "/Users/revone/projects/data-structure-typed")
|
||||
|
||||
# Prompt for the destination directory path
|
||||
individuals_dir=$(prompt_for_directory "Enter the destination directory" "/Users/revone/projects/data-structure-typed-individuals")
|
||||
|
||||
|
||||
# Read the version variable from package.json
|
||||
version_prompted=$(jq -r .version package.json)
|
||||
|
||||
cd "$individuals_dir"
|
||||
|
||||
# List of directories
|
||||
directories=(
|
||||
"avl-tree-typed"
|
||||
"binary-tree-typed"
|
||||
"bst-typed"
|
||||
"deque-typed"
|
||||
"directed-graph-typed"
|
||||
"doubly-linked-list-typed"
|
||||
"graph-typed"
|
||||
"heap-typed"
|
||||
"linked-list-typed"
|
||||
"max-heap-typed"
|
||||
"max-priority-queue-typed"
|
||||
"min-heap-typed"
|
||||
"min-priority-queue-typed"
|
||||
"priority-queue-typed"
|
||||
"singly-linked-list-typed"
|
||||
"queue-typed"
|
||||
"stack-typed"
|
||||
"tree-multiset-typed"
|
||||
"trie-typed"
|
||||
"undirected-graph-typed"
|
||||
)
|
||||
|
||||
# Loop through each directory
|
||||
for dir in "${directories[@]}"; do
|
||||
cd "$dir" || exit
|
||||
|
||||
# Update package.json version
|
||||
npm version "$version_prompted"
|
||||
|
||||
# jq ".dependencies[\"data-structure-typed\"] = \"$version_prompted\"" package.json > temp.json
|
||||
# mv temp.json package.json
|
||||
|
||||
# Install data-structure-typed package and build
|
||||
npm i data-structure-typed@"$version_prompted"
|
||||
npm run build:publish
|
||||
|
||||
cd ..
|
||||
done
|
||||
|
||||
echo "All packages updated and built."
|
||||
|
||||
cd "$source_dir"
|
65
scripts/publish_docs.sh
Executable file
65
scripts/publish_docs.sh
Executable file
|
@ -0,0 +1,65 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Function to prompt for a directory path with a default value
|
||||
prompt_for_directory() {
|
||||
local message="$1"
|
||||
local default_path="$2"
|
||||
read -p "$message [$default_path]: " user_path
|
||||
echo "${user_path:-$default_path}"
|
||||
}
|
||||
|
||||
# Prompt for the source directory path
|
||||
source_dir=$(prompt_for_directory "Enter the source directory" "/Users/revone/projects/data-structure-typed")
|
||||
|
||||
# Prompt for the destination directory path
|
||||
docs_dir=$(prompt_for_directory "Enter the destination directory" "/Users/revone/projects/data-structure-typed-docs")
|
||||
|
||||
# Check if jq is installed and install it if needed
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "jq is not installed. Installing..."
|
||||
|
||||
if [[ "$OSTYPE" == "linux-gnu" ]]; then
|
||||
sudo apt-get update
|
||||
sudo apt-get install jq
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
if ! command -v brew &> /dev/null; then
|
||||
echo "Homebrew is not installed. Please install Homebrew first."
|
||||
exit 1
|
||||
fi
|
||||
brew install jq
|
||||
else
|
||||
echo "Unsupported operating system. Please install jq manually."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "jq has been installed."
|
||||
else
|
||||
echo "jq is already installed."
|
||||
fi
|
||||
|
||||
# Change to the source directory
|
||||
cd "$source_dir"
|
||||
|
||||
# Read the version variable from package.json
|
||||
version=$(jq -r .version package.json)
|
||||
|
||||
# Execute the clear.sh script in the other directory
|
||||
cd "$docs_dir"
|
||||
shopt -s extglob
|
||||
rm -r !(.gitignore|favicon.ico|.idea)
|
||||
|
||||
# Copy all files from source directory to destination directory
|
||||
cp -r "$source_dir/docs/"* "$docs_dir"
|
||||
|
||||
# Change to the destination directory
|
||||
cd "$docs_dir"
|
||||
|
||||
# Commit the changes to the Git repository
|
||||
git add .
|
||||
git commit -m "[pkg] $version published"
|
||||
|
||||
# Push the changes to the remote repository
|
||||
git push
|
||||
|
||||
# Change back to the original directory
|
||||
cd "$source_dir"
|
62
scripts/run_command_all_subs.sh
Executable file
62
scripts/run_command_all_subs.sh
Executable file
|
@ -0,0 +1,62 @@
|
|||
#!/bin/bash
|
||||
|
||||
# Function to prompt for a directory path with a default value
|
||||
prompt_for_directory() {
|
||||
local message="$1"
|
||||
local default_path="$2"
|
||||
read -p "$message [$default_path]: " user_path
|
||||
echo "${user_path:-$default_path}"
|
||||
}
|
||||
|
||||
# Prompt for the source directory path
|
||||
source_dir=$(prompt_for_directory "Enter the source directory" "/Users/revone/projects/data-structure-typed")
|
||||
|
||||
# Prompt for the destination directory path
|
||||
individuals_dir=$(prompt_for_directory "Enter the destination directory" "/Users/revone/projects/data-structure-typed-individuals")
|
||||
|
||||
|
||||
# Read the version variable from package.json
|
||||
version_prompted=$(jq -r .version package.json)
|
||||
|
||||
cd "$individuals_dir"
|
||||
|
||||
# Read the command from the user
|
||||
read -p "Enter the command: " command
|
||||
|
||||
# List of directories
|
||||
directories=(
|
||||
"avl-tree-typed"
|
||||
"binary-tree-typed"
|
||||
"bst-typed"
|
||||
"deque-typed"
|
||||
"directed-graph-typed"
|
||||
"doubly-linked-list-typed"
|
||||
"graph-typed"
|
||||
"heap-typed"
|
||||
"linked-list-typed"
|
||||
"max-heap-typed"
|
||||
"max-priority-queue-typed"
|
||||
"min-heap-typed"
|
||||
"min-priority-queue-typed"
|
||||
"priority-queue-typed"
|
||||
"singly-linked-list-typed"
|
||||
"queue-typed"
|
||||
"stack-typed"
|
||||
"tree-multiset-typed"
|
||||
"trie-typed"
|
||||
"undirected-graph-typed"
|
||||
)
|
||||
|
||||
# Loop through each directory
|
||||
for dir in "${directories[@]}"; do
|
||||
cd "$dir" || exit
|
||||
|
||||
# execute the command
|
||||
$command
|
||||
|
||||
cd ..
|
||||
done
|
||||
|
||||
echo "$command in all libs executed success."
|
||||
|
||||
cd "$source_dir"
|
|
@ -1 +0,0 @@
|
|||
export class AaTree {}
|
File diff suppressed because it is too large
Load diff
|
@ -6,19 +6,22 @@
|
|||
* @license MIT License
|
||||
*/
|
||||
import {BST, BSTNode} from './bst';
|
||||
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeId} from '../../types';
|
||||
import {IAVLTree, IAVLTreeNode} from '../../interfaces';
|
||||
import type {AVLTreeNodeNested, AVLTreeOptions, BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../../types';
|
||||
import {IBinaryTree} from '../../interfaces';
|
||||
|
||||
export class AVLTreeNode<V = any, NEIGHBOR extends AVLTreeNode<V, NEIGHBOR> = AVLTreeNodeNested<V>>
|
||||
extends BSTNode<V, NEIGHBOR>
|
||||
implements IAVLTreeNode<V, NEIGHBOR>
|
||||
{
|
||||
constructor(id: BinaryTreeNodeId, val?: V) {
|
||||
super(id, val);
|
||||
export class AVLTreeNode<V = any, FAMILY extends AVLTreeNode<V, FAMILY> = AVLTreeNodeNested<V>> extends BSTNode<
|
||||
V,
|
||||
FAMILY
|
||||
> {
|
||||
height: number;
|
||||
|
||||
constructor(key: BinaryTreeNodeKey, val?: V) {
|
||||
super(key, val);
|
||||
this.height = 0;
|
||||
}
|
||||
}
|
||||
|
||||
export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends BST<N> implements IAVLTree<N> {
|
||||
export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends BST<N> implements IBinaryTree<N> {
|
||||
/**
|
||||
* This is a constructor function for an AVL tree data structure in TypeScript.
|
||||
* @param {AVLTreeOptions} [options] - The `options` parameter is an optional object that can be passed to the
|
||||
|
@ -30,27 +33,53 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
|
|||
}
|
||||
|
||||
/**
|
||||
* The function creates a new AVL tree node with the given id and value.
|
||||
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier for the binary tree node. It is used to uniquely
|
||||
* The `swapLocation` function swaps the location of two nodes in a binary tree.
|
||||
* @param {N} srcNode - The source node that you want to swap with the destination node.
|
||||
* @param {N} destNode - The `destNode` parameter represents the destination node where the values from `srcNode` will
|
||||
* be swapped to.
|
||||
* @returns The `destNode` is being returned.
|
||||
*/
|
||||
override swapLocation(srcNode: N, destNode: N): N {
|
||||
const {key, val, height} = destNode;
|
||||
const tempNode = this.createNode(key, val);
|
||||
|
||||
if (tempNode) {
|
||||
tempNode.height = height;
|
||||
|
||||
destNode.key = srcNode.key;
|
||||
destNode.val = srcNode.val;
|
||||
destNode.height = srcNode.height;
|
||||
|
||||
srcNode.key = tempNode.key;
|
||||
srcNode.val = tempNode.val;
|
||||
srcNode.height = tempNode.height;
|
||||
}
|
||||
|
||||
return destNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function creates a new AVL tree node with the given key and value.
|
||||
* @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier for the binary tree node. It is used to uniquely
|
||||
* identify each node in the tree.
|
||||
* @param [val] - The `val` parameter is an optional value that can be assigned to the node. It represents the value
|
||||
* that will be stored in the node.
|
||||
* @returns a new AVLTreeNode object with the specified id and value.
|
||||
* @returns a new AVLTreeNode object with the specified key and value.
|
||||
*/
|
||||
override createNode(id: BinaryTreeNodeId, val?: N['val']): N {
|
||||
return new AVLTreeNode<N['val'], N>(id, val) as N;
|
||||
override createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
|
||||
return new AVLTreeNode<N['val'], N>(key, val) as N;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function overrides the add method of a binary tree node and balances the tree after inserting a new node.
|
||||
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier of the binary tree node that we want to add.
|
||||
* @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier of the binary tree node that we want to add.
|
||||
* @param [val] - The `val` parameter is an optional value that can be assigned to the node being added. It is of type
|
||||
* `N['val']`, which means it should be of the same type as the `val` property of the nodes in the binary tree.
|
||||
* @returns The method is returning the inserted node, or null or undefined if the insertion was not successful.
|
||||
*/
|
||||
override add(id: BinaryTreeNodeId, val?: N['val']): N | null | undefined {
|
||||
override add(key: BinaryTreeNodeKey, val?: N['val']): N | null | undefined {
|
||||
// TODO support node as a param
|
||||
const inserted = super.add(id, val);
|
||||
const inserted = super.add(key, val);
|
||||
if (inserted) this._balancePath(inserted);
|
||||
return inserted;
|
||||
}
|
||||
|
@ -58,12 +87,12 @@ export class AVLTree<N extends AVLTreeNode<N['val'], N> = AVLTreeNode> extends B
|
|||
/**
|
||||
* The function overrides the remove method of a binary tree and performs additional operations to balance the tree after
|
||||
* deletion.
|
||||
* @param {BinaryTreeNodeId} id - The `id` parameter represents the identifier of the binary tree node that needs to be
|
||||
* @param {BinaryTreeNodeKey} key - The `key` parameter represents the identifier of the binary tree node that needs to be
|
||||
* removed.
|
||||
* @returns The method is returning an array of `BinaryTreeDeletedResult<N>` objects.
|
||||
*/
|
||||
override remove(id: BinaryTreeNodeId): BinaryTreeDeletedResult<N>[] {
|
||||
const deletedResults = super.remove(id);
|
||||
override remove(key: BinaryTreeNodeKey): BinaryTreeDeletedResult<N>[] {
|
||||
const deletedResults = super.remove(key);
|
||||
for (const {needBalanced} of deletedResults) {
|
||||
if (needBalanced) {
|
||||
this._balancePath(needBalanced);
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export class BTree {}
|
File diff suppressed because it is too large
Load diff
|
@ -5,21 +5,24 @@
|
|||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import type {BinaryTreeNodeId, BinaryTreeNodePropertyName, BSTComparator, BSTNodeNested, BSTOptions} from '../../types';
|
||||
import type {
|
||||
BinaryTreeNodeKey,
|
||||
BinaryTreeNodePropertyName,
|
||||
BSTComparator,
|
||||
BSTNodeNested,
|
||||
BSTOptions
|
||||
} from '../../types';
|
||||
import {CP, LoopType} from '../../types';
|
||||
import {BinaryTree, BinaryTreeNode} from './binary-tree';
|
||||
import {IBST, IBSTNode} from '../../interfaces';
|
||||
import {IBinaryTree} from '../../interfaces';
|
||||
|
||||
export class BSTNode<V = any, NEIGHBOR extends BSTNode<V, NEIGHBOR> = BSTNodeNested<V>>
|
||||
extends BinaryTreeNode<V, NEIGHBOR>
|
||||
implements IBSTNode<V, NEIGHBOR>
|
||||
{
|
||||
constructor(id: BinaryTreeNodeId, val?: V) {
|
||||
super(id, val);
|
||||
export class BSTNode<V = any, FAMILY extends BSTNode<V, FAMILY> = BSTNodeNested<V>> extends BinaryTreeNode<V, FAMILY> {
|
||||
constructor(key: BinaryTreeNodeKey, val?: V) {
|
||||
super(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N> implements IBST<N> {
|
||||
export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N> implements IBinaryTree<N> {
|
||||
/**
|
||||
* The constructor function initializes a binary search tree object with an optional comparator function.
|
||||
* @param {BSTOptions} [options] - An optional object that contains configuration options for the binary search tree.
|
||||
|
@ -35,35 +38,35 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
}
|
||||
|
||||
/**
|
||||
* The function creates a new binary search tree node with the given id and value.
|
||||
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier for the binary tree node. It is used to uniquely
|
||||
* The function creates a new binary search tree node with the given key and value.
|
||||
* @param {BinaryTreeNodeKey} key - The `key` parameter is the identifier for the binary tree node. It is used to uniquely
|
||||
* identify each node in the binary tree.
|
||||
* @param [val] - The `val` parameter is an optional value that can be assigned to the node. It represents the value
|
||||
* that will be stored in the node.
|
||||
* @returns a new instance of the BSTNode class with the specified id and value.
|
||||
* @returns a new instance of the BSTNode class with the specified key and value.
|
||||
*/
|
||||
override createNode(id: BinaryTreeNodeId, val?: N['val']): N {
|
||||
return new BSTNode<N['val'], N>(id, val) as N;
|
||||
override createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
|
||||
return new BSTNode<N['val'], N>(key, val) as N;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `add` function adds a new node to a binary search tree, either by creating a new node or by updating an existing
|
||||
* node with the same ID.
|
||||
* @param {BinaryTreeNodeId | N | null} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeId` or a `N`
|
||||
* @param {BinaryTreeNodeKey | N | null} keyOrNode - The `keyOrNode` parameter can be either a `BinaryTreeNodeKey` or a `N`
|
||||
* (which represents a binary tree node) or `null`.
|
||||
* @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the new node
|
||||
* being added to the binary search tree.
|
||||
* @returns The function `add` returns the inserted node (`inserted`) which can be of type `N`, `null`, or `undefined`.
|
||||
*/
|
||||
override add(idOrNode: BinaryTreeNodeId | N | null, val?: N['val']): N | null | undefined {
|
||||
override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined {
|
||||
// TODO support node as a param
|
||||
let inserted: N | null = null;
|
||||
let newNode: N | null = null;
|
||||
if (idOrNode instanceof BSTNode) {
|
||||
newNode = idOrNode;
|
||||
} else if (typeof idOrNode === 'number') {
|
||||
newNode = this.createNode(idOrNode, val);
|
||||
} else if (idOrNode === null) {
|
||||
if (keyOrNode instanceof BSTNode) {
|
||||
newNode = keyOrNode;
|
||||
} else if (typeof keyOrNode === 'number') {
|
||||
newNode = this.createNode(keyOrNode, val);
|
||||
} else if (keyOrNode === null) {
|
||||
newNode = null;
|
||||
}
|
||||
if (this.root === null) {
|
||||
|
@ -75,14 +78,14 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
let traversing = true;
|
||||
while (traversing) {
|
||||
if (cur !== null && newNode !== null) {
|
||||
if (this._compare(cur.id, newNode.id) === CP.eq) {
|
||||
if (this._compare(cur.key, newNode.key) === CP.eq) {
|
||||
if (newNode) {
|
||||
cur.val = newNode.val;
|
||||
}
|
||||
//Duplicates are not accepted.
|
||||
traversing = false;
|
||||
inserted = cur;
|
||||
} else if (this._compare(cur.id, newNode.id) === CP.gt) {
|
||||
} else if (this._compare(cur.key, newNode.key) === CP.gt) {
|
||||
// Traverse left of the node
|
||||
if (cur.left === undefined) {
|
||||
if (newNode) {
|
||||
|
@ -97,7 +100,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
//Traverse the left of the current node
|
||||
if (cur.left) cur = cur.left;
|
||||
}
|
||||
} else if (this._compare(cur.id, newNode.id) === CP.lt) {
|
||||
} else if (this._compare(cur.key, newNode.key) === CP.lt) {
|
||||
// Traverse right of the node
|
||||
if (cur.right === undefined) {
|
||||
if (newNode) {
|
||||
|
@ -124,48 +127,50 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
/**
|
||||
* The `addMany` function overrides the base class method to add multiple nodes to a binary search tree in a balanced
|
||||
* manner.
|
||||
* @param {[BinaryTreeNodeId | N , N['val']][]} idsOrNodes - The `idsOrNodes` parameter in the `addMany` function is an array of
|
||||
* `BinaryTreeNodeId` or `N` (node) objects, or `null` values. It represents the nodes or node IDs that need to be added
|
||||
* @param {[BinaryTreeNodeKey | N , N['val']][]} keysOrNodes - The `keysOrNodes` parameter in the `addMany` function is an array of
|
||||
* `BinaryTreeNodeKey` or `N` (node) objects, or `null` values. It represents the nodes or node IDs that need to be added
|
||||
* to the binary search tree.
|
||||
* @param {N['val'][]} data - The values of tree nodes
|
||||
* @param {boolean} isBalanceAdd - If true the nodes will be balance inserted in binary search method.
|
||||
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
|
||||
*/
|
||||
override addMany(
|
||||
idsOrNodes: (BinaryTreeNodeId | null)[] | (N | null)[],
|
||||
keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[],
|
||||
data?: N['val'][],
|
||||
isBalanceAdd = false
|
||||
): (N | null | undefined)[] {
|
||||
function hasNoNull(arr: (BinaryTreeNodeId | null)[] | (N | null)[]): arr is BinaryTreeNodeId[] | N[] {
|
||||
function hasNoNull(arr: (BinaryTreeNodeKey | null)[] | (N | null)[]): arr is BinaryTreeNodeKey[] | N[] {
|
||||
return arr.indexOf(null) === -1;
|
||||
}
|
||||
if (!isBalanceAdd || !hasNoNull(idsOrNodes)) {
|
||||
return super.addMany(idsOrNodes, data);
|
||||
if (!isBalanceAdd || !hasNoNull(keysOrNodes)) {
|
||||
return super.addMany(keysOrNodes, data);
|
||||
}
|
||||
const inserted: (N | null | undefined)[] = [];
|
||||
const combinedArr: [BinaryTreeNodeId | N, N['val']][] = idsOrNodes.map((value, index) => [value, data?.[index]]);
|
||||
const combinedArr: [BinaryTreeNodeKey | N, N['val']][] = keysOrNodes.map((value, index) => [value, data?.[index]]);
|
||||
let sorted = [];
|
||||
function isNodeOrNullTuple(arr: [BinaryTreeNodeId | N, N['val']][]): arr is [N, N['val']][] {
|
||||
for (const [idOrNode] of arr) if (idOrNode instanceof BSTNode) return true;
|
||||
function isNodeOrNullTuple(arr: [BinaryTreeNodeKey | N, N['val']][]): arr is [N, N['val']][] {
|
||||
for (const [keyOrNode] of arr) if (keyOrNode instanceof BSTNode) return true;
|
||||
return false;
|
||||
}
|
||||
function isBinaryTreeIdOrNullTuple(arr: [BinaryTreeNodeId | N, N['val']][]): arr is [BinaryTreeNodeId, N['val']][] {
|
||||
for (const [idOrNode] of arr) if (typeof idOrNode === 'number') return true;
|
||||
function isBinaryTreeKeyOrNullTuple(
|
||||
arr: [BinaryTreeNodeKey | N, N['val']][]
|
||||
): arr is [BinaryTreeNodeKey, N['val']][] {
|
||||
for (const [keyOrNode] of arr) if (typeof keyOrNode === 'number') return true;
|
||||
return false;
|
||||
}
|
||||
let sortedIdsOrNodes: (number | N | null)[] = [],
|
||||
let sortedKeysOrNodes: (number | N | null)[] = [],
|
||||
sortedData: (N['val'] | undefined)[] | undefined = [];
|
||||
|
||||
if (isNodeOrNullTuple(combinedArr)) {
|
||||
sorted = combinedArr.sort((a, b) => a[0].id - b[0].id);
|
||||
} else if (isBinaryTreeIdOrNullTuple(combinedArr)) {
|
||||
sorted = combinedArr.sort((a, b) => a[0].key - b[0].key);
|
||||
} else if (isBinaryTreeKeyOrNullTuple(combinedArr)) {
|
||||
sorted = combinedArr.sort((a, b) => a[0] - b[0]);
|
||||
} else {
|
||||
throw new Error('Invalid input idsOrNodes');
|
||||
throw new Error('Invalid input keysOrNodes');
|
||||
}
|
||||
sortedIdsOrNodes = sorted.map(([idOrNode]) => idOrNode);
|
||||
sortedKeysOrNodes = sorted.map(([keyOrNode]) => keyOrNode);
|
||||
sortedData = sorted.map(([, val]) => val);
|
||||
const recursive = (arr: (BinaryTreeNodeId | null | N)[], data?: N['val'][]) => {
|
||||
const recursive = (arr: (BinaryTreeNodeKey | null | N)[], data?: N['val'][]) => {
|
||||
if (arr.length === 0) return;
|
||||
|
||||
const mid = Math.floor((arr.length - 1) / 2);
|
||||
|
@ -183,7 +188,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
const [l, r] = popped;
|
||||
if (l <= r) {
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const newNode = this.add(sortedIdsOrNodes[m], sortedData?.[m]);
|
||||
const newNode = this.add(sortedKeysOrNodes[m], sortedData?.[m]);
|
||||
inserted.push(newNode);
|
||||
stack.push([m + 1, r]);
|
||||
stack.push([l, m - 1]);
|
||||
|
@ -192,7 +197,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
}
|
||||
};
|
||||
if (this.loopType === LoopType.RECURSIVE) {
|
||||
recursive(sortedIdsOrNodes, sortedData);
|
||||
recursive(sortedKeysOrNodes, sortedData);
|
||||
} else {
|
||||
iterative();
|
||||
}
|
||||
|
@ -202,45 +207,44 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
|
||||
/**
|
||||
* The function returns the first node in a binary tree that matches the given property name and value.
|
||||
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or a
|
||||
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a
|
||||
* generic type `N`. It represents the property of the binary tree node that you want to search for.
|
||||
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
|
||||
* specifies the property name to use for searching the binary tree nodes. If not provided, it defaults to `'id'`.
|
||||
* @returns The method is returning either a BinaryTreeNodeId or N (generic type) or null.
|
||||
* specifies the property name to use for searching the binary tree nodes. If not provided, it defaults to `'key'`.
|
||||
* @returns The method is returning either a BinaryTreeNodeKey or N (generic type) or null.
|
||||
*/
|
||||
override get(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): N | null {
|
||||
propertyName = propertyName ?? 'id';
|
||||
override get(nodeProperty: BinaryTreeNodeKey | N, propertyName: BinaryTreeNodePropertyName = 'key'): N | null {
|
||||
return this.getNodes(nodeProperty, propertyName, true)[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns the id of the rightmost node if the comparison between two values is less than, the id of the
|
||||
* leftmost node if the comparison is greater than, and the id of the rightmost node otherwise.
|
||||
* @returns The method `lastKey()` returns the id of the rightmost node in the binary tree if the comparison between
|
||||
* the values at index 0 and 1 is less than, otherwise it returns the id of the leftmost node. If the comparison is
|
||||
* equal, it returns the id of the rightmost node. If there are no nodes in the tree, it returns 0.
|
||||
* The function returns the key of the rightmost node if the comparison between two values is less than, the key of the
|
||||
* leftmost node if the comparison is greater than, and the key of the rightmost node otherwise.
|
||||
* @returns The method `lastKey()` returns the key of the rightmost node in the binary tree if the comparison between
|
||||
* the values at index 0 and 1 is less than, otherwise it returns the key of the leftmost node. If the comparison is
|
||||
* equal, it returns the key of the rightmost node. If there are no nodes in the tree, it returns 0.
|
||||
*/
|
||||
lastKey(): BinaryTreeNodeId {
|
||||
if (this._compare(0, 1) === CP.lt) return this.getRightMost()?.id ?? 0;
|
||||
else if (this._compare(0, 1) === CP.gt) return this.getLeftMost()?.id ?? 0;
|
||||
else return this.getRightMost()?.id ?? 0;
|
||||
lastKey(): BinaryTreeNodeKey {
|
||||
if (this._compare(0, 1) === CP.lt) return this.getRightMost()?.key ?? 0;
|
||||
else if (this._compare(0, 1) === CP.gt) return this.getLeftMost()?.key ?? 0;
|
||||
else return this.getRightMost()?.key ?? 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function `getNodes` returns an array of nodes in a binary tree that match a given property value.
|
||||
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or an
|
||||
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or an
|
||||
* `N` type. It represents the property of the binary tree node that you want to compare with.
|
||||
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
|
||||
* specifies the property name to use for comparison. If not provided, it defaults to `'id'`.
|
||||
* specifies the property name to use for comparison. If not provided, it defaults to `'key'`.
|
||||
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
|
||||
* return only one node that matches the given `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne`
|
||||
* is set to `true`, the function will return an array with only one node (if
|
||||
* @returns an array of nodes (type N).
|
||||
*/
|
||||
override getNodes(
|
||||
nodeProperty: BinaryTreeNodeId | N,
|
||||
propertyName: BinaryTreeNodePropertyName = 'id',
|
||||
onlyOne?: boolean
|
||||
nodeProperty: BinaryTreeNodeKey | N,
|
||||
propertyName: BinaryTreeNodePropertyName = 'key',
|
||||
onlyOne = false
|
||||
): N[] {
|
||||
if (!this.root) return [];
|
||||
const result: N[] = [];
|
||||
|
@ -250,9 +254,9 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return;
|
||||
|
||||
if (!cur.left && !cur.right) return;
|
||||
if (propertyName === 'id') {
|
||||
if (this._compare(cur.id, nodeProperty as number) === CP.gt) cur.left && _traverse(cur.left);
|
||||
if (this._compare(cur.id, nodeProperty as number) === CP.lt) cur.right && _traverse(cur.right);
|
||||
if (propertyName === 'key') {
|
||||
if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && _traverse(cur.left);
|
||||
if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && _traverse(cur.right);
|
||||
} else {
|
||||
cur.left && _traverse(cur.left);
|
||||
cur.right && _traverse(cur.right);
|
||||
|
@ -266,9 +270,9 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
const cur = queue.shift();
|
||||
if (cur) {
|
||||
if (this._pushByPropertyNameStopOrNot(cur, result, nodeProperty, propertyName, onlyOne)) return result;
|
||||
if (propertyName === 'id') {
|
||||
if (this._compare(cur.id, nodeProperty as number) === CP.gt) cur.left && queue.push(cur.left);
|
||||
if (this._compare(cur.id, nodeProperty as number) === CP.lt) cur.right && queue.push(cur.right);
|
||||
if (propertyName === 'key') {
|
||||
if (this._compare(cur.key, nodeProperty as number) === CP.gt) cur.left && queue.push(cur.left);
|
||||
if (this._compare(cur.key, nodeProperty as number) === CP.lt) cur.right && queue.push(cur.right);
|
||||
} else {
|
||||
cur.left && queue.push(cur.left);
|
||||
cur.right && queue.push(cur.right);
|
||||
|
@ -284,26 +288,25 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
/**
|
||||
* The `lesserSum` function calculates the sum of property values in a binary tree for nodes that have a property value
|
||||
* less than a given node.
|
||||
* @param {N | BinaryTreeNodeId | null} beginNode - The `beginNode` parameter can be one of the following:
|
||||
* @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following:
|
||||
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
|
||||
* specifies the property name to use for calculating the sum. If not provided, it defaults to `'id'`.
|
||||
* specifies the property name to use for calculating the sum. If not provided, it defaults to `'key'`.
|
||||
* @returns The function `lesserSum` returns a number, which represents the sum of the values of the nodes in the
|
||||
* binary tree that have a lesser value than the specified `beginNode` based on the `propertyName`.
|
||||
*/
|
||||
lesserSum(beginNode: N | BinaryTreeNodeId | null, propertyName?: BinaryTreeNodePropertyName): number {
|
||||
propertyName = propertyName ?? 'id';
|
||||
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'id');
|
||||
lesserSum(beginNode: N | BinaryTreeNodeKey | null, propertyName: BinaryTreeNodePropertyName = 'key'): number {
|
||||
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key');
|
||||
if (!beginNode) return 0;
|
||||
if (!this.root) return 0;
|
||||
const id = beginNode.id;
|
||||
const key = beginNode.key;
|
||||
const getSumByPropertyName = (cur: N) => {
|
||||
let needSum: number;
|
||||
switch (propertyName) {
|
||||
case 'id':
|
||||
needSum = cur.id;
|
||||
case 'key':
|
||||
needSum = cur.key;
|
||||
break;
|
||||
default:
|
||||
needSum = cur.id;
|
||||
needSum = cur.key;
|
||||
break;
|
||||
}
|
||||
return needSum;
|
||||
|
@ -313,7 +316,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
|
||||
if (this.loopType === LoopType.RECURSIVE) {
|
||||
const _traverse = (cur: N): void => {
|
||||
const compared = this._compare(cur.id, id);
|
||||
const compared = this._compare(cur.key, key);
|
||||
if (compared === CP.eq) {
|
||||
if (cur.right) sum += this.subTreeSum(cur.right, propertyName);
|
||||
return;
|
||||
|
@ -334,7 +337,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
while (queue.length > 0) {
|
||||
const cur = queue.shift();
|
||||
if (cur) {
|
||||
const compared = this._compare(cur.id, id);
|
||||
const compared = this._compare(cur.key, key);
|
||||
if (compared === CP.eq) {
|
||||
if (cur.right) sum += this.subTreeSum(cur.right, propertyName);
|
||||
return sum;
|
||||
|
@ -358,44 +361,43 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
/**
|
||||
* The `allGreaterNodesAdd` function adds a delta value to the specified property of all nodes in a binary tree that
|
||||
* have a greater value than a given node.
|
||||
* @param {N | BinaryTreeNodeId | null} node - The `node` parameter can be either of type `N` (a generic type),
|
||||
* `BinaryTreeNodeId`, or `null`. It represents the node in the binary tree to which the delta value will be added.
|
||||
* @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be either of type `N` (a generic type),
|
||||
* `BinaryTreeNodeKey`, or `null`. It represents the node in the binary tree to which the delta value will be added.
|
||||
* @param {number} delta - The `delta` parameter is a number that represents the amount by which the property value of
|
||||
* each greater node should be increased.
|
||||
* @param {BinaryTreeNodePropertyName} [propertyName] - The `propertyName` parameter is an optional parameter that
|
||||
* specifies the property name of the nodes in the binary tree that you want to update. If not provided, it defaults to
|
||||
* 'id'.
|
||||
* 'key'.
|
||||
* @returns a boolean value.
|
||||
*/
|
||||
allGreaterNodesAdd(
|
||||
node: N | BinaryTreeNodeId | null,
|
||||
node: N | BinaryTreeNodeKey | null,
|
||||
delta: number,
|
||||
propertyName?: BinaryTreeNodePropertyName
|
||||
propertyName: BinaryTreeNodePropertyName = 'key'
|
||||
): boolean {
|
||||
propertyName = propertyName ?? 'id';
|
||||
if (typeof node === 'number') node = this.get(node, 'id');
|
||||
if (typeof node === 'number') node = this.get(node, 'key');
|
||||
if (!node) return false;
|
||||
const id = node.id;
|
||||
const key = node.key;
|
||||
if (!this.root) return false;
|
||||
|
||||
const _sumByPropertyName = (cur: N) => {
|
||||
switch (propertyName) {
|
||||
case 'id':
|
||||
cur.id += delta;
|
||||
case 'key':
|
||||
cur.key += delta;
|
||||
break;
|
||||
default:
|
||||
cur.id += delta;
|
||||
cur.key += delta;
|
||||
break;
|
||||
}
|
||||
};
|
||||
if (this.loopType === LoopType.RECURSIVE) {
|
||||
const _traverse = (cur: N) => {
|
||||
const compared = this._compare(cur.id, id);
|
||||
const compared = this._compare(cur.key, key);
|
||||
if (compared === CP.gt) _sumByPropertyName(cur);
|
||||
|
||||
if (!cur.left && !cur.right) return;
|
||||
if (cur.left && this._compare(cur.left.id, id) === CP.gt) _traverse(cur.left);
|
||||
if (cur.right && this._compare(cur.right.id, id) === CP.gt) _traverse(cur.right);
|
||||
if (cur.left && this._compare(cur.left.key, key) === CP.gt) _traverse(cur.left);
|
||||
if (cur.right && this._compare(cur.right.key, key) === CP.gt) _traverse(cur.right);
|
||||
};
|
||||
|
||||
_traverse(this.root);
|
||||
|
@ -405,11 +407,11 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
while (queue.length > 0) {
|
||||
const cur = queue.shift();
|
||||
if (cur) {
|
||||
const compared = this._compare(cur.id, id);
|
||||
const compared = this._compare(cur.key, key);
|
||||
if (compared === CP.gt) _sumByPropertyName(cur);
|
||||
|
||||
if (cur.left && this._compare(cur.left.id, id) === CP.gt) queue.push(cur.left);
|
||||
if (cur.right && this._compare(cur.right.id, id) === CP.gt) queue.push(cur.right);
|
||||
if (cur.left && this._compare(cur.left.key, key) === CP.gt) queue.push(cur.left);
|
||||
if (cur.right && this._compare(cur.right.key, key) === CP.gt) queue.push(cur.right);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
@ -432,7 +434,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
* @returns The function `perfectlyBalance()` returns a boolean value.
|
||||
*/
|
||||
perfectlyBalance(): boolean {
|
||||
const sorted = this.DFS('in', 'node'),
|
||||
const sorted = this.dfs('in', 'node'),
|
||||
n = sorted.length;
|
||||
this.clear();
|
||||
|
||||
|
@ -442,7 +444,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
if (l > r) return;
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const midNode = sorted[m];
|
||||
this.add(midNode.id, midNode.val);
|
||||
this.add(midNode.key, midNode.val);
|
||||
buildBalanceBST(l, m - 1);
|
||||
buildBalanceBST(m + 1, r);
|
||||
};
|
||||
|
@ -458,7 +460,7 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
if (l <= r) {
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const midNode = sorted[m];
|
||||
this.add(midNode.id, midNode.val);
|
||||
this.add(midNode.key, midNode.val);
|
||||
stack.push([m + 1, r]);
|
||||
stack.push([l, m - 1]);
|
||||
}
|
||||
|
@ -521,12 +523,12 @@ export class BST<N extends BSTNode<N['val'], N> = BSTNode> extends BinaryTree<N>
|
|||
/**
|
||||
* The function compares two binary tree node IDs using a comparator function and returns whether the first ID is
|
||||
* greater than, less than, or equal to the second ID.
|
||||
* @param {BinaryTreeNodeId} a - a is a BinaryTreeNodeId, which represents the identifier of a binary tree node.
|
||||
* @param {BinaryTreeNodeId} b - The parameter "b" in the above code refers to a BinaryTreeNodeId.
|
||||
* @param {BinaryTreeNodeKey} a - "a" is a BinaryTreeNodeKey, which represents the identifier of a binary tree node.
|
||||
* @param {BinaryTreeNodeKey} b - The parameter "b" in the above code refers to a BinaryTreeNodeKey.
|
||||
* @returns a value of type CP (ComparisonResult). The possible return values are CP.gt (greater than), CP.lt (less
|
||||
* than), or CP.eq (equal).
|
||||
*/
|
||||
protected _compare(a: BinaryTreeNodeId, b: BinaryTreeNodeId): CP {
|
||||
protected _compare(a: BinaryTreeNodeKey, b: BinaryTreeNodeKey): CP {
|
||||
const compared = this._comparator(a, b);
|
||||
if (compared > 0) return CP.gt;
|
||||
else if (compared < 0) return CP.lt;
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
export * from './abstract-binary-tree';
|
||||
export * from './binary-tree';
|
||||
export * from './bst';
|
||||
export * from './binary-indexed-tree';
|
||||
export * from './segment-tree';
|
||||
export * from './avl-tree';
|
||||
export * from './b-tree';
|
||||
export * from './rb-tree';
|
||||
export * from './splay-tree';
|
||||
export * from './aa-tree';
|
||||
export * from './tree-multiset';
|
||||
export * from './two-three-tree';
|
||||
|
|
|
@ -5,10 +5,11 @@ import {BST, BSTNode} from './bst';
|
|||
export class RBTreeNode<V = any, NEIGHBOR extends RBTreeNode<V, NEIGHBOR> = RBTreeNodeNested<V>>
|
||||
extends BSTNode<V, NEIGHBOR>
|
||||
implements IRBTreeNode<V, NEIGHBOR> {
|
||||
|
||||
private _color: RBColor;
|
||||
|
||||
constructor(id: BinaryTreeNodeId, val?: V) {
|
||||
super(id, val);
|
||||
constructor(key: BinaryTreeNodeKey, val?: V) {
|
||||
super(key, val);
|
||||
this._color = RBColor.RED;
|
||||
}
|
||||
|
||||
|
@ -21,15 +22,16 @@ export class RBTreeNode<V = any, NEIGHBOR extends RBTreeNode<V, NEIGHBOR> = RBTr
|
|||
}
|
||||
}
|
||||
|
||||
export class RBTree<N extends RBTreeNode<N['val'], N> = RBTreeNode> extends BST<N> implements IRBTree<N> {
|
||||
export class RBTree<N extends RBTreeNode<N['val'], N> = RBTreeNode> extends BST<N> implements IBinaryTree<N> {
|
||||
constructor(options?: RBTreeOptions) {
|
||||
super(options);
|
||||
}
|
||||
|
||||
override createNode(id: BinaryTreeNodeId, val?: N['val']): N {
|
||||
return new RBTreeNode(id, val) as N;
|
||||
override createNode(key: BinaryTreeNodeKey, val?: N['val']): N {
|
||||
return new RBTreeNode(key, val) as N;
|
||||
}
|
||||
|
||||
|
||||
private fixInsertion(node: N): void {
|
||||
while (node !== this.root && node.parent?.color === RBColor.RED) {
|
||||
if (node.parent === node.parent?.parent?.left) {
|
||||
|
@ -319,4 +321,5 @@ export class RBTree<N extends RBTreeNode<N['val'], N> = RBTreeNode> extends BST<
|
|||
}
|
||||
node.color = RBColor.BLACK; // Ensure the root is always black.
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export class SplayTree {}
|
|
@ -5,39 +5,31 @@
|
|||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import type {BinaryTreeNodeId, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types';
|
||||
import type {BinaryTreeNodeKey, TreeMultisetNodeNested, TreeMultisetOptions} from '../../types';
|
||||
import {BinaryTreeDeletedResult, CP, DFSOrderPattern, FamilyPosition, LoopType} from '../../types';
|
||||
import {ITreeMultiset, ITreeMultisetNode} from '../../interfaces';
|
||||
import {IBinaryTree} from '../../interfaces';
|
||||
import {AVLTree, AVLTreeNode} from './avl-tree';
|
||||
|
||||
export class TreeMultisetNode<V = any, NEIGHBOR extends TreeMultisetNode<V, NEIGHBOR> = TreeMultisetNodeNested<V>>
|
||||
extends AVLTreeNode<V, NEIGHBOR>
|
||||
implements ITreeMultisetNode<V, NEIGHBOR>
|
||||
{
|
||||
export class TreeMultisetNode<
|
||||
V = any,
|
||||
FAMILY extends TreeMultisetNode<V, FAMILY> = TreeMultisetNodeNested<V>
|
||||
> extends AVLTreeNode<V, FAMILY> {
|
||||
/**
|
||||
* The constructor function initializes a BinaryTreeNode object with an id, value, and count.
|
||||
* @param {BinaryTreeNodeId} id - The `id` parameter is of type `BinaryTreeNodeId` and represents the unique identifier
|
||||
* The constructor function initializes a BinaryTreeNode object with a key, value, and count.
|
||||
* @param {BinaryTreeNodeKey} key - The `key` parameter is of type `BinaryTreeNodeKey` and represents the unique identifier
|
||||
* of the binary tree node.
|
||||
* @param {V} [val] - The `val` parameter is an optional parameter of type `V`. It represents the value of the binary
|
||||
* tree node. If no value is provided, it will be `undefined`.
|
||||
* @param {number} [count=1] - The `count` parameter is a number that represents the number of times a particular value
|
||||
* occurs in a binary tree node. It has a default value of 1, which means that if no value is provided for the `count`
|
||||
* parameter when creating a new instance of the `BinaryTreeNode` class,
|
||||
* parameter when creating a new instance of the `BinaryTreeNode` class.
|
||||
*/
|
||||
constructor(id: BinaryTreeNodeId, val?: V, count = 1) {
|
||||
super(id, val);
|
||||
this._count = count;
|
||||
constructor(key: BinaryTreeNodeKey, val?: V, count = 1) {
|
||||
super(key, val);
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
private _count: number;
|
||||
|
||||
get count(): number {
|
||||
return this._count;
|
||||
}
|
||||
|
||||
set count(v: number) {
|
||||
this._count = v;
|
||||
}
|
||||
count: number;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,7 +37,7 @@ export class TreeMultisetNode<V = any, NEIGHBOR extends TreeMultisetNode<V, NEIG
|
|||
*/
|
||||
export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultisetNode>
|
||||
extends AVLTree<N>
|
||||
implements ITreeMultiset<N>
|
||||
implements IBinaryTree<N>
|
||||
{
|
||||
/**
|
||||
* The constructor function for a TreeMultiset class in TypeScript, which extends another class and sets an option to
|
||||
|
@ -54,7 +46,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
* TreeMultiset.
|
||||
*/
|
||||
constructor(options?: TreeMultisetOptions) {
|
||||
super({...options});
|
||||
super(options);
|
||||
}
|
||||
|
||||
private _count = 0;
|
||||
|
@ -64,16 +56,16 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
}
|
||||
|
||||
/**
|
||||
* The function creates a new BSTNode with the given id, value, and count.
|
||||
* @param {BinaryTreeNodeId} id - The id parameter is the unique identifier for the binary tree node. It is used to
|
||||
* The function creates a new BSTNode with the given key, value, and count.
|
||||
* @param {BinaryTreeNodeKey} key - The key parameter is the unique identifier for the binary tree node. It is used to
|
||||
* distinguish one node from another in the tree.
|
||||
* @param {N} val - The `val` parameter represents the value that will be stored in the binary search tree node.
|
||||
* @param {number} [count] - The "count" parameter is an optional parameter of type number. It represents the number of
|
||||
* occurrences of the value in the binary search tree node. If not provided, the count will default to 1.
|
||||
* @returns A new instance of the BSTNode class with the specified id, value, and count (if provided).
|
||||
* @returns A new instance of the BSTNode class with the specified key, value, and count (if provided).
|
||||
*/
|
||||
override createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N {
|
||||
return new TreeMultisetNode(id, val, count) as N;
|
||||
override createNode(key: BinaryTreeNodeKey, val?: N['val'], count?: number): N {
|
||||
return new TreeMultisetNode(key, val, count) as N;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -84,17 +76,17 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
* @returns the `destNode` after swapping its values with the `srcNode`.
|
||||
*/
|
||||
override swapLocation(srcNode: N, destNode: N): N {
|
||||
const {id, val, count, height} = destNode;
|
||||
const tempNode = this.createNode(id, val, count);
|
||||
const {key, val, count, height} = destNode;
|
||||
const tempNode = this.createNode(key, val, count);
|
||||
if (tempNode) {
|
||||
tempNode.height = height;
|
||||
|
||||
destNode.id = srcNode.id;
|
||||
destNode.key = srcNode.key;
|
||||
destNode.val = srcNode.val;
|
||||
destNode.count = srcNode.count;
|
||||
destNode.height = srcNode.height;
|
||||
|
||||
srcNode.id = tempNode.id;
|
||||
srcNode.key = tempNode.key;
|
||||
srcNode.val = tempNode.val;
|
||||
srcNode.count = tempNode.count;
|
||||
srcNode.height = tempNode.height;
|
||||
|
@ -106,23 +98,22 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
/**
|
||||
* The `add` function adds a new node to a binary search tree, maintaining the tree's properties and balancing if
|
||||
* necessary.
|
||||
* @param {BinaryTreeNodeId | N} idOrNode - The `idOrNode` parameter can be either a `BinaryTreeNodeId` or a `N` (which
|
||||
* @param {BinaryTreeNodeKey | N} keyOrNode - The `keyOrNode` parameter can be either a `BinaryTreeNodeKey` or a `N` (which
|
||||
* represents a `BinaryTreeNode`).
|
||||
* @param [val] - The `val` parameter represents the value to be added to the binary tree node.
|
||||
* @param {number} [count] - The `count` parameter is an optional parameter that specifies the number of times the
|
||||
* value should be added to the binary tree. If the `count` parameter is not provided, it defaults to 1.
|
||||
* @returns The method `add` returns either the inserted node (`N`), `null`, or `undefined`.
|
||||
*/
|
||||
override add(idOrNode: BinaryTreeNodeId | N | null, val?: N['val'], count?: number): N | null | undefined {
|
||||
count = count ?? 1;
|
||||
override add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val'], count = 1): N | null | undefined {
|
||||
let inserted: N | null | undefined = undefined,
|
||||
newNode: N | null;
|
||||
if (idOrNode instanceof TreeMultisetNode) {
|
||||
newNode = this.createNode(idOrNode.id, idOrNode.val, idOrNode.count);
|
||||
} else if (idOrNode === null) {
|
||||
if (keyOrNode instanceof TreeMultisetNode) {
|
||||
newNode = this.createNode(keyOrNode.key, keyOrNode.val, keyOrNode.count);
|
||||
} else if (keyOrNode === null) {
|
||||
newNode = null;
|
||||
} else {
|
||||
newNode = this.createNode(idOrNode, val, count);
|
||||
newNode = this.createNode(keyOrNode, val, count);
|
||||
}
|
||||
if (!this.root) {
|
||||
this._setRoot(newNode);
|
||||
|
@ -135,13 +126,13 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
while (traversing) {
|
||||
if (cur) {
|
||||
if (newNode) {
|
||||
if (this._compare(cur.id, newNode.id) === CP.eq) {
|
||||
if (this._compare(cur.key, newNode.key) === CP.eq) {
|
||||
cur.val = newNode.val;
|
||||
cur.count += newNode.count;
|
||||
this._setCount(this.count + newNode.count);
|
||||
traversing = false;
|
||||
inserted = cur;
|
||||
} else if (this._compare(cur.id, newNode.id) === CP.gt) {
|
||||
} else if (this._compare(cur.key, newNode.key) === CP.gt) {
|
||||
// Traverse left of the node
|
||||
if (cur.left === undefined) {
|
||||
//Add to the left of the current node
|
||||
|
@ -155,7 +146,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
//Traverse the left of the current node
|
||||
if (cur.left) cur = cur.left;
|
||||
}
|
||||
} else if (this._compare(cur.id, newNode.id) === CP.lt) {
|
||||
} else if (this._compare(cur.key, newNode.key) === CP.lt) {
|
||||
// Traverse right of the node
|
||||
if (cur.right === undefined) {
|
||||
//Add to the right of the current node
|
||||
|
@ -219,33 +210,33 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
/**
|
||||
* The `addMany` function takes an array of node IDs or nodes and adds them to the tree multiset, returning an array of
|
||||
* the inserted nodes.
|
||||
* @param {(BinaryTreeNodeId | null)[] | (N | null)[]} idsOrNodes - An array of BinaryTreeNodeId or BinaryTreeNode
|
||||
* @param {(BinaryTreeNodeKey | null)[] | (N | null)[]} keysOrNodes - An array of BinaryTreeNodeKey or BinaryTreeNode
|
||||
* objects, or null values.
|
||||
* @param {N['val'][]} [data] - The `data` parameter is an optional array of values (`N['val'][]`) that corresponds to
|
||||
* the nodes being added. It is used when adding nodes using the `idOrNode` and `data` arguments in the `this.add()`
|
||||
* the nodes being added. It is used when adding nodes using the `keyOrNode` and `data` arguments in the `this.add()`
|
||||
* method. If provided, the `data` array should
|
||||
* @returns The function `addMany` returns an array of `N`, `null`, or `undefined` values.
|
||||
*/
|
||||
override addMany(
|
||||
idsOrNodes: (BinaryTreeNodeId | null)[] | (N | null)[],
|
||||
keysOrNodes: (BinaryTreeNodeKey | null)[] | (N | null)[],
|
||||
data?: N['val'][]
|
||||
): (N | null | undefined)[] {
|
||||
const inserted: (N | null | undefined)[] = [];
|
||||
|
||||
for (let i = 0; i < idsOrNodes.length; i++) {
|
||||
const idOrNode = idsOrNodes[i];
|
||||
for (let i = 0; i < keysOrNodes.length; i++) {
|
||||
const keyOrNode = keysOrNodes[i];
|
||||
|
||||
if (idOrNode instanceof TreeMultisetNode) {
|
||||
inserted.push(this.add(idOrNode.id, idOrNode.val, idOrNode.count));
|
||||
if (keyOrNode instanceof TreeMultisetNode) {
|
||||
inserted.push(this.add(keyOrNode.key, keyOrNode.val, keyOrNode.count));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (idOrNode === null) {
|
||||
if (keyOrNode === null) {
|
||||
inserted.push(this.add(NaN, null, 0));
|
||||
continue;
|
||||
}
|
||||
|
||||
inserted.push(this.add(idOrNode, data?.[i], 1));
|
||||
inserted.push(this.add(keyOrNode, data?.[i], 1));
|
||||
}
|
||||
return inserted;
|
||||
}
|
||||
|
@ -256,7 +247,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
* @returns The function `perfectlyBalance()` returns a boolean value.
|
||||
*/
|
||||
override perfectlyBalance(): boolean {
|
||||
const sorted = this.DFS('in', 'node'),
|
||||
const sorted = this.dfs('in', 'node'),
|
||||
n = sorted.length;
|
||||
if (sorted.length < 1) return false;
|
||||
|
||||
|
@ -267,7 +258,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
if (l > r) return;
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const midNode = sorted[m];
|
||||
this.add(midNode.id, midNode.val, midNode.count);
|
||||
this.add(midNode.key, midNode.val, midNode.count);
|
||||
buildBalanceBST(l, m - 1);
|
||||
buildBalanceBST(m + 1, r);
|
||||
};
|
||||
|
@ -283,7 +274,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
if (l <= r) {
|
||||
const m = l + Math.floor((r - l) / 2);
|
||||
const midNode = sorted[m];
|
||||
this.add(midNode.id, midNode.val, midNode.count);
|
||||
this.add(midNode.key, midNode.val, midNode.count);
|
||||
stack.push([m + 1, r]);
|
||||
stack.push([l, m - 1]);
|
||||
}
|
||||
|
@ -296,17 +287,17 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
/**
|
||||
* The `remove` function removes a node from a binary search tree and returns the deleted node along with the parent
|
||||
* node that needs to be balanced.
|
||||
* @param {N | BinaryTreeNodeId | null} nodeOrId - The `nodeOrId` parameter can be one of the following:
|
||||
* @param {N | BinaryTreeNodeKey | null} nodeOrKey - The `nodeOrKey` parameter can be one of the following:
|
||||
* @param {boolean} [ignoreCount] - The `ignoreCount` parameter is an optional boolean parameter that determines
|
||||
* whether to ignore the count of the node being removed. If `ignoreCount` is set to `true`, the count of the node will
|
||||
* not be taken into account when removing it. If `ignoreCount` is set to `false
|
||||
* @returns The function `remove` returns an array of `BinaryTreeDeletedResult<N>` objects.
|
||||
*/
|
||||
override remove(nodeOrId: N | BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[] {
|
||||
override remove(nodeOrKey: N | BinaryTreeNodeKey, ignoreCount = false): BinaryTreeDeletedResult<N>[] {
|
||||
const bstDeletedResult: BinaryTreeDeletedResult<N>[] = [];
|
||||
if (!this.root) return bstDeletedResult;
|
||||
|
||||
const curr: N | null = this.get(nodeOrId);
|
||||
const curr: N | null = this.get(nodeOrKey);
|
||||
if (!curr) return bstDeletedResult;
|
||||
|
||||
const parent: N | null = curr?.parent ? curr.parent : null;
|
||||
|
@ -397,13 +388,13 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
/**
|
||||
* The function `subTreeSumCount` calculates the sum of the `count` property of each node in a subtree, either
|
||||
* recursively or iteratively.
|
||||
* @param {N | BinaryTreeNodeId | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
|
||||
* in a binary tree. It can be either a `BinaryTreeNodeId` (a unique identifier for a node in the binary tree) or
|
||||
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
|
||||
* in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree) or
|
||||
* `null` if the subtree is empty.
|
||||
* @returns the sum of the count values of all nodes in the subtree rooted at `subTreeRoot`.
|
||||
*/
|
||||
subTreeSumCount(subTreeRoot: N | BinaryTreeNodeId | null): number {
|
||||
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'id');
|
||||
subTreeSumCount(subTreeRoot: N | BinaryTreeNodeKey | null): number {
|
||||
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
|
||||
|
||||
if (!subTreeRoot) return 0;
|
||||
|
||||
|
@ -434,15 +425,15 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
/**
|
||||
* The function `subTreeAddCount` recursively or iteratively traverses a binary tree and adds a given delta value to
|
||||
* the `count` property of each node.
|
||||
* @param {N | BinaryTreeNodeId | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
|
||||
* in a binary tree. It can be either a `BinaryTreeNodeId` (a unique identifier for a node in the binary tree), a
|
||||
* @param {N | BinaryTreeNodeKey | null} subTreeRoot - The `subTreeRoot` parameter represents the root node of a subtree
|
||||
* in a binary tree. It can be either a `BinaryTreeNodeKey` (a unique identifier for a node in the binary tree), a
|
||||
* `BinaryTreeNode` object, or `null` if the subtree is empty.
|
||||
* @param {number} delta - The delta parameter is a number that represents the amount by which the count of each node
|
||||
* in the subtree should be increased or decreased.
|
||||
* @returns a boolean value.
|
||||
*/
|
||||
subTreeAddCount(subTreeRoot: N | BinaryTreeNodeId | null, delta: number): boolean {
|
||||
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'id');
|
||||
subTreeAddCount(subTreeRoot: N | BinaryTreeNodeKey | null, delta: number): boolean {
|
||||
if (typeof subTreeRoot === 'number') subTreeRoot = this.get(subTreeRoot, 'key');
|
||||
|
||||
if (!subTreeRoot) return false;
|
||||
|
||||
|
@ -476,14 +467,14 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
/**
|
||||
* The function `getNodesByCount` returns an array of nodes that have a specific count property, either recursively or
|
||||
* using a queue.
|
||||
* @param {BinaryTreeNodeId | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeId` or a
|
||||
* @param {BinaryTreeNodeKey | N} nodeProperty - The `nodeProperty` parameter can be either a `BinaryTreeNodeKey` or a
|
||||
* `N`. It represents the property of the nodes that you want to search for.
|
||||
* @param {boolean} [onlyOne] - The `onlyOne` parameter is an optional boolean parameter that determines whether to
|
||||
* return only one node that matches the `nodeProperty` or all nodes that match the `nodeProperty`. If `onlyOne` is set
|
||||
* to `true`, the function will return only one node. If `onlyOne`
|
||||
* @returns an array of nodes that match the given nodeProperty.
|
||||
*/
|
||||
getNodesByCount(nodeProperty: BinaryTreeNodeId | N, onlyOne?: boolean): N[] {
|
||||
getNodesByCount(nodeProperty: BinaryTreeNodeKey | N, onlyOne = false): N[] {
|
||||
if (!this.root) return [];
|
||||
const result: N[] = [];
|
||||
|
||||
|
@ -522,10 +513,10 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
/**
|
||||
* The BFSCount function returns an array of counts from a breadth-first search of nodes.
|
||||
* @returns The BFSCount() function returns an array of numbers, specifically the count property of each node in the
|
||||
* BFS traversal.
|
||||
* bfs traversal.
|
||||
*/
|
||||
BFSCount(): number[] {
|
||||
const nodes = super.BFS('node');
|
||||
const nodes = super.bfs('node');
|
||||
return nodes.map(node => node.count);
|
||||
}
|
||||
|
||||
|
@ -549,56 +540,53 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
* traversal pattern for the Morris traversal algorithm. It can have one of three values: 'in', 'pre', or 'post'.
|
||||
* @returns The function `morrisCount` returns an array of numbers.
|
||||
*/
|
||||
morrisCount(pattern?: 'in' | 'pre' | 'post'): number[] {
|
||||
pattern = pattern || 'in';
|
||||
morrisCount(pattern: DFSOrderPattern = 'in'): number[] {
|
||||
const nodes = super.morris(pattern, 'node');
|
||||
return nodes.map(node => node.count);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function DFSIterativeCount performs an iterative depth-first search and returns an array of node counts based on
|
||||
* The function dfsCountIterative performs an iterative depth-first search and returns an array of node counts based on
|
||||
* the specified traversal pattern.
|
||||
* @param {'in' | 'pre' | 'post'} [pattern] - The pattern parameter is a string that specifies the traversal order for
|
||||
* the Depth-First Search (DFS) algorithm. It can have three possible values: 'in', 'pre', or 'post'.
|
||||
* @returns The DFSIterativeCount function returns an array of numbers, which represents the count property of each node
|
||||
* in the DFS traversal.
|
||||
* the Depth-First Search (dfs) algorithm. It can have three possible values: 'in', 'pre', or 'post'.
|
||||
* @returns The dfsCountIterative function returns an array of numbers, which represents the count property of each node
|
||||
* in the dfs traversal.
|
||||
*/
|
||||
DFSIterativeCount(pattern?: 'in' | 'pre' | 'post'): number[] {
|
||||
pattern = pattern ?? 'in';
|
||||
const nodes = super.DFSIterative(pattern, 'node');
|
||||
dfsCountIterative(pattern: DFSOrderPattern = 'in'): number[] {
|
||||
const nodes = super.dfsIterative(pattern, 'node');
|
||||
return nodes.map(node => node.count);
|
||||
}
|
||||
|
||||
/**
|
||||
* The DFSCount function returns an array of counts for each node in a depth-first search traversal.
|
||||
* The dfsCount function returns an array of counts for each node in a depth-first search traversal.
|
||||
* @param {DFSOrderPattern} [pattern] - The pattern parameter is an optional parameter that specifies the order in which
|
||||
* the Depth-First Search (DFS) algorithm should traverse the nodes. It can have one of the following values:
|
||||
* @returns The DFSCount function returns an array of numbers, specifically the count property of each node in the DFS
|
||||
* the Depth-First Search (dfs) algorithm should traverse the nodes. It can have one of the following values:
|
||||
* @returns The dfsCount function returns an array of numbers, specifically the count property of each node in the dfs
|
||||
* traversal.
|
||||
*/
|
||||
DFSCount(pattern?: DFSOrderPattern): number[] {
|
||||
pattern = pattern ?? 'in';
|
||||
const nodes = super.DFS(pattern, 'node');
|
||||
dfsCount(pattern: DFSOrderPattern = 'in'): number[] {
|
||||
const nodes = super.dfs(pattern, 'node');
|
||||
return nodes.map(node => node.count);
|
||||
}
|
||||
|
||||
/**
|
||||
* The `lesserSumCount` function calculates the sum of the counts of all nodes in a binary tree that have a lesser
|
||||
* value than a given node.
|
||||
* @param {N | BinaryTreeNodeId | null} beginNode - The `beginNode` parameter can be one of the following:
|
||||
* @param {N | BinaryTreeNodeKey | null} beginNode - The `beginNode` parameter can be one of the following:
|
||||
* @returns the sum of the counts of nodes in the binary tree that have a lesser value than the given beginNode.
|
||||
*/
|
||||
lesserSumCount(beginNode: N | BinaryTreeNodeId | null): number {
|
||||
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'id');
|
||||
lesserSumCount(beginNode: N | BinaryTreeNodeKey | null): number {
|
||||
if (typeof beginNode === 'number') beginNode = this.get(beginNode, 'key');
|
||||
if (!beginNode) return 0;
|
||||
if (!this.root) return 0;
|
||||
const id = beginNode.id;
|
||||
const key = beginNode.key;
|
||||
|
||||
let sum = 0;
|
||||
|
||||
if (this.loopType === LoopType.RECURSIVE) {
|
||||
const _traverse = (cur: N): void => {
|
||||
const compared = this._compare(cur.id, id);
|
||||
const compared = this._compare(cur.key, key);
|
||||
if (compared === CP.eq) {
|
||||
if (cur.right) sum += this.subTreeSumCount(cur.right);
|
||||
return;
|
||||
|
@ -619,7 +607,7 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
while (queue.length > 0) {
|
||||
const cur = queue.shift();
|
||||
if (cur) {
|
||||
const compared = this._compare(cur.id, id);
|
||||
const compared = this._compare(cur.key, key);
|
||||
if (compared === CP.eq) {
|
||||
if (cur.right) sum += this.subTreeSumCount(cur.right);
|
||||
return sum;
|
||||
|
@ -643,25 +631,25 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
/**
|
||||
* The function `allGreaterNodesAddCount` updates the count property of all nodes in a binary tree that have an ID
|
||||
* greater than a given ID by a specified delta value.
|
||||
* @param {N | BinaryTreeNodeId | null} node - The `node` parameter can be one of the following:
|
||||
* @param {N | BinaryTreeNodeKey | null} node - The `node` parameter can be one of the following:
|
||||
* @param {number} delta - The `delta` parameter is a number that represents the amount by which the `count` property
|
||||
* of each node should be increased.
|
||||
* @returns a boolean value.
|
||||
*/
|
||||
allGreaterNodesAddCount(node: N | BinaryTreeNodeId | null, delta: number): boolean {
|
||||
if (typeof node === 'number') node = this.get(node, 'id');
|
||||
allGreaterNodesAddCount(node: N | BinaryTreeNodeKey | null, delta: number): boolean {
|
||||
if (typeof node === 'number') node = this.get(node, 'key');
|
||||
if (!node) return false;
|
||||
const id = node.id;
|
||||
const key = node.key;
|
||||
if (!this.root) return false;
|
||||
|
||||
if (this.loopType === LoopType.RECURSIVE) {
|
||||
const _traverse = (cur: N) => {
|
||||
const compared = this._compare(cur.id, id);
|
||||
const compared = this._compare(cur.key, key);
|
||||
if (compared === CP.gt) cur.count += delta;
|
||||
|
||||
if (!cur.left && !cur.right) return;
|
||||
if (cur.left && this._compare(cur.left.id, id) === CP.gt) _traverse(cur.left);
|
||||
if (cur.right && this._compare(cur.right.id, id) === CP.gt) _traverse(cur.right);
|
||||
if (cur.left && this._compare(cur.left.key, key) === CP.gt) _traverse(cur.left);
|
||||
if (cur.right && this._compare(cur.right.key, key) === CP.gt) _traverse(cur.right);
|
||||
};
|
||||
|
||||
_traverse(this.root);
|
||||
|
@ -671,11 +659,11 @@ export class TreeMultiset<N extends TreeMultisetNode<N['val'], N> = TreeMultiset
|
|||
while (queue.length > 0) {
|
||||
const cur = queue.shift();
|
||||
if (cur) {
|
||||
const compared = this._compare(cur.id, id);
|
||||
const compared = this._compare(cur.key, key);
|
||||
if (compared === CP.gt) cur.count += delta;
|
||||
|
||||
if (cur.left && this._compare(cur.left.id, id) === CP.gt) queue.push(cur.left);
|
||||
if (cur.right && this._compare(cur.right.id, id) === CP.gt) queue.push(cur.right);
|
||||
if (cur.left && this._compare(cur.left.key, key) === CP.gt) queue.push(cur.left);
|
||||
if (cur.right && this._compare(cur.right.key, key) === CP.gt) queue.push(cur.right);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export class TwoThreeTree {}
|
|
@ -1,36 +1,36 @@
|
|||
/**
|
||||
* data-structure-typed
|
||||
*
|
||||
* @author Tyler Zeng
|
||||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @author Kirk Qi
|
||||
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import {arrayRemove, uuidV4} from '../../utils';
|
||||
import {PriorityQueue} from '../priority-queue';
|
||||
import type {DijkstraResult, VertexId} from '../../types';
|
||||
import {IAbstractGraph} from '../../interfaces';
|
||||
import type {DijkstraResult, VertexKey} from '../../types';
|
||||
import {IGraph} from '../../interfaces';
|
||||
|
||||
export abstract class AbstractVertex<V = any> {
|
||||
/**
|
||||
* The function is a protected constructor that takes an id and an optional value as parameters.
|
||||
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex. It is
|
||||
* The function is a protected constructor that takes an key and an optional value as parameters.
|
||||
* @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is
|
||||
* used to uniquely identify the vertex object.
|
||||
* @param {V} [val] - The parameter "val" is an optional parameter of type V. It is used to assign a value to the
|
||||
* vertex. If no value is provided, it will be set to undefined.
|
||||
*/
|
||||
protected constructor(id: VertexId, val?: V) {
|
||||
this._id = id;
|
||||
protected constructor(key: VertexKey, val?: V) {
|
||||
this._key = key;
|
||||
this._val = val;
|
||||
}
|
||||
|
||||
private _id: VertexId;
|
||||
private _key: VertexKey;
|
||||
|
||||
get id(): VertexId {
|
||||
return this._id;
|
||||
get key(): VertexKey {
|
||||
return this._key;
|
||||
}
|
||||
|
||||
set id(v: VertexId) {
|
||||
this._id = v;
|
||||
set key(v: VertexKey) {
|
||||
this._key = v;
|
||||
}
|
||||
|
||||
private _val: V | undefined;
|
||||
|
@ -104,21 +104,21 @@ export abstract class AbstractEdge<V = any> {
|
|||
export abstract class AbstractGraph<
|
||||
V extends AbstractVertex<any> = AbstractVertex<any>,
|
||||
E extends AbstractEdge<any> = AbstractEdge<any>
|
||||
> implements IAbstractGraph<V, E>
|
||||
> implements IGraph<V, E>
|
||||
{
|
||||
private _vertices: Map<VertexId, V> = new Map<VertexId, V>();
|
||||
private _vertices: Map<VertexKey, V> = new Map<VertexKey, V>();
|
||||
|
||||
get vertices(): Map<VertexId, V> {
|
||||
get vertices(): Map<VertexKey, V> {
|
||||
return this._vertices;
|
||||
}
|
||||
|
||||
/**
|
||||
* In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it.
|
||||
* This means that using abstract methods in the parent class cannot constrain the grandchild classes. Defining methods within an interface also cannot constrain the descendant classes. When inheriting from this class, developers need to be aware that this method needs to be overridden.
|
||||
* @param id
|
||||
* @param key
|
||||
* @param val
|
||||
*/
|
||||
abstract createVertex(id: VertexId, val?: V): V;
|
||||
abstract createVertex(key: VertexKey, val?: V): V;
|
||||
|
||||
/**
|
||||
* In TypeScript, a subclass inherits the interface implementation of its parent class, without needing to implement the same interface again in the subclass. This behavior differs from Java's approach. In Java, if a parent class implements an interface, the subclass needs to explicitly implement the same interface, even if the parent class has already implemented it.
|
||||
|
@ -128,75 +128,75 @@ export abstract class AbstractGraph<
|
|||
* @param weight
|
||||
* @param val
|
||||
*/
|
||||
abstract createEdge(srcOrV1: VertexId | string, destOrV2: VertexId | string, weight?: number, val?: E): E;
|
||||
abstract createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): E;
|
||||
|
||||
abstract removeEdge(edge: E): E | null;
|
||||
|
||||
abstract getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
|
||||
abstract getEdge(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null;
|
||||
|
||||
abstract degreeOf(vertexOrId: V | VertexId): number;
|
||||
abstract degreeOf(vertexOrKey: V | VertexKey): number;
|
||||
|
||||
abstract edgeSet(): E[];
|
||||
|
||||
abstract edgesOf(vertexOrId: V | VertexId): E[];
|
||||
abstract edgesOf(vertexOrKey: V | VertexKey): E[];
|
||||
|
||||
abstract getNeighbors(vertexOrId: V | VertexId): V[];
|
||||
abstract getNeighbors(vertexOrKey: V | VertexKey): V[];
|
||||
|
||||
abstract getEndsOfEdge(edge: E): [V, V] | null;
|
||||
|
||||
/**
|
||||
* The function "getVertex" returns the vertex with the specified ID or null if it doesn't exist.
|
||||
* @param {VertexId} vertexId - The `vertexId` parameter is the identifier of the vertex that you want to retrieve from
|
||||
* @param {VertexKey} vertexKey - The `vertexKey` parameter is the identifier of the vertex that you want to retrieve from
|
||||
* the `_vertices` map.
|
||||
* @returns The method `getVertex` returns the vertex with the specified `vertexId` if it exists in the `_vertices`
|
||||
* @returns The method `getVertex` returns the vertex with the specified `vertexKey` if it exists in the `_vertices`
|
||||
* map. If the vertex does not exist, it returns `null`.
|
||||
*/
|
||||
getVertex(vertexId: VertexId): V | null {
|
||||
return this._vertices.get(vertexId) || null;
|
||||
getVertex(vertexKey: VertexKey): V | null {
|
||||
return this._vertices.get(vertexKey) || null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks if a vertex exists in a graph.
|
||||
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexId`).
|
||||
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexKey`).
|
||||
* @returns a boolean value.
|
||||
*/
|
||||
hasVertex(vertexOrId: V | VertexId): boolean {
|
||||
return this._vertices.has(this._getVertexId(vertexOrId));
|
||||
hasVertex(vertexOrKey: V | VertexKey): boolean {
|
||||
return this._vertices.has(this._getVertexKey(vertexOrKey));
|
||||
}
|
||||
|
||||
addVertex(vertex: V): boolean;
|
||||
|
||||
addVertex(id: VertexId, val?: V['val']): boolean;
|
||||
addVertex(key: VertexKey, val?: V['val']): boolean;
|
||||
|
||||
addVertex(idOrVertex: VertexId | V, val?: V['val']): boolean {
|
||||
if (idOrVertex instanceof AbstractVertex) {
|
||||
return this._addVertexOnly(idOrVertex);
|
||||
addVertex(keyOrVertex: VertexKey | V, val?: V['val']): boolean {
|
||||
if (keyOrVertex instanceof AbstractVertex) {
|
||||
return this._addVertexOnly(keyOrVertex);
|
||||
} else {
|
||||
const newVertex = this.createVertex(idOrVertex, val);
|
||||
const newVertex = this.createVertex(keyOrVertex, val);
|
||||
return this._addVertexOnly(newVertex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The `removeVertex` function removes a vertex from a graph by its ID or by the vertex object itself.
|
||||
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexId`).
|
||||
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexKey`).
|
||||
* @returns The method is returning a boolean value.
|
||||
*/
|
||||
removeVertex(vertexOrId: V | VertexId): boolean {
|
||||
const vertexId = this._getVertexId(vertexOrId);
|
||||
return this._vertices.delete(vertexId);
|
||||
removeVertex(vertexOrKey: V | VertexKey): boolean {
|
||||
const vertexKey = this._getVertexKey(vertexOrKey);
|
||||
return this._vertices.delete(vertexKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function removes all vertices from a graph and returns a boolean indicating if any vertices were removed.
|
||||
* @param {V[] | VertexId[]} vertices - The `vertices` parameter can be either an array of vertices (`V[]`) or an array
|
||||
* of vertex IDs (`VertexId[]`).
|
||||
* @param {V[] | VertexKey[]} vertices - The `vertices` parameter can be either an array of vertices (`V[]`) or an array
|
||||
* of vertex IDs (`VertexKey[]`).
|
||||
* @returns a boolean value. It returns true if at least one vertex was successfully removed, and false if no vertices
|
||||
* were removed.
|
||||
*/
|
||||
removeAllVertices(vertices: V[] | VertexId[]): boolean {
|
||||
removeAllVertices(vertices: V[] | VertexKey[]): boolean {
|
||||
const removed: boolean[] = [];
|
||||
for (const v of vertices) {
|
||||
removed.push(this.removeVertex(v));
|
||||
|
@ -206,50 +206,50 @@ export abstract class AbstractGraph<
|
|||
|
||||
/**
|
||||
* The function checks if there is an edge between two vertices and returns a boolean value indicating the result.
|
||||
* @param {VertexId | V} v1 - The parameter v1 can be either a VertexId or a V. A VertexId represents the unique
|
||||
* @param {VertexKey | V} v1 - The parameter v1 can be either a VertexKey or a V. A VertexKey represents the unique
|
||||
* identifier of a vertex in a graph, while V represents the type of the vertex object itself.
|
||||
* @param {VertexId | V} v2 - The parameter `v2` represents the second vertex in the edge. It can be either a
|
||||
* `VertexId` or a `V` type, which represents the type of the vertex.
|
||||
* @param {VertexKey | V} v2 - The parameter `v2` represents the second vertex in the edge. It can be either a
|
||||
* `VertexKey` or a `V` type, which represents the type of the vertex.
|
||||
* @returns A boolean value is being returned.
|
||||
*/
|
||||
hasEdge(v1: VertexId | V, v2: VertexId | V): boolean {
|
||||
hasEdge(v1: VertexKey | V, v2: VertexKey | V): boolean {
|
||||
const edge = this.getEdge(v1, v2);
|
||||
return !!edge;
|
||||
}
|
||||
|
||||
addEdge(edge: E): boolean;
|
||||
|
||||
addEdge(src: V | VertexId, dest: V | VertexId, weight?: number, val?: E['val']): boolean;
|
||||
addEdge(src: V | VertexKey, dest: V | VertexKey, weight?: number, val?: E['val']): boolean;
|
||||
|
||||
addEdge(srcOrEdge: V | VertexId | E, dest?: V | VertexId, weight?: number, val?: E['val']): boolean {
|
||||
addEdge(srcOrEdge: V | VertexKey | E, dest?: V | VertexKey, weight?: number, val?: E['val']): boolean {
|
||||
if (srcOrEdge instanceof AbstractEdge) {
|
||||
return this._addEdgeOnly(srcOrEdge);
|
||||
} else {
|
||||
if (dest instanceof AbstractVertex || typeof dest === 'string' || typeof dest === 'number') {
|
||||
if (!(this.hasVertex(srcOrEdge) && this.hasVertex(dest))) return false;
|
||||
if (srcOrEdge instanceof AbstractVertex) srcOrEdge = srcOrEdge.id;
|
||||
if (dest instanceof AbstractVertex) dest = dest.id;
|
||||
if (srcOrEdge instanceof AbstractVertex) srcOrEdge = srcOrEdge.key;
|
||||
if (dest instanceof AbstractVertex) dest = dest.key;
|
||||
const newEdge = this.createEdge(srcOrEdge, dest, weight, val);
|
||||
return this._addEdgeOnly(newEdge);
|
||||
} else {
|
||||
throw new Error('dest must be a Vertex or vertex id while srcOrEdge is an Edge');
|
||||
throw new Error('dest must be a Vertex or vertex key while srcOrEdge is an Edge');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function sets the weight of an edge between two vertices in a graph.
|
||||
* @param {VertexId | V} srcOrId - The `srcOrId` parameter can be either a `VertexId` or a `V` object. It represents
|
||||
* @param {VertexKey | V} srcOrKey - The `srcOrKey` parameter can be either a `VertexKey` or a `V` object. It represents
|
||||
* the source vertex of the edge.
|
||||
* @param {VertexId | V} destOrId - The `destOrId` parameter represents the destination vertex of the edge. It can be
|
||||
* either a `VertexId` or a vertex object `V`.
|
||||
* @param {number} weight - The weight parameter represents the weight of the edge between the source vertex (srcOrId)
|
||||
* and the destination vertex (destOrId).
|
||||
* @param {VertexKey | V} destOrKey - The `destOrKey` parameter represents the destination vertex of the edge. It can be
|
||||
* either a `VertexKey` or a vertex object `V`.
|
||||
* @param {number} weight - The weight parameter represents the weight of the edge between the source vertex (srcOrKey)
|
||||
* and the destination vertex (destOrKey).
|
||||
* @returns a boolean value. If the edge exists between the source and destination vertices, the function will update
|
||||
* the weight of the edge and return true. If the edge does not exist, the function will return false.
|
||||
*/
|
||||
setEdgeWeight(srcOrId: VertexId | V, destOrId: VertexId | V, weight: number): boolean {
|
||||
const edge = this.getEdge(srcOrId, destOrId);
|
||||
setEdgeWeight(srcOrKey: VertexKey | V, destOrKey: VertexKey | V, weight: number): boolean {
|
||||
const edge = this.getEdge(srcOrKey, destOrKey);
|
||||
if (edge) {
|
||||
edge.weight = weight;
|
||||
return true;
|
||||
|
@ -260,12 +260,12 @@ export abstract class AbstractGraph<
|
|||
|
||||
/**
|
||||
* The function `getAllPathsBetween` finds all paths between two vertices in a graph using depth-first search.
|
||||
* @param {V | VertexId} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexId`).
|
||||
* @param {V | VertexKey} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexKey`).
|
||||
* It is the starting vertex for finding paths.
|
||||
* @param {V | VertexId} v2 - The parameter `v2` represents either a vertex object (`V`) or a vertex ID (`VertexId`).
|
||||
* @param {V | VertexKey} v2 - The parameter `v2` represents either a vertex object (`V`) or a vertex ID (`VertexKey`).
|
||||
* @returns The function `getAllPathsBetween` returns an array of arrays of vertices (`V[][]`).
|
||||
*/
|
||||
getAllPathsBetween(v1: V | VertexId, v2: V | VertexId): V[][] {
|
||||
getAllPathsBetween(v1: V | VertexKey, v2: V | VertexKey): V[][] {
|
||||
const paths: V[][] = [];
|
||||
const vertex1 = this._getVertex(v1);
|
||||
const vertex2 = this._getVertex(v2);
|
||||
|
@ -312,8 +312,8 @@ export abstract class AbstractGraph<
|
|||
/**
|
||||
* The function `getMinCostBetween` calculates the minimum cost between two vertices in a graph, either based on edge
|
||||
* weights or using a breadth-first search algorithm.
|
||||
* @param {V | VertexId} v1 - The parameter `v1` represents the starting vertex or its ID.
|
||||
* @param {V | VertexId} v2 - The parameter `v2` represents the destination vertex or its ID. It is the vertex to which
|
||||
* @param {V | VertexKey} v1 - The parameter `v1` represents the starting vertex or its ID.
|
||||
* @param {V | VertexKey} v2 - The parameter `v2` represents the destination vertex or its ID. It is the vertex to which
|
||||
* you want to find the minimum cost or weight from the source vertex `v1`.
|
||||
* @param {boolean} [isWeight] - isWeight is an optional parameter that indicates whether the graph edges have weights.
|
||||
* If isWeight is set to true, the function will calculate the minimum cost between v1 and v2 based on the weights of
|
||||
|
@ -323,7 +323,7 @@ export abstract class AbstractGraph<
|
|||
* vertices. If `isWeight` is `false` or not provided, it uses a breadth-first search (BFS) algorithm to calculate the
|
||||
* minimum number of
|
||||
*/
|
||||
getMinCostBetween(v1: V | VertexId, v2: V | VertexId, isWeight?: boolean): number | null {
|
||||
getMinCostBetween(v1: V | VertexKey, v2: V | VertexKey, isWeight?: boolean): number | null {
|
||||
if (isWeight === undefined) isWeight = false;
|
||||
|
||||
if (isWeight) {
|
||||
|
@ -371,9 +371,9 @@ export abstract class AbstractGraph<
|
|||
/**
|
||||
* The function `getMinPathBetween` returns the minimum path between two vertices in a graph, either based on weight or
|
||||
* using a breadth-first search algorithm.
|
||||
* @param {V | VertexId} v1 - The parameter `v1` represents the starting vertex of the path. It can be either a vertex
|
||||
* object (`V`) or a vertex ID (`VertexId`).
|
||||
* @param {V | VertexId} v2 - V | VertexId - The second vertex or vertex ID between which we want to find the minimum
|
||||
* @param {V | VertexKey} v1 - The parameter `v1` represents the starting vertex of the path. It can be either a vertex
|
||||
* object (`V`) or a vertex ID (`VertexKey`).
|
||||
* @param {V | VertexKey} v2 - V | VertexKey - The second vertex or vertex ID between which we want to find the minimum
|
||||
* path.
|
||||
* @param {boolean} [isWeight] - A boolean flag indicating whether to consider the weight of edges in finding the
|
||||
* minimum path. If set to true, the function will use Dijkstra's algorithm to find the minimum weighted path. If set
|
||||
|
@ -381,7 +381,7 @@ export abstract class AbstractGraph<
|
|||
* @returns The function `getMinPathBetween` returns an array of vertices (`V[]`) representing the minimum path between
|
||||
* two vertices (`v1` and `v2`). If there is no path between the vertices, it returns `null`.
|
||||
*/
|
||||
getMinPathBetween(v1: V | VertexId, v2: V | VertexId, isWeight?: boolean): V[] | null {
|
||||
getMinPathBetween(v1: V | VertexKey, v2: V | VertexKey, isWeight?: boolean): V[] | null {
|
||||
if (isWeight === undefined) isWeight = false;
|
||||
|
||||
if (isWeight) {
|
||||
|
@ -440,9 +440,9 @@ export abstract class AbstractGraph<
|
|||
* Dijkstra algorithm time: O(VE) space: O(V + E)
|
||||
* The function `dijkstraWithoutHeap` implements Dijkstra's algorithm to find the shortest path between two vertices in
|
||||
* a graph without using a heap data structure.
|
||||
* @param {V | VertexId} src - The source vertex from which to start the Dijkstra's algorithm. It can be either a
|
||||
* @param {V | VertexKey} src - The source vertex from which to start the Dijkstra's algorithm. It can be either a
|
||||
* vertex object or a vertex ID.
|
||||
* @param {V | VertexId | null} [dest] - The `dest` parameter in the `dijkstraWithoutHeap` function is an optional
|
||||
* @param {V | VertexKey | null} [dest] - The `dest` parameter in the `dijkstraWithoutHeap` function is an optional
|
||||
* parameter that specifies the destination vertex for the Dijkstra algorithm. It can be either a vertex object or its
|
||||
* identifier. If no destination is provided, the value is set to `null`.
|
||||
* @param {boolean} [getMinDist] - The `getMinDist` parameter is a boolean flag that determines whether the minimum
|
||||
|
@ -454,8 +454,8 @@ export abstract class AbstractGraph<
|
|||
* @returns The function `dijkstraWithoutHeap` returns an object of type `DijkstraResult<V>`.
|
||||
*/
|
||||
dijkstraWithoutHeap(
|
||||
src: V | VertexId,
|
||||
dest?: V | VertexId | null,
|
||||
src: V | VertexKey,
|
||||
dest?: V | VertexKey | null,
|
||||
getMinDist?: boolean,
|
||||
genPaths?: boolean
|
||||
): DijkstraResult<V> {
|
||||
|
@ -481,8 +481,8 @@ export abstract class AbstractGraph<
|
|||
}
|
||||
|
||||
for (const vertex of vertices) {
|
||||
const vertexOrId = vertex[1];
|
||||
if (vertexOrId instanceof AbstractVertex) distMap.set(vertexOrId, Infinity);
|
||||
const vertexOrKey = vertex[1];
|
||||
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
|
||||
}
|
||||
distMap.set(srcVertex, 0);
|
||||
preMap.set(srcVertex, null);
|
||||
|
@ -503,11 +503,11 @@ export abstract class AbstractGraph<
|
|||
|
||||
const getPaths = (minV: V | null) => {
|
||||
for (const vertex of vertices) {
|
||||
const vertexOrId = vertex[1];
|
||||
const vertexOrKey = vertex[1];
|
||||
|
||||
if (vertexOrId instanceof AbstractVertex) {
|
||||
const path: V[] = [vertexOrId];
|
||||
let parent = preMap.get(vertexOrId);
|
||||
if (vertexOrKey instanceof AbstractVertex) {
|
||||
const path: V[] = [vertexOrKey];
|
||||
let parent = preMap.get(vertexOrKey);
|
||||
while (parent) {
|
||||
path.push(parent);
|
||||
parent = preMap.get(parent);
|
||||
|
@ -580,9 +580,9 @@ export abstract class AbstractGraph<
|
|||
* Dijkstra's algorithm is used to find the shortest paths from a source node to all other nodes in a graph. Its basic idea is to repeatedly choose the node closest to the source node and update the distances of other nodes using this node as an intermediary. Dijkstra's algorithm requires that the edge weights in the graph are non-negative.
|
||||
* The `dijkstra` function implements Dijkstra's algorithm to find the shortest path between a source vertex and an
|
||||
* optional destination vertex, and optionally returns the minimum distance, the paths, and other information.
|
||||
* @param {V | VertexId} src - The `src` parameter represents the source vertex from which the Dijkstra algorithm will
|
||||
* @param {V | VertexKey} src - The `src` parameter represents the source vertex from which the Dijkstra algorithm will
|
||||
* start. It can be either a vertex object or a vertex ID.
|
||||
* @param {V | VertexId | null} [dest] - The `dest` parameter is the destination vertex or vertex ID. It specifies the
|
||||
* @param {V | VertexKey | null} [dest] - The `dest` parameter is the destination vertex or vertex ID. It specifies the
|
||||
* vertex to which the shortest path is calculated from the source vertex. If no destination is provided, the algorithm
|
||||
* will calculate the shortest paths to all other vertices from the source vertex.
|
||||
* @param {boolean} [getMinDist] - The `getMinDist` parameter is a boolean flag that determines whether the minimum
|
||||
|
@ -593,7 +593,12 @@ export abstract class AbstractGraph<
|
|||
* shortest paths from the source vertex to all other vertices in the graph. If `genPaths
|
||||
* @returns The function `dijkstra` returns an object of type `DijkstraResult<V>`.
|
||||
*/
|
||||
dijkstra(src: V | VertexId, dest?: V | VertexId | null, getMinDist?: boolean, genPaths?: boolean): DijkstraResult<V> {
|
||||
dijkstra(
|
||||
src: V | VertexKey,
|
||||
dest?: V | VertexKey | null,
|
||||
getMinDist?: boolean,
|
||||
genPaths?: boolean
|
||||
): DijkstraResult<V> {
|
||||
if (getMinDist === undefined) getMinDist = false;
|
||||
if (genPaths === undefined) genPaths = false;
|
||||
|
||||
|
@ -613,14 +618,12 @@ export abstract class AbstractGraph<
|
|||
if (!srcVertex) return null;
|
||||
|
||||
for (const vertex of vertices) {
|
||||
const vertexOrId = vertex[1];
|
||||
if (vertexOrId instanceof AbstractVertex) distMap.set(vertexOrId, Infinity);
|
||||
const vertexOrKey = vertex[1];
|
||||
if (vertexOrKey instanceof AbstractVertex) distMap.set(vertexOrKey, Infinity);
|
||||
}
|
||||
|
||||
const heap = new PriorityQueue<{id: number; val: V}>({
|
||||
comparator: (a, b) => a.id - b.id
|
||||
});
|
||||
heap.add({id: 0, val: srcVertex});
|
||||
const heap = new PriorityQueue<{key: number; val: V}>((a, b) => a.key - b.key);
|
||||
heap.add({key: 0, val: srcVertex});
|
||||
|
||||
distMap.set(srcVertex, 0);
|
||||
preMap.set(srcVertex, null);
|
||||
|
@ -632,10 +635,10 @@ export abstract class AbstractGraph<
|
|||
*/
|
||||
const getPaths = (minV: V | null) => {
|
||||
for (const vertex of vertices) {
|
||||
const vertexOrId = vertex[1];
|
||||
if (vertexOrId instanceof AbstractVertex) {
|
||||
const path: V[] = [vertexOrId];
|
||||
let parent = preMap.get(vertexOrId);
|
||||
const vertexOrKey = vertex[1];
|
||||
if (vertexOrKey instanceof AbstractVertex) {
|
||||
const path: V[] = [vertexOrKey];
|
||||
let parent = preMap.get(vertexOrKey);
|
||||
while (parent) {
|
||||
path.push(parent);
|
||||
parent = preMap.get(parent);
|
||||
|
@ -649,7 +652,7 @@ export abstract class AbstractGraph<
|
|||
|
||||
while (heap.size > 0) {
|
||||
const curHeapNode = heap.poll();
|
||||
const dist = curHeapNode?.id;
|
||||
const dist = curHeapNode?.key;
|
||||
const cur = curHeapNode?.val;
|
||||
if (dist !== undefined) {
|
||||
if (cur) {
|
||||
|
@ -671,7 +674,7 @@ export abstract class AbstractGraph<
|
|||
const distSrcToNeighbor = distMap.get(neighbor);
|
||||
if (distSrcToNeighbor) {
|
||||
if (dist + weight < distSrcToNeighbor) {
|
||||
heap.add({id: dist + weight, val: neighbor});
|
||||
heap.add({key: dist + weight, val: neighbor});
|
||||
preMap.set(neighbor, cur);
|
||||
distMap.set(neighbor, dist + weight);
|
||||
}
|
||||
|
@ -712,7 +715,7 @@ export abstract class AbstractGraph<
|
|||
* The Bellman-Ford algorithm is also used to find the shortest paths from a source node to all other nodes in a graph. Unlike Dijkstra's algorithm, it can handle edge weights that are negative. Its basic idea involves iterative relaxation of all edges for several rounds to gradually approximate the shortest paths. Due to its ability to handle negative-weight edges, the Bellman-Ford algorithm is more flexible in some scenarios.
|
||||
* The `bellmanFord` function implements the Bellman-Ford algorithm to find the shortest path from a source vertex to
|
||||
* all other vertices in a graph, and optionally detects negative cycles and generates the minimum path.
|
||||
* @param {V | VertexId} src - The `src` parameter is the source vertex from which the Bellman-Ford algorithm will
|
||||
* @param {V | VertexKey} src - The `src` parameter is the source vertex from which the Bellman-Ford algorithm will
|
||||
* start calculating the shortest paths. It can be either a vertex object or a vertex ID.
|
||||
* @param {boolean} [scanNegativeCycle] - A boolean flag indicating whether to scan for negative cycles in the graph.
|
||||
* @param {boolean} [getMin] - The `getMin` parameter is a boolean flag that determines whether the algorithm should
|
||||
|
@ -722,7 +725,7 @@ export abstract class AbstractGraph<
|
|||
* vertex.
|
||||
* @returns The function `bellmanFord` returns an object with the following properties:
|
||||
*/
|
||||
bellmanFord(src: V | VertexId, scanNegativeCycle?: boolean, getMin?: boolean, genPath?: boolean) {
|
||||
bellmanFord(src: V | VertexKey, scanNegativeCycle?: boolean, getMin?: boolean, genPath?: boolean) {
|
||||
if (getMin === undefined) getMin = false;
|
||||
if (genPath === undefined) genPath = false;
|
||||
|
||||
|
@ -780,10 +783,10 @@ export abstract class AbstractGraph<
|
|||
|
||||
if (genPath) {
|
||||
for (const vertex of vertices) {
|
||||
const vertexOrId = vertex[1];
|
||||
if (vertexOrId instanceof AbstractVertex) {
|
||||
const path: V[] = [vertexOrId];
|
||||
let parent = preMap.get(vertexOrId);
|
||||
const vertexOrKey = vertex[1];
|
||||
if (vertexOrKey instanceof AbstractVertex) {
|
||||
const path: V[] = [vertexOrKey];
|
||||
let parent = preMap.get(vertexOrKey);
|
||||
while (parent !== undefined) {
|
||||
path.push(parent);
|
||||
parent = preMap.get(parent);
|
||||
|
@ -884,7 +887,7 @@ export abstract class AbstractGraph<
|
|||
}
|
||||
|
||||
/**
|
||||
* Tarjan is an algorithm based on DFS,which is used to solve the connectivity problem of graphs.
|
||||
* Tarjan is an algorithm based on dfs,which is used to solve the connectivity problem of graphs.
|
||||
* Tarjan can find cycles in directed or undirected graph
|
||||
* Tarjan can find the articulation points and bridges(critical edges) of undirected graphs in linear time,
|
||||
* Tarjan solve the bi-connected components of undirected graphs;
|
||||
|
@ -892,7 +895,7 @@ export abstract class AbstractGraph<
|
|||
* /
|
||||
|
||||
/**
|
||||
* Tarjan is an algorithm based on DFS,which is used to solve the connectivity problem of graphs.
|
||||
* Tarjan is an algorithm based on dfs,which is used to solve the connectivity problem of graphs.
|
||||
* Tarjan can find cycles in directed or undirected graph
|
||||
* Tarjan can find the articulation points and bridges(critical edges) of undirected graphs in linear time,
|
||||
* Tarjan solve the bi-connected components of undirected graphs;
|
||||
|
@ -913,8 +916,8 @@ export abstract class AbstractGraph<
|
|||
* @returns The function `tarjan` returns an object with the following properties:
|
||||
*/
|
||||
tarjan(needArticulationPoints?: boolean, needBridges?: boolean, needSCCs?: boolean, needCycles?: boolean) {
|
||||
// !! in undirected graph we will not let child visit parent when DFS
|
||||
// !! articulation point(in DFS search tree not in graph): (cur !== root && cur.has(child)) && (low(child) >= dfn(cur)) || (cur === root && cur.children() >= 2)
|
||||
// !! in undirected graph we will not let child visit parent when dfs
|
||||
// !! articulation point(in dfs search tree not in graph): (cur !== root && cur.has(child)) && (low(child) >= dfn(cur)) || (cur === root && cur.children() >= 2)
|
||||
// !! bridge: low(child) > dfn(cur)
|
||||
|
||||
const defaultConfig = false;
|
||||
|
@ -942,7 +945,7 @@ export abstract class AbstractGraph<
|
|||
lowMap.set(cur, dfn);
|
||||
|
||||
const neighbors = this.getNeighbors(cur);
|
||||
let childCount = 0; // child in DFS tree not child in graph
|
||||
let childCount = 0; // child in dfs tree not child in graph
|
||||
for (const neighbor of neighbors) {
|
||||
if (neighbor !== parent) {
|
||||
if (dfnMap.get(neighbor) === -1) {
|
||||
|
@ -1019,22 +1022,22 @@ export abstract class AbstractGraph<
|
|||
protected _addVertexOnly(newVertex: V): boolean {
|
||||
if (this.hasVertex(newVertex)) {
|
||||
return false;
|
||||
// throw (new Error('Duplicated vertex id is not allowed'));
|
||||
// throw (new Error('Duplicated vertex key is not allowed'));
|
||||
}
|
||||
this._vertices.set(newVertex.id, newVertex);
|
||||
this._vertices.set(newVertex.key, newVertex);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected _getVertex(vertexOrId: VertexId | V): V | null {
|
||||
const vertexId = this._getVertexId(vertexOrId);
|
||||
return this._vertices.get(vertexId) || null;
|
||||
protected _getVertex(vertexOrKey: VertexKey | V): V | null {
|
||||
const vertexKey = this._getVertexKey(vertexOrKey);
|
||||
return this._vertices.get(vertexKey) || null;
|
||||
}
|
||||
|
||||
protected _getVertexId(vertexOrId: V | VertexId): VertexId {
|
||||
return vertexOrId instanceof AbstractVertex ? vertexOrId.id : vertexOrId;
|
||||
protected _getVertexKey(vertexOrKey: V | VertexKey): VertexKey {
|
||||
return vertexOrKey instanceof AbstractVertex ? vertexOrKey.key : vertexOrKey;
|
||||
}
|
||||
|
||||
protected _setVertices(value: Map<VertexId, V>) {
|
||||
protected _setVertices(value: Map<VertexKey, V>) {
|
||||
this._vertices = value;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
*/
|
||||
import {arrayRemove} from '../../utils';
|
||||
import {AbstractEdge, AbstractGraph, AbstractVertex} from './abstract-graph';
|
||||
import type {TopologicalStatus, VertexId} from '../../types';
|
||||
import {IDirectedGraph} from '../../interfaces';
|
||||
import type {TopologicalStatus, VertexKey} from '../../types';
|
||||
import {IGraph} from '../../interfaces';
|
||||
|
||||
export class DirectedVertex<V = any> extends AbstractVertex<V> {
|
||||
/**
|
||||
* The constructor function initializes a vertex with an optional value.
|
||||
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex. It is
|
||||
* @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is
|
||||
* used to uniquely identify the vertex within a graph or data structure.
|
||||
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to initialize the value of the
|
||||
* vertex. If no value is provided, the vertex will be initialized with a default value.
|
||||
*/
|
||||
constructor(id: VertexId, val?: V) {
|
||||
super(id, val);
|
||||
constructor(key: VertexKey, val?: V) {
|
||||
super(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,44 +27,44 @@ export class DirectedEdge<V = any> extends AbstractEdge<V> {
|
|||
/**
|
||||
* The constructor function initializes the source and destination vertices of an edge, along with an optional weight
|
||||
* and value.
|
||||
* @param {VertexId} src - The `src` parameter is the source vertex ID. It represents the starting point of an edge in
|
||||
* @param {VertexKey} src - The `src` parameter is the source vertex ID. It represents the starting point of an edge in
|
||||
* a graph.
|
||||
* @param {VertexId} dest - The `dest` parameter represents the destination vertex of an edge. It is of type
|
||||
* `VertexId`, which is likely a unique identifier for a vertex in a graph.
|
||||
* @param {VertexKey} dest - The `dest` parameter represents the destination vertex of an edge. It is of type
|
||||
* `VertexKey`, which is likely a unique identifier for a vertex in a graph.
|
||||
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge.
|
||||
* @param {V} [val] - The `val` parameter is an optional parameter of type `V`. It represents the value associated with
|
||||
* the edge.
|
||||
*/
|
||||
constructor(src: VertexId, dest: VertexId, weight?: number, val?: V) {
|
||||
constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: V) {
|
||||
super(weight, val);
|
||||
this._src = src;
|
||||
this._dest = dest;
|
||||
}
|
||||
|
||||
private _src: VertexId;
|
||||
private _src: VertexKey;
|
||||
|
||||
get src(): VertexId {
|
||||
get src(): VertexKey {
|
||||
return this._src;
|
||||
}
|
||||
|
||||
set src(v: VertexId) {
|
||||
set src(v: VertexKey) {
|
||||
this._src = v;
|
||||
}
|
||||
|
||||
private _dest: VertexId;
|
||||
private _dest: VertexKey;
|
||||
|
||||
get dest(): VertexId {
|
||||
get dest(): VertexKey {
|
||||
return this._dest;
|
||||
}
|
||||
|
||||
set dest(v: VertexId) {
|
||||
set dest(v: VertexKey) {
|
||||
this._dest = v;
|
||||
}
|
||||
}
|
||||
|
||||
export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E extends DirectedEdge<any> = DirectedEdge>
|
||||
extends AbstractGraph<V, E>
|
||||
implements IDirectedGraph<V, E>
|
||||
implements IGraph<V, E>
|
||||
{
|
||||
/**
|
||||
* The constructor function initializes an instance of a class.
|
||||
|
@ -92,15 +92,15 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function creates a new vertex with an optional value and returns it.
|
||||
* @param {VertexId} id - The `id` parameter is the unique identifier for the vertex. It is of type `VertexId`, which
|
||||
* @param {VertexKey} key - The `key` parameter is the unique identifier for the vertex. It is of type `VertexKey`, which
|
||||
* could be a number or a string depending on how you want to identify your vertices.
|
||||
* @param [val] - The 'val' parameter is an optional value that can be assigned to the vertex. If a value is provided,
|
||||
* it will be assigned to the 'val' property of the vertex. If no value is provided, the 'val' property will be
|
||||
* assigned the same value as the 'id' parameter
|
||||
* assigned the same value as the 'key' parameter
|
||||
* @returns a new instance of a DirectedVertex object, casted as type V.
|
||||
*/
|
||||
createVertex(id: VertexId, val?: V['val']): V {
|
||||
return new DirectedVertex(id, val ?? id) as V;
|
||||
createVertex(key: VertexKey, val?: V['val']): V {
|
||||
return new DirectedVertex(key, val ?? key) as V;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -110,37 +110,37 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function creates a directed edge between two vertices with an optional weight and value.
|
||||
* @param {VertexId} src - The source vertex ID of the edge. It represents the starting point of the edge.
|
||||
* @param {VertexId} dest - The `dest` parameter is the identifier of the destination vertex for the edge.
|
||||
* @param {VertexKey} src - The source vertex ID of the edge. It represents the starting point of the edge.
|
||||
* @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for the edge.
|
||||
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge. If no
|
||||
* weight is provided, it defaults to 1.
|
||||
* @param [val] - The 'val' parameter is an optional value that can be assigned to the edge. It can be of any type and
|
||||
* is used to store additional information or data associated with the edge.
|
||||
* @returns a new instance of a DirectedEdge object, casted as type E.
|
||||
*/
|
||||
createEdge(src: VertexId, dest: VertexId, weight?: number, val?: E['val']): E {
|
||||
createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E['val']): E {
|
||||
return new DirectedEdge(src, dest, weight ?? 1, val) as E;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `getEdge` function retrieves an edge between two vertices based on their source and destination IDs.
|
||||
* @param {V | null | VertexId} srcOrId - The source vertex or its ID. It can be either a vertex object or a vertex ID.
|
||||
* @param {V | null | VertexId} destOrId - The `destOrId` parameter in the `getEdge` function represents the
|
||||
* destination vertex of the edge. It can be either a vertex object (`V`), a vertex ID (`VertexId`), or `null` if the
|
||||
* @param {V | null | VertexKey} srcOrKey - The source vertex or its ID. It can be either a vertex object or a vertex ID.
|
||||
* @param {V | null | VertexKey} destOrKey - The `destOrKey` parameter in the `getEdge` function represents the
|
||||
* destination vertex of the edge. It can be either a vertex object (`V`), a vertex ID (`VertexKey`), or `null` if the
|
||||
* destination is not specified.
|
||||
* @returns the first edge found between the source and destination vertices, or null if no such edge is found.
|
||||
*/
|
||||
getEdge(srcOrId: V | null | VertexId, destOrId: V | null | VertexId): E | null {
|
||||
getEdge(srcOrKey: V | null | VertexKey, destOrKey: V | null | VertexKey): E | null {
|
||||
let edges: E[] = [];
|
||||
|
||||
if (srcOrId !== null && destOrId !== null) {
|
||||
const src: V | null = this._getVertex(srcOrId);
|
||||
const dest: V | null = this._getVertex(destOrId);
|
||||
if (srcOrKey !== null && destOrKey !== null) {
|
||||
const src: V | null = this._getVertex(srcOrKey);
|
||||
const dest: V | null = this._getVertex(destOrKey);
|
||||
|
||||
if (src && dest) {
|
||||
const srcOutEdges = this._outEdgeMap.get(src);
|
||||
if (srcOutEdges) {
|
||||
edges = srcOutEdges.filter(edge => edge.dest === dest.id);
|
||||
edges = srcOutEdges.filter(edge => edge.dest === dest.key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,13 +150,13 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function removes an edge between two vertices in a graph and returns the removed edge.
|
||||
* @param {V | VertexId} srcOrId - The source vertex or its ID.
|
||||
* @param {V | VertexId} destOrId - The `destOrId` parameter represents the destination vertex or its ID.
|
||||
* @param {V | VertexKey} srcOrKey - The source vertex or its ID.
|
||||
* @param {V | VertexKey} destOrKey - The `destOrKey` parameter represents the destination vertex or its ID.
|
||||
* @returns the removed edge (E) if it exists, or null if either the source or destination vertex does not exist.
|
||||
*/
|
||||
removeEdgeSrcToDest(srcOrId: V | VertexId, destOrId: V | VertexId): E | null {
|
||||
const src: V | null = this._getVertex(srcOrId);
|
||||
const dest: V | null = this._getVertex(destOrId);
|
||||
removeEdgeSrcToDest(srcOrKey: V | VertexKey, destOrKey: V | VertexKey): E | null {
|
||||
const src: V | null = this._getVertex(srcOrKey);
|
||||
const dest: V | null = this._getVertex(destOrKey);
|
||||
let removed: E | null = null;
|
||||
if (!src || !dest) {
|
||||
return null;
|
||||
|
@ -164,12 +164,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
const srcOutEdges = this._outEdgeMap.get(src);
|
||||
if (srcOutEdges) {
|
||||
arrayRemove<E>(srcOutEdges, (edge: E) => edge.dest === dest.id);
|
||||
arrayRemove<E>(srcOutEdges, (edge: E) => edge.dest === dest.key);
|
||||
}
|
||||
|
||||
const destInEdges = this._inEdgeMap.get(dest);
|
||||
if (destInEdges) {
|
||||
removed = arrayRemove<E>(destInEdges, (edge: E) => edge.src === src.id)[0] || null;
|
||||
removed = arrayRemove<E>(destInEdges, (edge: E) => edge.src === src.key)[0] || null;
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
@ -187,12 +187,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
if (src && dest) {
|
||||
const srcOutEdges = this._outEdgeMap.get(src);
|
||||
if (srcOutEdges && srcOutEdges.length > 0) {
|
||||
arrayRemove(srcOutEdges, (edge: E) => edge.src === src.id);
|
||||
arrayRemove(srcOutEdges, (edge: E) => edge.src === src.key);
|
||||
}
|
||||
|
||||
const destInEdges = this._inEdgeMap.get(dest);
|
||||
if (destInEdges && destInEdges.length > 0) {
|
||||
removed = arrayRemove(destInEdges, (edge: E) => edge.dest === dest.id)[0];
|
||||
removed = arrayRemove(destInEdges, (edge: E) => edge.dest === dest.key)[0];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,13 +201,13 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function removes edges between two vertices and returns the removed edges.
|
||||
* @param {VertexId | V} v1 - The parameter `v1` can be either a `VertexId` or a `V`. A `VertexId` represents the
|
||||
* @param {VertexKey | V} v1 - The parameter `v1` can be either a `VertexKey` or a `V`. A `VertexKey` represents the
|
||||
* unique identifier of a vertex in a graph, while `V` represents the actual vertex object.
|
||||
* @param {VertexId | V} v2 - The parameter `v2` represents either a `VertexId` or a `V` object. It is used to specify
|
||||
* @param {VertexKey | V} v2 - The parameter `v2` represents either a `VertexKey` or a `V` object. It is used to specify
|
||||
* the second vertex in the edge that needs to be removed.
|
||||
* @returns an array of removed edges (E[]).
|
||||
*/
|
||||
removeEdgesBetween(v1: VertexId | V, v2: VertexId | V): E[] {
|
||||
removeEdgesBetween(v1: VertexKey | V, v2: VertexKey | V): E[] {
|
||||
const removed: E[] = [];
|
||||
|
||||
if (v1 && v2) {
|
||||
|
@ -223,12 +223,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function `incomingEdgesOf` returns an array of incoming edges for a given vertex or vertex ID.
|
||||
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexId`).
|
||||
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexKey`).
|
||||
* @returns The method `incomingEdgesOf` returns an array of edges (`E[]`).
|
||||
*/
|
||||
incomingEdgesOf(vertexOrId: V | VertexId): E[] {
|
||||
const target = this._getVertex(vertexOrId);
|
||||
incomingEdgesOf(vertexOrKey: V | VertexKey): E[] {
|
||||
const target = this._getVertex(vertexOrKey);
|
||||
if (target) {
|
||||
return this.inEdgeMap.get(target) || [];
|
||||
}
|
||||
|
@ -237,12 +237,12 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function `outgoingEdgesOf` returns an array of outgoing edges from a given vertex or vertex ID.
|
||||
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can accept either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexId`).
|
||||
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can accept either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexKey`).
|
||||
* @returns The method `outgoingEdgesOf` returns an array of edges (`E[]`).
|
||||
*/
|
||||
outgoingEdgesOf(vertexOrId: V | VertexId): E[] {
|
||||
const target = this._getVertex(vertexOrId);
|
||||
outgoingEdgesOf(vertexOrKey: V | VertexKey): E[] {
|
||||
const target = this._getVertex(vertexOrKey);
|
||||
if (target) {
|
||||
return this._outEdgeMap.get(target) || [];
|
||||
}
|
||||
|
@ -251,38 +251,38 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function "degreeOf" returns the total degree of a vertex, which is the sum of its out-degree and in-degree.
|
||||
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
|
||||
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
|
||||
* @returns The sum of the out-degree and in-degree of the specified vertex or vertex ID.
|
||||
*/
|
||||
degreeOf(vertexOrId: VertexId | V): number {
|
||||
return this.outDegreeOf(vertexOrId) + this.inDegreeOf(vertexOrId);
|
||||
degreeOf(vertexOrKey: VertexKey | V): number {
|
||||
return this.outDegreeOf(vertexOrKey) + this.inDegreeOf(vertexOrKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "inDegreeOf" returns the number of incoming edges for a given vertex.
|
||||
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
|
||||
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
|
||||
* @returns The number of incoming edges of the specified vertex or vertex ID.
|
||||
*/
|
||||
inDegreeOf(vertexOrId: VertexId | V): number {
|
||||
return this.incomingEdgesOf(vertexOrId).length;
|
||||
inDegreeOf(vertexOrKey: VertexKey | V): number {
|
||||
return this.incomingEdgesOf(vertexOrKey).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function `outDegreeOf` returns the number of outgoing edges from a given vertex.
|
||||
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
|
||||
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
|
||||
* @returns The number of outgoing edges from the specified vertex or vertex ID.
|
||||
*/
|
||||
outDegreeOf(vertexOrId: VertexId | V): number {
|
||||
return this.outgoingEdgesOf(vertexOrId).length;
|
||||
outDegreeOf(vertexOrKey: VertexKey | V): number {
|
||||
return this.outgoingEdgesOf(vertexOrKey).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function "edgesOf" returns an array of both outgoing and incoming edges of a given vertex or vertex ID.
|
||||
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
|
||||
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
|
||||
* @returns The function `edgesOf` returns an array of edges.
|
||||
*/
|
||||
edgesOf(vertexOrId: VertexId | V): E[] {
|
||||
return [...this.outgoingEdgesOf(vertexOrId), ...this.incomingEdgesOf(vertexOrId)];
|
||||
edgesOf(vertexOrKey: VertexKey | V): E[] {
|
||||
return [...this.outgoingEdgesOf(vertexOrKey), ...this.incomingEdgesOf(vertexOrKey)];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,11 +305,11 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function `getDestinations` returns an array of destination vertices connected to a given vertex.
|
||||
* @param {V | VertexId | null} vertex - The `vertex` parameter represents the starting vertex from which we want to
|
||||
* find the destinations. It can be either a `V` object, a `VertexId` value, or `null`.
|
||||
* @param {V | VertexKey | null} vertex - The `vertex` parameter represents the starting vertex from which we want to
|
||||
* find the destinations. It can be either a `V` object, a `VertexKey` value, or `null`.
|
||||
* @returns an array of vertices (V[]).
|
||||
*/
|
||||
getDestinations(vertex: V | VertexId | null): V[] {
|
||||
getDestinations(vertex: V | VertexKey | null): V[] {
|
||||
if (vertex === null) {
|
||||
return [];
|
||||
}
|
||||
|
@ -327,23 +327,23 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
/**
|
||||
* The `topologicalSort` function performs a topological sort on a graph and returns an array of vertices or vertex IDs
|
||||
* in the sorted order, or null if the graph contains a cycle.
|
||||
* @param {'vertex' | 'id'} [propertyName] - The `propertyName` parameter is an optional parameter that specifies the
|
||||
* property to use for sorting the vertices. It can have two possible values: 'vertex' or 'id'. If 'vertex' is
|
||||
* specified, the vertices themselves will be used for sorting. If 'id' is specified, the ids of
|
||||
* @param {'vertex' | 'key'} [propertyName] - The `propertyName` parameter is an optional parameter that specifies the
|
||||
* property to use for sorting the vertices. It can have two possible values: 'vertex' or 'key'. If 'vertex' is
|
||||
* specified, the vertices themselves will be used for sorting. If 'key' is specified, the ids of
|
||||
* @returns an array of vertices or vertex IDs in topological order. If there is a cycle in the graph, it returns null.
|
||||
*/
|
||||
topologicalSort(propertyName?: 'vertex' | 'id'): Array<V | VertexId> | null {
|
||||
propertyName = propertyName ?? 'id';
|
||||
topologicalSort(propertyName?: 'vertex' | 'key'): Array<V | VertexKey> | null {
|
||||
propertyName = propertyName ?? 'key';
|
||||
// When judging whether there is a cycle in the undirected graph, all nodes with degree of **<= 1** are enqueued
|
||||
// When judging whether there is a cycle in the directed graph, all nodes with **in degree = 0** are enqueued
|
||||
const statusMap: Map<V | VertexId, TopologicalStatus> = new Map<V | VertexId, TopologicalStatus>();
|
||||
const statusMap: Map<V | VertexKey, TopologicalStatus> = new Map<V | VertexKey, TopologicalStatus>();
|
||||
for (const entry of this.vertices) {
|
||||
statusMap.set(entry[1], 0);
|
||||
}
|
||||
|
||||
let sorted: (V | VertexId)[] = [];
|
||||
let sorted: (V | VertexKey)[] = [];
|
||||
let hasCycle = false;
|
||||
const dfs = (cur: V | VertexId) => {
|
||||
const dfs = (cur: V | VertexKey) => {
|
||||
statusMap.set(cur, 1);
|
||||
const children = this.getDestinations(cur);
|
||||
for (const child of children) {
|
||||
|
@ -366,7 +366,7 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
if (hasCycle) return null;
|
||||
|
||||
if (propertyName === 'id') sorted = sorted.map(vertex => (vertex instanceof DirectedVertex ? vertex.id : vertex));
|
||||
if (propertyName === 'key') sorted = sorted.map(vertex => (vertex instanceof DirectedVertex ? vertex.key : vertex));
|
||||
return sorted.reverse();
|
||||
}
|
||||
|
||||
|
@ -384,13 +384,13 @@ export class DirectedGraph<V extends DirectedVertex<any> = DirectedVertex, E ext
|
|||
|
||||
/**
|
||||
* The function `getNeighbors` returns an array of neighboring vertices of a given vertex or vertex ID in a graph.
|
||||
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexId`).
|
||||
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexKey`).
|
||||
* @returns an array of vertices (V[]).
|
||||
*/
|
||||
getNeighbors(vertexOrId: V | VertexId): V[] {
|
||||
getNeighbors(vertexOrKey: V | VertexKey): V[] {
|
||||
const neighbors: V[] = [];
|
||||
const vertex = this._getVertex(vertexOrId);
|
||||
const vertex = this._getVertex(vertexOrKey);
|
||||
if (vertex) {
|
||||
const outEdges = this.outgoingEdgesOf(vertex);
|
||||
for (const outEdge of outEdges) {
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
import {MapGraphCoordinate, VertexId} from '../../types';
|
||||
import {MapGraphCoordinate, VertexKey} from '../../types';
|
||||
import {DirectedEdge, DirectedGraph, DirectedVertex} from './directed-graph';
|
||||
|
||||
export class MapVertex<V = any> extends DirectedVertex<V> {
|
||||
/**
|
||||
* The constructor function initializes an object with an id, latitude, longitude, and an optional value.
|
||||
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex.
|
||||
* The constructor function initializes an object with an key, latitude, longitude, and an optional value.
|
||||
* @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex.
|
||||
* @param {number} lat - The "lat" parameter represents the latitude of a vertex. Latitude is a geographic coordinate
|
||||
* that specifies the north-south position of a point on the Earth's surface. It is measured in degrees, with positive
|
||||
* values representing points north of the equator and negative values representing points south of the equator.
|
||||
|
@ -14,8 +14,8 @@ export class MapVertex<V = any> extends DirectedVertex<V> {
|
|||
* @param {V} [val] - The "val" parameter is an optional value of type V. It is not required to be provided when
|
||||
* creating an instance of the class.
|
||||
*/
|
||||
constructor(id: VertexId, lat: number, long: number, val?: V) {
|
||||
super(id, val);
|
||||
constructor(key: VertexKey, lat: number, long: number, val?: V) {
|
||||
super(key, val);
|
||||
this._lat = lat;
|
||||
this._long = long;
|
||||
}
|
||||
|
@ -45,14 +45,14 @@ export class MapEdge<V = any> extends DirectedEdge<V> {
|
|||
/**
|
||||
* The constructor function initializes a new instance of a class with the given source, destination, weight, and
|
||||
* value.
|
||||
* @param {VertexId} src - The `src` parameter is the source vertex ID. It represents the starting point of an edge in
|
||||
* @param {VertexKey} src - The `src` parameter is the source vertex ID. It represents the starting point of an edge in
|
||||
* a graph.
|
||||
* @param {VertexId} dest - The `dest` parameter is the identifier of the destination vertex for an edge.
|
||||
* @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for an edge.
|
||||
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge.
|
||||
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to store additional
|
||||
* information or data associated with the edge.
|
||||
*/
|
||||
constructor(src: VertexId, dest: VertexId, weight?: number, val?: V) {
|
||||
constructor(src: VertexKey, dest: VertexKey, weight?: number, val?: V) {
|
||||
super(src, dest, weight, val);
|
||||
}
|
||||
}
|
||||
|
@ -97,8 +97,8 @@ export class MapGraph<V extends MapVertex<V['val']> = MapVertex, E extends MapEd
|
|||
}
|
||||
|
||||
/**
|
||||
* The function creates a new vertex with the given id, value, latitude, and longitude.
|
||||
* @param {VertexId} id - The id parameter is the unique identifier for the vertex. It is of type VertexId, which could
|
||||
* The function creates a new vertex with the given key, value, latitude, and longitude.
|
||||
* @param {VertexKey} key - The key parameter is the unique identifier for the vertex. It is of type VertexKey, which could
|
||||
* be a string or a number depending on how you define it in your code.
|
||||
* @param [val] - The `val` parameter is an optional value that can be assigned to the `val` property of the vertex. It
|
||||
* is of type `V['val']`, which means it should be of the same type as the `val` property of the vertex class `V`.
|
||||
|
@ -107,23 +107,28 @@ export class MapGraph<V extends MapVertex<V['val']> = MapVertex, E extends MapEd
|
|||
* @param {number} long - The `long` parameter represents the longitude coordinate of the vertex.
|
||||
* @returns The method is returning a new instance of the `MapVertex` class, casted as type `V`.
|
||||
*/
|
||||
override createVertex(id: VertexId, val?: V['val'], lat: number = this.origin[0], long: number = this.origin[1]): V {
|
||||
return new MapVertex(id, lat, long, val) as V;
|
||||
override createVertex(
|
||||
key: VertexKey,
|
||||
val?: V['val'],
|
||||
lat: number = this.origin[0],
|
||||
long: number = this.origin[1]
|
||||
): V {
|
||||
return new MapVertex(key, lat, long, val) as V;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function creates a new instance of a MapEdge with the given source, destination, weight, and value.
|
||||
* @param {VertexId} src - The source vertex ID of the edge. It represents the starting point of the edge.
|
||||
* @param {VertexId} dest - The `dest` parameter is the identifier of the destination vertex for the edge being
|
||||
* @param {VertexKey} src - The source vertex ID of the edge. It represents the starting point of the edge.
|
||||
* @param {VertexKey} dest - The `dest` parameter is the identifier of the destination vertex for the edge being
|
||||
* created.
|
||||
* @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the edge. It
|
||||
* is used to assign a numerical value to the edge, which can be used in algorithms such as shortest path algorithms.
|
||||
* If the weight is not provided, it can be set to a default value or left undefined.
|
||||
* @param [val] - The `val` parameter is an optional value that can be assigned to the edge. It can be of any type,
|
||||
* depending on the specific implementation of the `MapEdge` class.
|
||||
* @returns a new instance of the `MapEdge` class, casted as type `E`.
|
||||
* @returns a new instance of the `MapEdge` class, cast as type `E`.
|
||||
*/
|
||||
override createEdge(src: VertexId, dest: VertexId, weight?: number, val?: E['val']): E {
|
||||
override createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E['val']): E {
|
||||
return new MapEdge(src, dest, weight, val) as E;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,19 +7,19 @@
|
|||
*/
|
||||
import {arrayRemove} from '../../utils';
|
||||
import {AbstractEdge, AbstractGraph, AbstractVertex} from './abstract-graph';
|
||||
import type {VertexId} from '../../types';
|
||||
import {IUNDirectedGraph} from '../../interfaces';
|
||||
import type {VertexKey} from '../../types';
|
||||
import {IGraph} from '../../interfaces';
|
||||
|
||||
export class UndirectedVertex<V = any> extends AbstractVertex<V> {
|
||||
/**
|
||||
* The constructor function initializes a vertex with an optional value.
|
||||
* @param {VertexId} id - The `id` parameter is of type `VertexId` and represents the identifier of the vertex. It is
|
||||
* @param {VertexKey} key - The `key` parameter is of type `VertexKey` and represents the identifier of the vertex. It is
|
||||
* used to uniquely identify the vertex within a graph or network.
|
||||
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to initialize the value of the
|
||||
* vertex. If no value is provided, the vertex will be initialized with a default value.
|
||||
*/
|
||||
constructor(id: VertexId, val?: V) {
|
||||
super(id, val);
|
||||
constructor(key: VertexKey, val?: V) {
|
||||
super(key, val);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,25 +27,25 @@ export class UndirectedEdge<V = number> extends AbstractEdge<V> {
|
|||
/**
|
||||
* The constructor function creates an instance of a class with two vertex IDs, an optional weight, and an optional
|
||||
* value.
|
||||
* @param {VertexId} v1 - The first vertex ID of the edge.
|
||||
* @param {VertexId} v2 - The parameter `v2` is a `VertexId`, which represents the identifier of the second vertex in a
|
||||
* @param {VertexKey} v1 - The first vertex ID of the edge.
|
||||
* @param {VertexKey} v2 - The parameter `v2` is a `VertexKey`, which represents the identifier of the second vertex in a
|
||||
* graph edge.
|
||||
* @param {number} [weight] - The weight parameter is an optional number that represents the weight of the edge.
|
||||
* @param {V} [val] - The "val" parameter is an optional parameter of type V. It is used to store a value associated
|
||||
* with the edge.
|
||||
*/
|
||||
constructor(v1: VertexId, v2: VertexId, weight?: number, val?: V) {
|
||||
constructor(v1: VertexKey, v2: VertexKey, weight?: number, val?: V) {
|
||||
super(weight, val);
|
||||
this._vertices = [v1, v2];
|
||||
}
|
||||
|
||||
private _vertices: [VertexId, VertexId];
|
||||
private _vertices: [VertexKey, VertexKey];
|
||||
|
||||
get vertices() {
|
||||
return this._vertices;
|
||||
}
|
||||
|
||||
set vertices(v: [VertexId, VertexId]) {
|
||||
set vertices(v: [VertexKey, VertexKey]) {
|
||||
this._vertices = v;
|
||||
}
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ export class UndirectedGraph<
|
|||
E extends UndirectedEdge<any> = UndirectedEdge
|
||||
>
|
||||
extends AbstractGraph<V, E>
|
||||
implements IUNDirectedGraph<V, E>
|
||||
implements IGraph<V, E>
|
||||
{
|
||||
/**
|
||||
* The constructor initializes a new Map object to store edges.
|
||||
|
@ -73,40 +73,40 @@ export class UndirectedGraph<
|
|||
|
||||
/**
|
||||
* The function creates a new vertex with an optional value and returns it.
|
||||
* @param {VertexId} id - The `id` parameter is the unique identifier for the vertex. It is used to distinguish one
|
||||
* @param {VertexKey} key - The `key` parameter is the unique identifier for the vertex. It is used to distinguish one
|
||||
* vertex from another in the graph.
|
||||
* @param [val] - The `val` parameter is an optional value that can be assigned to the vertex. If a value is provided,
|
||||
* it will be used as the value of the vertex. If no value is provided, the `id` parameter will be used as the value of
|
||||
* it will be used as the value of the vertex. If no value is provided, the `key` parameter will be used as the value of
|
||||
* the vertex.
|
||||
* @returns The method is returning a new instance of the `UndirectedVertex` class, casted as type `V`.
|
||||
*/
|
||||
override createVertex(id: VertexId, val?: V['val']): V {
|
||||
return new UndirectedVertex(id, val ?? id) as V;
|
||||
override createVertex(key: VertexKey, val?: V['val']): V {
|
||||
return new UndirectedVertex(key, val ?? key) as V;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function creates an undirected edge between two vertices with an optional weight and value.
|
||||
* @param {VertexId} v1 - The parameter `v1` represents the first vertex of the edge.
|
||||
* @param {VertexId} v2 - The parameter `v2` represents the second vertex of the edge.
|
||||
* @param {VertexKey} v1 - The parameter `v1` represents the first vertex of the edge.
|
||||
* @param {VertexKey} v2 - The parameter `v2` represents the second vertex of the edge.
|
||||
* @param {number} [weight] - The `weight` parameter is an optional number that represents the weight of the edge. If
|
||||
* no weight is provided, it defaults to 1.
|
||||
* @param [val] - The `val` parameter is an optional value that can be assigned to the edge. It can be of any type and
|
||||
* is used to store additional information or data associated with the edge.
|
||||
* @returns a new instance of the `UndirectedEdge` class, which is casted as type `E`.
|
||||
*/
|
||||
override createEdge(v1: VertexId, v2: VertexId, weight?: number, val?: E['val']): E {
|
||||
override createEdge(v1: VertexKey, v2: VertexKey, weight?: number, val?: E['val']): E {
|
||||
return new UndirectedEdge(v1, v2, weight ?? 1, val) as E;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function `getEdge` returns the first edge that connects two vertices, or null if no such edge exists.
|
||||
* @param {V | null | VertexId} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `V` (vertex
|
||||
* object), `null`, or `VertexId` (a string or number representing the ID of a vertex).
|
||||
* @param {V | null | VertexId} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `V` (vertex
|
||||
* object), `null`, or `VertexId` (vertex ID).
|
||||
* @param {V | null | VertexKey} v1 - The parameter `v1` represents a vertex or vertex ID. It can be of type `V` (vertex
|
||||
* object), `null`, or `VertexKey` (a string or number representing the ID of a vertex).
|
||||
* @param {V | null | VertexKey} v2 - The parameter `v2` represents a vertex or vertex ID. It can be of type `V` (vertex
|
||||
* object), `null`, or `VertexKey` (vertex ID).
|
||||
* @returns an edge (E) or null.
|
||||
*/
|
||||
getEdge(v1: V | null | VertexId, v2: V | null | VertexId): E | null {
|
||||
getEdge(v1: V | null | VertexKey, v2: V | null | VertexKey): E | null {
|
||||
let edges: E[] | undefined = [];
|
||||
|
||||
if (v1 !== null && v2 !== null) {
|
||||
|
@ -114,7 +114,7 @@ export class UndirectedGraph<
|
|||
const vertex2: V | null = this._getVertex(v2);
|
||||
|
||||
if (vertex1 && vertex2) {
|
||||
edges = this._edges.get(vertex1)?.filter(e => e.vertices.includes(vertex2.id));
|
||||
edges = this._edges.get(vertex1)?.filter(e => e.vertices.includes(vertex2.key));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,12 +123,12 @@ export class UndirectedGraph<
|
|||
|
||||
/**
|
||||
* The function removes an edge between two vertices in a graph and returns the removed edge.
|
||||
* @param {V | VertexId} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexId`).
|
||||
* @param {V | VertexId} v2 - V | VertexId - This parameter can be either a vertex object (V) or a vertex ID
|
||||
* (VertexId). It represents the second vertex of the edge that needs to be removed.
|
||||
* @param {V | VertexKey} v1 - The parameter `v1` represents either a vertex object (`V`) or a vertex ID (`VertexKey`).
|
||||
* @param {V | VertexKey} v2 - V | VertexKey - This parameter can be either a vertex object (V) or a vertex ID
|
||||
* (VertexKey). It represents the second vertex of the edge that needs to be removed.
|
||||
* @returns the removed edge (E) if it exists, or null if either of the vertices (V) does not exist.
|
||||
*/
|
||||
removeEdgeBetween(v1: V | VertexId, v2: V | VertexId): E | null {
|
||||
removeEdgeBetween(v1: V | VertexKey, v2: V | VertexKey): E | null {
|
||||
const vertex1: V | null = this._getVertex(v1);
|
||||
const vertex2: V | null = this._getVertex(v2);
|
||||
|
||||
|
@ -139,11 +139,11 @@ export class UndirectedGraph<
|
|||
const v1Edges = this._edges.get(vertex1);
|
||||
let removed: E | null = null;
|
||||
if (v1Edges) {
|
||||
removed = arrayRemove<E>(v1Edges, (e: E) => e.vertices.includes(vertex2.id))[0] || null;
|
||||
removed = arrayRemove<E>(v1Edges, (e: E) => e.vertices.includes(vertex2.key))[0] || null;
|
||||
}
|
||||
const v2Edges = this._edges.get(vertex2);
|
||||
if (v2Edges) {
|
||||
arrayRemove<E>(v2Edges, (e: E) => e.vertices.includes(vertex1.id));
|
||||
arrayRemove<E>(v2Edges, (e: E) => e.vertices.includes(vertex1.key));
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
@ -160,12 +160,12 @@ export class UndirectedGraph<
|
|||
/**
|
||||
* The function `degreeOf` returns the degree of a vertex in a graph, which is the number of edges connected to that
|
||||
* vertex.
|
||||
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`.
|
||||
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`.
|
||||
* @returns The function `degreeOf` returns the degree of a vertex in a graph. The degree of a vertex is the number of
|
||||
* edges connected to that vertex.
|
||||
*/
|
||||
degreeOf(vertexOrId: VertexId | V): number {
|
||||
const vertex = this._getVertex(vertexOrId);
|
||||
degreeOf(vertexOrKey: VertexKey | V): number {
|
||||
const vertex = this._getVertex(vertexOrKey);
|
||||
if (vertex) {
|
||||
return this._edges.get(vertex)?.length || 0;
|
||||
} else {
|
||||
|
@ -175,12 +175,12 @@ export class UndirectedGraph<
|
|||
|
||||
/**
|
||||
* The function returns the edges of a given vertex or vertex ID.
|
||||
* @param {VertexId | V} vertexOrId - The parameter `vertexOrId` can be either a `VertexId` or a `V`. A `VertexId` is a
|
||||
* @param {VertexKey | V} vertexOrKey - The parameter `vertexOrKey` can be either a `VertexKey` or a `V`. A `VertexKey` is a
|
||||
* unique identifier for a vertex in a graph, while `V` represents the type of the vertex.
|
||||
* @returns an array of edges.
|
||||
*/
|
||||
edgesOf(vertexOrId: VertexId | V): E[] {
|
||||
const vertex = this._getVertex(vertexOrId);
|
||||
edgesOf(vertexOrKey: VertexKey | V): E[] {
|
||||
const vertex = this._getVertex(vertexOrKey);
|
||||
if (vertex) {
|
||||
return this._edges.get(vertex) || [];
|
||||
} else {
|
||||
|
@ -204,17 +204,17 @@ export class UndirectedGraph<
|
|||
|
||||
/**
|
||||
* The function "getNeighbors" returns an array of neighboring vertices for a given vertex or vertex ID.
|
||||
* @param {V | VertexId} vertexOrId - The parameter `vertexOrId` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexId`).
|
||||
* @param {V | VertexKey} vertexOrKey - The parameter `vertexOrKey` can be either a vertex object (`V`) or a vertex ID
|
||||
* (`VertexKey`).
|
||||
* @returns an array of vertices (V[]).
|
||||
*/
|
||||
getNeighbors(vertexOrId: V | VertexId): V[] {
|
||||
getNeighbors(vertexOrKey: V | VertexKey): V[] {
|
||||
const neighbors: V[] = [];
|
||||
const vertex = this._getVertex(vertexOrId);
|
||||
const vertex = this._getVertex(vertexOrKey);
|
||||
if (vertex) {
|
||||
const neighborEdges = this.edgesOf(vertex);
|
||||
for (const edge of neighborEdges) {
|
||||
const neighbor = this._getVertex(edge.vertices.filter(e => e !== vertex.id)[0]);
|
||||
const neighbor = this._getVertex(edge.vertices.filter(e => e !== vertex.key)[0]);
|
||||
if (neighbor) {
|
||||
neighbors.push(neighbor);
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
export * from './hash-table';
|
||||
export * from './coordinate-map';
|
||||
export * from './coordinate-set';
|
||||
export * from './pair';
|
||||
export * from './tree-map';
|
||||
export * from './tree-set';
|
||||
export * from './hash-map';
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
export class Pair {}
|
|
@ -1,212 +1,236 @@
|
|||
/**
|
||||
* data-structure-typed
|
||||
*
|
||||
* @author Tyler Zeng
|
||||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @author Kirk Qi
|
||||
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import {PriorityQueue} from '../priority-queue';
|
||||
import type {HeapOptions} from '../../types';
|
||||
|
||||
export class HeapItem<V = any> {
|
||||
/**
|
||||
* The constructor function initializes an instance of a class with a priority and a value.
|
||||
* @param {number} priority - The `priority` parameter is a number that represents the priority of the value. It is
|
||||
* optional and has a default value of `NaN`.
|
||||
* @param {V | null} [val=null] - The `val` parameter is of type `V | null`, which means it can accept a value of type
|
||||
* `V` or `null`.
|
||||
*/
|
||||
constructor(priority: number = Number.MAX_SAFE_INTEGER, val: V | null = null) {
|
||||
this._val = val;
|
||||
this._priority = priority;
|
||||
}
|
||||
import type {HeapComparator, HeapDFSOrderPattern} from '../../types';
|
||||
|
||||
private _priority: number;
|
||||
export class Heap<E> {
|
||||
protected nodes: E[] = [];
|
||||
private readonly comparator: HeapComparator<E>;
|
||||
|
||||
get priority(): number {
|
||||
return this._priority;
|
||||
}
|
||||
|
||||
set priority(value: number) {
|
||||
this._priority = value;
|
||||
}
|
||||
|
||||
private _val: V | null;
|
||||
|
||||
get val(): V | null {
|
||||
return this._val;
|
||||
}
|
||||
|
||||
set val(value: V | null) {
|
||||
this._val = value;
|
||||
}
|
||||
}
|
||||
|
||||
export abstract class Heap<V = number> {
|
||||
/**
|
||||
* The function is a constructor for a class that initializes a priority callback function based on the
|
||||
* options provided.
|
||||
* @param [options] - An optional object that contains configuration options for the Heap.
|
||||
*/
|
||||
protected constructor(options?: HeapOptions<V>) {
|
||||
if (options) {
|
||||
const {priorityExtractor} = options;
|
||||
if (priorityExtractor !== undefined && typeof priorityExtractor !== 'function') {
|
||||
throw new Error('.constructor expects a valid priority function');
|
||||
}
|
||||
this._priorityExtractor = priorityExtractor || (el => +el);
|
||||
} else {
|
||||
this._priorityExtractor = el => +el;
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract _pq: PriorityQueue<HeapItem<V>>;
|
||||
|
||||
get pq() {
|
||||
return this._pq;
|
||||
}
|
||||
|
||||
protected _priorityExtractor: (val: V) => number;
|
||||
get priorityExtractor() {
|
||||
return this._priorityExtractor;
|
||||
constructor(comparator: HeapComparator<E>) {
|
||||
this.comparator = comparator;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns the size of a priority queue.
|
||||
* @returns The size of the priority queue.
|
||||
* Insert an element into the heap and maintain the heap properties.
|
||||
* @param value - The element to be inserted.
|
||||
*/
|
||||
get size(): number {
|
||||
return this._pq.size;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks if a priority queue is empty.
|
||||
* @returns {boolean} A boolean value indicating whether the size of the priority queue is less than 1.
|
||||
*/
|
||||
isEmpty(): boolean {
|
||||
return this._pq.size < 1;
|
||||
}
|
||||
|
||||
peek(isItem?: undefined): V | undefined;
|
||||
peek(isItem: false): V | undefined;
|
||||
peek(isItem: true): HeapItem<V> | null;
|
||||
|
||||
/**
|
||||
* The `peek` function returns the top item in the priority queue without removing it.
|
||||
* @returns The `peek()` method is returning either a `HeapItem<V>` object or `null`.Returns an val with the highest priority in the queue
|
||||
*/
|
||||
peek(isItem?: boolean): HeapItem<V> | null | V | undefined {
|
||||
isItem = isItem ?? false;
|
||||
const peeked = this._pq.peek();
|
||||
|
||||
return isItem ? peeked : peeked?.val;
|
||||
}
|
||||
|
||||
peekLast(isItem?: undefined): V | undefined;
|
||||
peekLast(isItem: false): V | undefined;
|
||||
peekLast(isItem: true): HeapItem<V> | null;
|
||||
|
||||
/**
|
||||
* The `peekLast` function returns the last item in the heap.
|
||||
* @returns The method `peekLast()` returns either a `HeapItem<V>` object or `null`.Returns an val with the lowest priority in the queue
|
||||
*/
|
||||
peekLast(isItem?: boolean): HeapItem<V> | null | V | undefined {
|
||||
isItem = isItem ?? false;
|
||||
const leafItem = this._pq.leaf();
|
||||
|
||||
return isItem ? leafItem : leafItem?.val;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `add` function adds an val to a priority queue with an optional priority value.
|
||||
* @param {V} val - The `val` parameter represents the value that you want to add to the heap. It can be of any
|
||||
* type.
|
||||
* @param {number} [priority] - The `priority` parameter is an optional number that represents the priority of the
|
||||
* val being added to the heap. If the `val` parameter is a number, then the `priority` parameter is set to
|
||||
* the value of `val`. If the `val` parameter is not a number, then the
|
||||
* @returns The `add` method returns the instance of the `Heap` class.
|
||||
* @throws {Error} if priority is not a valid number
|
||||
*/
|
||||
add(priority: number, val?: V): Heap<V> {
|
||||
val = val === undefined ? (priority as unknown as V) : val;
|
||||
this._pq.add(new HeapItem<V>(priority, val));
|
||||
|
||||
add(value: E): Heap<E> {
|
||||
this.nodes.push(value);
|
||||
this.bubbleUp(this.nodes.length - 1);
|
||||
return this;
|
||||
}
|
||||
|
||||
poll(isItem?: undefined): V | undefined;
|
||||
poll(isItem: false): V | undefined;
|
||||
poll(isItem: true): HeapItem<V> | null;
|
||||
|
||||
/**
|
||||
* The `poll` function returns the top item from a priority queue or null if the queue is empty.Removes and returns an val with the highest priority in the queue
|
||||
* @returns either a HeapItem<V> object or null.
|
||||
* Remove and return the top element (smallest or largest element) from the heap.
|
||||
* @returns The top element or null if the heap is empty.
|
||||
*/
|
||||
poll(isItem?: boolean): HeapItem<V> | null | V | undefined {
|
||||
isItem = isItem ?? false;
|
||||
const top = this._pq.poll();
|
||||
if (!top) {
|
||||
poll(): E | null {
|
||||
if (this.nodes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
if (this.nodes.length === 1) {
|
||||
return this.nodes.pop() as E;
|
||||
}
|
||||
|
||||
return isItem ? top : top.val;
|
||||
const topValue = this.nodes[0];
|
||||
this.nodes[0] = this.nodes.pop() as E;
|
||||
this.sinkDown(0);
|
||||
return topValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks if a given node or value exists in the priority queue.
|
||||
* @param {V | HeapItem<V>} node - The parameter `node` can be of type `V` or `HeapItem<V>`.
|
||||
* @returns a boolean value.
|
||||
* Float operation to maintain heap properties after adding an element.
|
||||
* @param index - The index of the newly added element.
|
||||
*/
|
||||
has(node: V | HeapItem<V>): boolean {
|
||||
if (node instanceof HeapItem) {
|
||||
return this.pq.getNodes().includes(node);
|
||||
} else {
|
||||
return (
|
||||
this.pq.getNodes().findIndex(item => {
|
||||
return item.val === node;
|
||||
}) !== -1
|
||||
);
|
||||
protected bubbleUp(index: number): void {
|
||||
const element = this.nodes[index];
|
||||
while (index > 0) {
|
||||
const parentIndex = Math.floor((index - 1) / 2);
|
||||
const parent = this.nodes[parentIndex];
|
||||
if (this.comparator(element, parent) < 0) {
|
||||
this.nodes[index] = parent;
|
||||
this.nodes[parentIndex] = element;
|
||||
index = parentIndex;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
toArray(isItem?: undefined): (V | undefined)[];
|
||||
toArray(isItem: false): (V | undefined)[];
|
||||
toArray(isItem: true): (HeapItem<V> | null)[];
|
||||
|
||||
/**
|
||||
* The `toArray` function returns an array of `HeapItem<V>` objects.
|
||||
* @returns An array of HeapItem<V> objects.Returns a sorted list of vals
|
||||
* Sinking operation to maintain heap properties after removing the top element.
|
||||
* @param index - The index from which to start sinking.
|
||||
*/
|
||||
toArray(isItem?: boolean): (HeapItem<V> | null | V | undefined)[] {
|
||||
isItem = isItem ?? false;
|
||||
const itemArray = this._pq.toArray();
|
||||
protected sinkDown(index: number): void {
|
||||
const leftChildIndex = 2 * index + 1;
|
||||
const rightChildIndex = 2 * index + 2;
|
||||
const length = this.nodes.length;
|
||||
let targetIndex = index;
|
||||
|
||||
return isItem ? itemArray : itemArray.map(item => item.val);
|
||||
}
|
||||
if (leftChildIndex < length && this.comparator(this.nodes[leftChildIndex], this.nodes[targetIndex]) < 0) {
|
||||
targetIndex = leftChildIndex;
|
||||
}
|
||||
if (rightChildIndex < length && this.comparator(this.nodes[rightChildIndex], this.nodes[targetIndex]) < 0) {
|
||||
targetIndex = rightChildIndex;
|
||||
}
|
||||
|
||||
sort(isItem?: undefined): (V | undefined)[];
|
||||
sort(isItem: false): (V | undefined)[];
|
||||
sort(isItem: true): (HeapItem<V> | null)[];
|
||||
|
||||
/**
|
||||
* The function sorts the elements in the priority queue and returns either the sorted items or their values depending
|
||||
* on the value of the isItem parameter.
|
||||
* @param {boolean} [isItem] - The `isItem` parameter is a boolean flag that indicates whether the sorted result should
|
||||
* be an array of `HeapItem<V>` objects or an array of the values (`V`) of those objects. If `isItem` is `true`, the
|
||||
* sorted result will be an array of `HeapItem
|
||||
* @returns an array of either `HeapItem<V>`, `null`, `V`, or `undefined` values.
|
||||
*/
|
||||
sort(isItem?: boolean): (HeapItem<V> | null | V | undefined)[] {
|
||||
isItem = isItem ?? false;
|
||||
const sorted = this._pq.sort();
|
||||
|
||||
return isItem ? sorted : sorted.map(item => item.val);
|
||||
if (targetIndex !== index) {
|
||||
const temp = this.nodes[index];
|
||||
this.nodes[index] = this.nodes[targetIndex];
|
||||
this.nodes[targetIndex] = temp;
|
||||
this.sinkDown(targetIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The clear function clears the priority queue.
|
||||
* Fix the entire heap to maintain heap properties.
|
||||
*/
|
||||
clear(): void {
|
||||
this._pq.clear();
|
||||
protected fix() {
|
||||
for (let i = Math.floor(this.size / 2); i >= 0; i--) this.sinkDown(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Peek at the top element of the heap without removing it.
|
||||
* @returns The top element or null if the heap is empty.
|
||||
*/
|
||||
peek(): E | null {
|
||||
if (this.nodes.length === 0) {
|
||||
return null;
|
||||
}
|
||||
return this.nodes[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the size (number of elements) of the heap.
|
||||
*/
|
||||
get size(): number {
|
||||
return this.nodes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last element in the heap, which is not necessarily a leaf node.
|
||||
* @returns The last element or null if the heap is empty.
|
||||
*/
|
||||
get leaf(): E | null {
|
||||
return this.nodes[this.size - 1] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the heap is empty.
|
||||
* @returns True if the heap is empty, otherwise false.
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.size === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the nodes of the heap. Make the nodes empty.
|
||||
*/
|
||||
clear() {
|
||||
this.nodes = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear and add nodes of the heap
|
||||
* @param nodes
|
||||
*/
|
||||
refill(nodes: E[]) {
|
||||
this.nodes = nodes;
|
||||
this.fix();
|
||||
}
|
||||
|
||||
/**
|
||||
* Use a comparison function to check whether a binary heap contains a specific element.
|
||||
* @param value - the element to check.
|
||||
* @returns Returns true if the specified element is contained; otherwise, returns false.
|
||||
*/
|
||||
has(value: E): boolean {
|
||||
return this.nodes.includes(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Depth-first search (DFS) method, different traversal orders can be selected。
|
||||
* @param order - Traversal order parameter: 'in' (in-order), 'pre' (pre-order) or 'post' (post-order).
|
||||
* @returns An array containing elements traversed in the specified order.
|
||||
*/
|
||||
dfs(order: HeapDFSOrderPattern): E[] {
|
||||
const result: E[] = [];
|
||||
|
||||
// Auxiliary recursive function, traverses the binary heap according to the traversal order
|
||||
const dfsHelper = (index: number) => {
|
||||
if (index < this.size) {
|
||||
if (order === 'in') {
|
||||
dfsHelper(2 * index + 1);
|
||||
result.push(this.nodes[index]);
|
||||
dfsHelper(2 * index + 2);
|
||||
} else if (order === 'pre') {
|
||||
result.push(this.nodes[index]);
|
||||
dfsHelper(2 * index + 1);
|
||||
dfsHelper(2 * index + 2);
|
||||
} else if (order === 'post') {
|
||||
dfsHelper(2 * index + 1);
|
||||
dfsHelper(2 * index + 2);
|
||||
result.push(this.nodes[index]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
dfsHelper(0); // Traverse starting from the root node
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the heap to an array.
|
||||
* @returns An array containing the elements of the heap.
|
||||
*/
|
||||
toArray(): E[] {
|
||||
return [...this.nodes];
|
||||
}
|
||||
|
||||
getNodes(): E[] {
|
||||
return this.nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone the heap, creating a new heap with the same elements.
|
||||
* @returns A new Heap instance containing the same elements.
|
||||
*/
|
||||
clone(): Heap<E> {
|
||||
const clonedHeap = new Heap<E>(this.comparator);
|
||||
clonedHeap.nodes = [...this.nodes];
|
||||
return clonedHeap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the elements in the heap and return them as an array.
|
||||
* @returns An array containing the elements sorted in ascending order.
|
||||
*/
|
||||
sort(): E[] {
|
||||
const visitedNode: E[] = [];
|
||||
const cloned = this.clone();
|
||||
while (cloned.size !== 0) {
|
||||
const top = cloned.poll();
|
||||
if (top) visitedNode.push(top);
|
||||
}
|
||||
return visitedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Static method that creates a binary heap from an array of nodes and a comparison function.
|
||||
* @param nodes
|
||||
* @param comparator - Comparison function.
|
||||
* @returns A new Heap instance.
|
||||
*/
|
||||
static heapify<E>(nodes: E[], comparator: HeapComparator<E>): Heap<E> {
|
||||
const binaryHeap = new Heap<E>(comparator);
|
||||
binaryHeap.nodes = [...nodes];
|
||||
binaryHeap.fix(); // Fix heap properties
|
||||
return binaryHeap;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,31 +1,24 @@
|
|||
/**
|
||||
* data-structure-typed
|
||||
*
|
||||
* @author Tyler Zeng
|
||||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @author Kirk Qi
|
||||
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
import {Heap, HeapItem} from './heap';
|
||||
import {PriorityQueue} from '../priority-queue';
|
||||
import type {HeapOptions} from '../../types';
|
||||
import {Heap} from './heap';
|
||||
import type {HeapComparator} from '../../types';
|
||||
|
||||
/**
|
||||
* @class MaxHeap
|
||||
* @extends Heap
|
||||
*/
|
||||
export class MaxHeap<V = any> extends Heap<V> {
|
||||
protected _pq: PriorityQueue<HeapItem<V>>;
|
||||
|
||||
/**
|
||||
* The constructor initializes a PriorityQueue with a custom comparator function.
|
||||
* @param [options] - The `options` parameter is an optional object that can be passed to the constructor. It is of
|
||||
* type `HeapOptions<V>`, which is a generic type that represents the options for the heap.
|
||||
*/
|
||||
constructor(options?: HeapOptions<V>) {
|
||||
super(options);
|
||||
this._pq = new PriorityQueue<HeapItem<V>>({
|
||||
comparator: (a, b) => b.priority - a.priority
|
||||
});
|
||||
export class MaxHeap<E = any> extends Heap<E> {
|
||||
constructor(
|
||||
comparator: HeapComparator<E> = (a: E, b: E) => {
|
||||
if (!(typeof a === 'number' && typeof b === 'number')) {
|
||||
throw new Error('The a, b params of compare function must be number');
|
||||
} else {
|
||||
return b - a;
|
||||
}
|
||||
}
|
||||
) {
|
||||
super(comparator);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,32 +1,24 @@
|
|||
/**
|
||||
* data-structure-typed
|
||||
*
|
||||
* @author Tyler Zeng
|
||||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @author Kirk Qi
|
||||
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
import {Heap, HeapItem} from './heap';
|
||||
import {PriorityQueue} from '../priority-queue';
|
||||
import type {HeapOptions} from '../../types';
|
||||
import {Heap} from './heap';
|
||||
import type {HeapComparator} from '../../types';
|
||||
|
||||
/**
|
||||
* @class MinHeap
|
||||
* @extends Heap
|
||||
*/
|
||||
export class MinHeap<V = any> extends Heap<V> {
|
||||
protected _pq: PriorityQueue<HeapItem<V>>;
|
||||
|
||||
/**
|
||||
* The constructor initializes a PriorityQueue with a comparator function that compares the priority of two HeapItem
|
||||
* objects.
|
||||
* @param [options] - The `options` parameter is an optional object that can be passed to the constructor. It is of
|
||||
* type `HeapOptions<V>`, which is a generic type that represents the options for the heap.
|
||||
*/
|
||||
constructor(options?: HeapOptions<V>) {
|
||||
super(options);
|
||||
this._pq = new PriorityQueue<HeapItem<V>>({
|
||||
comparator: (a, b) => a.priority - b.priority
|
||||
});
|
||||
export class MinHeap<E = any> extends Heap<E> {
|
||||
constructor(
|
||||
comparator: HeapComparator<E> = (a: E, b: E) => {
|
||||
if (!(typeof a === 'number' && typeof b === 'number')) {
|
||||
throw new Error('The a, b params of compare function must be number');
|
||||
} else {
|
||||
return a - b;
|
||||
}
|
||||
}
|
||||
) {
|
||||
super(comparator);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,56 +1,23 @@
|
|||
/**
|
||||
* data-structure-typed
|
||||
*
|
||||
* @author Tyler Zeng
|
||||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @author Kirk Qi
|
||||
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import {PriorityQueue} from './priority-queue';
|
||||
import type {PriorityQueueOptions, SpecifyOptional} from '../../types';
|
||||
import type {HeapComparator} from '../../types';
|
||||
|
||||
export class MaxPriorityQueue<E = any> extends PriorityQueue<E> {
|
||||
constructor(options?: Omit<PriorityQueueOptions<number>, 'comparator'>);
|
||||
constructor(options: PriorityQueueOptions<E>);
|
||||
|
||||
/**
|
||||
* The constructor initializes a priority queue with an optional comparator function.
|
||||
* @param [options] - The `options` parameter is an optional object that can contain various properties to configure
|
||||
* the priority queue.
|
||||
*/
|
||||
constructor(options?: SpecifyOptional<PriorityQueueOptions<E>, 'comparator'>) {
|
||||
super({
|
||||
...options,
|
||||
comparator: options?.comparator
|
||||
? options.comparator
|
||||
: (a: E, b: E) => {
|
||||
const aKey = a as unknown as number,
|
||||
bKey = b as unknown as number;
|
||||
return bKey - aKey;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static override heapify<E extends number>(options?: Omit<PriorityQueueOptions<E>, 'comparator'>): MaxPriorityQueue<E>;
|
||||
static override heapify<E>(options: PriorityQueueOptions<E>): MaxPriorityQueue<E>;
|
||||
|
||||
/**
|
||||
* The function `heapify` creates a max priority queue from the given options and returns it.
|
||||
* @param options - The `options` parameter is an object that contains configuration options for creating a priority
|
||||
* queue. It can have the following properties:
|
||||
* @returns a MaxPriorityQueue object.
|
||||
*/
|
||||
static override heapify<E>(options: PriorityQueueOptions<E>): MaxPriorityQueue<E> {
|
||||
const maxPQ = new MaxPriorityQueue<E>({
|
||||
...options,
|
||||
comparator: options?.comparator
|
||||
? options.comparator
|
||||
: (a: E, b: E) => {
|
||||
const aKey = a as unknown as number,
|
||||
bKey = b as unknown as number;
|
||||
return bKey - aKey;
|
||||
}
|
||||
});
|
||||
maxPQ._fix();
|
||||
return maxPQ;
|
||||
constructor(
|
||||
compare: HeapComparator<E> = (a: E, b: E) => {
|
||||
if (!(typeof a === 'number' && typeof b === 'number')) {
|
||||
throw new Error('The a, b params of compare function must be number');
|
||||
} else {
|
||||
return b - a;
|
||||
}
|
||||
}
|
||||
) {
|
||||
super(compare);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,57 +1,23 @@
|
|||
/**
|
||||
* data-structure-typed
|
||||
*
|
||||
* @author Tyler Zeng
|
||||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @author Kirk Qi
|
||||
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import {PriorityQueue} from './priority-queue';
|
||||
import type {PriorityQueueOptions, SpecifyOptional} from '../../types';
|
||||
import type {HeapComparator} from '../../types';
|
||||
|
||||
export class MinPriorityQueue<E = any> extends PriorityQueue<E> {
|
||||
constructor(options?: Omit<PriorityQueueOptions<number>, 'comparator'>);
|
||||
constructor(options: PriorityQueueOptions<E>);
|
||||
|
||||
/**
|
||||
* The constructor initializes a priority queue with an optional comparator function.
|
||||
* @param [options] - The `options` parameter is an optional object that can contain various configuration options for
|
||||
* the `PriorityQueue` constructor.
|
||||
*/
|
||||
constructor(options?: SpecifyOptional<PriorityQueueOptions<E>, 'comparator'>) {
|
||||
super({
|
||||
...options,
|
||||
comparator: options?.comparator
|
||||
? options.comparator
|
||||
: (a: E, b: E) => {
|
||||
const aKey = a as unknown as number,
|
||||
bKey = b as unknown as number;
|
||||
return aKey - bKey;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static override heapify<E extends number>(options?: Omit<PriorityQueueOptions<E>, 'comparator'>): MinPriorityQueue<E>;
|
||||
static override heapify<E>(options: PriorityQueueOptions<E>): MinPriorityQueue<E>;
|
||||
|
||||
/**
|
||||
* The function `heapify` creates a new MinPriorityQueue instance and sets the comparator function based on the options
|
||||
* provided, and then fixes the heap structure of the queue.
|
||||
* @param options - The `options` parameter is an object that contains configuration options for creating a priority
|
||||
* queue. It can have the following properties:
|
||||
* @returns a MinPriorityQueue object.
|
||||
*/
|
||||
static override heapify<E>(options: PriorityQueueOptions<E>): MinPriorityQueue<E> {
|
||||
const minPQ = new MinPriorityQueue<E>({
|
||||
...options,
|
||||
comparator: options?.comparator
|
||||
? options.comparator
|
||||
: (a: E, b: E) => {
|
||||
const aKey = a as unknown as number,
|
||||
bKey = b as unknown as number;
|
||||
return aKey - bKey;
|
||||
}
|
||||
});
|
||||
minPQ._fix();
|
||||
return minPQ;
|
||||
constructor(
|
||||
compare: HeapComparator<E> = (a: E, b: E) => {
|
||||
if (!(typeof a === 'number' && typeof b === 'number')) {
|
||||
throw new Error('The a, b params of compare function must be number');
|
||||
} else {
|
||||
return a - b;
|
||||
}
|
||||
}
|
||||
) {
|
||||
super(compare);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,359 +1,16 @@
|
|||
/**
|
||||
* data-structure-typed
|
||||
*
|
||||
* @author Tyler Zeng
|
||||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @author Kirk Qi
|
||||
* @copyright Copyright (c) 2022 Kirk Qi <qilinaus@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
import type {PriorityQueueComparator, PriorityQueueDFSOrderPattern, PriorityQueueOptions} from '../../types';
|
||||
|
||||
export class PriorityQueue<E = any> {
|
||||
/**
|
||||
* The constructor initializes a priority queue with the given options, including an array of nodes and a comparator
|
||||
* function.
|
||||
* @param options - The `options` parameter is an object that contains the following properties:
|
||||
*/
|
||||
constructor(options: PriorityQueueOptions<E>) {
|
||||
const {nodes, comparator, isFix = true} = options;
|
||||
this._comparator = comparator;
|
||||
import {Heap} from '../heap';
|
||||
import {HeapComparator} from '../../types';
|
||||
|
||||
if (nodes && Array.isArray(nodes) && nodes.length > 0) {
|
||||
// TODO support distinct
|
||||
this._nodes = [...nodes];
|
||||
isFix && this._fix();
|
||||
}
|
||||
export class PriorityQueue<E> extends Heap<E> {
|
||||
constructor(comparator: HeapComparator<E>) {
|
||||
super(comparator);
|
||||
}
|
||||
|
||||
protected _nodes: E[] = [];
|
||||
|
||||
get nodes(): E[] {
|
||||
return this._nodes;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this.nodes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `heapify` function creates a new PriorityQueue instance and fixes the heap property.
|
||||
* @param options - The "options" parameter is an object that contains the configuration options for the PriorityQueue.
|
||||
* It can include properties such as "comparator" which specifies the comparison function used to order the elements in
|
||||
* the priority queue, and "initialValues" which is an array of initial values to be added to the priority
|
||||
* @returns a new instance of the PriorityQueue class after performing the heapify operation on it.
|
||||
*/
|
||||
static heapify<E>(options: PriorityQueueOptions<E>) {
|
||||
const heap = new PriorityQueue(options);
|
||||
heap._fix();
|
||||
return heap;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks if a priority queue is valid by creating a new priority queue with a fix option and then calling
|
||||
* the isValid method.
|
||||
* @param options - An object containing options for creating a priority queue. The options object should have the
|
||||
* following properties:
|
||||
* @returns the result of calling the `isValid()` method on a new instance of the `PriorityQueue` class.
|
||||
*/
|
||||
static isPriorityQueueified<E>(options: Omit<PriorityQueueOptions<E>, 'isFix'>) {
|
||||
return new PriorityQueue({...options, isFix: false}).isValid();
|
||||
}
|
||||
|
||||
/**
|
||||
* Starting from TypeScript version 5.0 and onwards, the use of distinct access modifiers for Getters and Setters is not permitted. As an alternative, to ensure compatibility, it is necessary to adopt a Java-style approach for Setters (using the same name as the property) while utilizing separate method names for Getters.
|
||||
*/
|
||||
getNodes(): E[] {
|
||||
return this._nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* The "add" function adds a node to the heap and ensures that the heap property is maintained.
|
||||
* @param {E} node - The parameter "node" is of type E, which means it can be any data type. It represents the node
|
||||
* that needs to be added to the heap.
|
||||
*/
|
||||
add(node: E) {
|
||||
this.nodes.push(node);
|
||||
this._heapifyUp(this.size - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* The "has" function checks if a given node is present in the list of nodes.
|
||||
* @param {E} node - The parameter `node` is of type `E`, which means it can be any type. It represents the node that
|
||||
* we want to check if it exists in the `nodes` array.
|
||||
* @returns a boolean value indicating whether the given node is included in the array of nodes.
|
||||
*/
|
||||
has(node: E): boolean {
|
||||
return this.nodes.includes(node);
|
||||
}
|
||||
|
||||
/**
|
||||
* The `peek` function returns the first element of the `nodes` array if it exists, otherwise it returns `null`.
|
||||
* @returns The `peek()` function is returning the first element (`E`) of the `nodes` array if the `size` is not zero.
|
||||
* Otherwise, it returns `null`.
|
||||
*/
|
||||
peek(): E | null {
|
||||
return this.size ? this.nodes[0] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `poll` function removes and returns the top element from a heap data structure.
|
||||
* @returns The `poll()` method returns a value of type `E` or `null`.
|
||||
*/
|
||||
poll(): E | null {
|
||||
let res: E | null = null;
|
||||
if (this.size > 1) {
|
||||
this._swap(0, this.nodes.length - 1);
|
||||
res = this.nodes.pop() ?? null;
|
||||
this._heapifyDown(0);
|
||||
} else if (this.size === 1) {
|
||||
res = this.nodes.pop() ?? null;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `leaf` function returns the last element in the `nodes` array or `null` if the array is empty.
|
||||
* @returns The method `leaf()` is returning the last element (`E`) in the `nodes` array if it exists. If the array is
|
||||
* empty or the last element is `null`, then it returns `null`.
|
||||
*/
|
||||
leaf(): E | null {
|
||||
return this.nodes[this.size - 1] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks if the size of an object is equal to zero and returns a boolean value indicating whether the
|
||||
* object is empty or not.
|
||||
* @returns The method `isEmpty()` is returning a boolean value indicating whether the size of the object is equal to
|
||||
* 0.
|
||||
*/
|
||||
isEmpty() {
|
||||
return this.size === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The clear function clears the nodes array.
|
||||
*/
|
||||
clear() {
|
||||
this._setNodes([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* The toArray function returns an array containing all the elements in the nodes property.
|
||||
* @returns An array of type E, which is the elements of the nodes property.
|
||||
*/
|
||||
toArray(): E[] {
|
||||
return [...this.nodes];
|
||||
}
|
||||
|
||||
/**
|
||||
* The `clone` function returns a new instance of the `PriorityQueue` class with the same nodes and comparator as the
|
||||
* original instance.
|
||||
* @returns The `clone()` method is returning a new instance of the `PriorityQueue` class with the same `nodes` and
|
||||
* `comparator` properties as the original instance.
|
||||
*/
|
||||
clone(): PriorityQueue<E> {
|
||||
return new PriorityQueue<E>({
|
||||
nodes: this.nodes,
|
||||
comparator: this._comparator
|
||||
});
|
||||
}
|
||||
|
||||
// --- start additional methods ---
|
||||
/**
|
||||
* The `isValid` function recursively checks if a binary tree satisfies a certain condition.
|
||||
* @returns The function `isValid()` returns a boolean value.
|
||||
*/
|
||||
isValid(): boolean {
|
||||
for (let i = 0; i < this.nodes.length; i++) {
|
||||
const leftChildIndex = this._getLeft(i);
|
||||
const rightChildIndex = this._getRight(i);
|
||||
if (this._isValidIndex(leftChildIndex) && !this._compare(leftChildIndex, i)) {
|
||||
return false;
|
||||
}
|
||||
if (this._isValidIndex(rightChildIndex) && !this._compare(rightChildIndex, i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* O(n log n), In scenarios with smaller data sizes, heap sort is generally expected to be slower than QuickSort or MergeSort.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The function sorts the elements in a data structure and returns them in an array.
|
||||
* Plan to support sorting of duplicate elements.
|
||||
* @returns The `sort()` method is returning an array of type `E[]`.
|
||||
*/
|
||||
sort(): E[] {
|
||||
const visitedNode: E[] = [];
|
||||
while (this.size !== 0) {
|
||||
const top = this.poll();
|
||||
if (top) visitedNode.push(top);
|
||||
}
|
||||
return visitedNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* The DFS function performs a depth-first search traversal on a binary tree and returns an array of visited nodes
|
||||
* based on the specified traversal order.
|
||||
* @param {PriorityQueueDFSOrderPattern} dfsMode - The dfsMode parameter is a string that specifies the order in which
|
||||
* the nodes should be visited during the Depth-First Search (DFS) traversal. It can have one of the following values:
|
||||
* @returns an array of type `(E | null)[]`.
|
||||
*/
|
||||
DFS(dfsMode: PriorityQueueDFSOrderPattern): (E | null)[] {
|
||||
const visitedNode: (E | null)[] = [];
|
||||
|
||||
const traverse = (cur: number) => {
|
||||
const leftChildIndex = this._getLeft(cur);
|
||||
const rightChildIndex = this._getRight(cur);
|
||||
switch (dfsMode) {
|
||||
case 'in':
|
||||
this._isValidIndex(leftChildIndex) && traverse(leftChildIndex);
|
||||
visitedNode.push(this.nodes[cur] ?? null);
|
||||
this._isValidIndex(rightChildIndex) && traverse(rightChildIndex);
|
||||
break;
|
||||
case 'pre':
|
||||
visitedNode.push(this.nodes[cur] ?? null);
|
||||
this._isValidIndex(leftChildIndex) && traverse(leftChildIndex);
|
||||
this._isValidIndex(rightChildIndex) && traverse(rightChildIndex);
|
||||
break;
|
||||
case 'post':
|
||||
this._isValidIndex(leftChildIndex) && traverse(leftChildIndex);
|
||||
this._isValidIndex(rightChildIndex) && traverse(rightChildIndex);
|
||||
visitedNode.push(this.nodes[cur] ?? null);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
this._isValidIndex(0) && traverse(0);
|
||||
return visitedNode;
|
||||
}
|
||||
|
||||
protected _setNodes(value: E[]) {
|
||||
this._nodes = value;
|
||||
}
|
||||
|
||||
protected readonly _comparator: PriorityQueueComparator<E> = (a: E, b: E) => {
|
||||
const aKey = a as unknown as number,
|
||||
bKey = b as unknown as number;
|
||||
return aKey - bKey;
|
||||
};
|
||||
|
||||
/**
|
||||
* The function compares two numbers using a custom comparator function.
|
||||
* @param {number} a - The parameter "a" is a number that represents the index of a node in an array.
|
||||
* @param {number} b - The parameter "b" is a number.
|
||||
* @returns the result of the comparison between the elements at indices `a` and `b` in the `nodes` array. The
|
||||
* comparison is done using the `_comparator` function, and if the result is greater than 0, `true` is returned,
|
||||
* indicating that the element at index `a` is greater than the element at index `b`.
|
||||
*/
|
||||
protected _compare(a: number, b: number) {
|
||||
return this._comparator(this.nodes[a], this.nodes[b]) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function swaps two elements in an array.
|
||||
* @param {number} a - The parameter "a" is a number that represents the index of an element in an array.
|
||||
* @param {number} b - The parameter "b" is a number.
|
||||
*/
|
||||
protected _swap(a: number, b: number) {
|
||||
const temp = this.nodes[a];
|
||||
this.nodes[a] = this.nodes[b];
|
||||
this.nodes[b] = temp;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function checks if a given index is valid within an array.
|
||||
* @param {number} index - The parameter "index" is of type number and represents the index value that needs to be
|
||||
* checked for validity.
|
||||
* @returns A boolean value indicating whether the given index is valid or not.
|
||||
*/
|
||||
protected _isValidIndex(index: number): boolean {
|
||||
return index > -1 && index < this.nodes.length;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns the index of the parent node given the index of a child node in a binary tree.
|
||||
* @param {number} child - The "child" parameter is a number representing the index of a child node in a binary tree.
|
||||
* @returns the parent of the given child node.
|
||||
*/
|
||||
protected _getParent(child: number): number {
|
||||
return Math.floor((child - 1) / 2);
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns the index of the left child node in a binary tree given the index of its parent node.
|
||||
* @param {number} parent - The parameter "parent" is a number that represents the index of a node in a binary tree.
|
||||
* @returns the left child of a given parent node in a binary tree.
|
||||
*/
|
||||
protected _getLeft(parent: number): number {
|
||||
return 2 * parent + 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns the index of the right child node in a binary tree given the index of its parent node.
|
||||
* @param {number} parent - The parameter "parent" is a number that represents the index of a node in a binary tree.
|
||||
* @returns the right child of a given parent node in a binary tree.
|
||||
*/
|
||||
protected _getRight(parent: number): number {
|
||||
return 2 * parent + 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function returns the index of the smallest child node of a given parent node.
|
||||
* @param {number} parent - The parent parameter is a number that represents the index of the parent node in a binary
|
||||
* tree.
|
||||
* @returns the minimum value between the parent node and its left and right child nodes.
|
||||
*/
|
||||
protected _getComparedChild(parent: number) {
|
||||
let min = parent;
|
||||
const left = this._getLeft(parent),
|
||||
right = this._getRight(parent);
|
||||
|
||||
if (left < this.size && this._compare(min, left)) {
|
||||
min = left;
|
||||
}
|
||||
if (right < this.size && this._compare(min, right)) {
|
||||
min = right;
|
||||
}
|
||||
return min;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function `_heapifyUp` is used to maintain the heap property by moving an element up the heap until it is in the
|
||||
* correct position.
|
||||
* @param {number} start - The start parameter is the index of the element that needs to be moved up in the heap.
|
||||
*/
|
||||
protected _heapifyUp(start: number) {
|
||||
while (start > 0 && this._compare(this._getParent(start), start)) {
|
||||
const parent = this._getParent(start);
|
||||
this._swap(start, parent);
|
||||
start = parent;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The function performs a heapify operation by comparing and swapping elements in a binary heap.
|
||||
* @param {number} start - The start parameter is the index of the element in the heap from where the heapifyDown
|
||||
* operation should start.
|
||||
*/
|
||||
protected _heapifyDown(start: number) {
|
||||
let min = this._getComparedChild(start);
|
||||
while (this._compare(start, min)) {
|
||||
this._swap(min, start);
|
||||
start = min;
|
||||
min = this._getComparedChild(start);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The _fix function performs a heapify operation on the elements of the heap starting from the middle and moving
|
||||
* towards the root.
|
||||
*/
|
||||
protected _fix() {
|
||||
for (let i = Math.floor(this.size / 2); i > -1; i--) this._heapifyDown(i);
|
||||
}
|
||||
|
||||
// --- end additional methods ---
|
||||
}
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
export class TreeNode<V = any> {
|
||||
constructor(id: string, value?: V, children?: TreeNode<V>[]) {
|
||||
this._id = id;
|
||||
constructor(key: string, value?: V, children?: TreeNode<V>[]) {
|
||||
this._key = key;
|
||||
this._value = value || undefined;
|
||||
this._children = children || [];
|
||||
}
|
||||
|
||||
private _id: string;
|
||||
private _key: string;
|
||||
|
||||
get id(): string {
|
||||
return this._id;
|
||||
get key(): string {
|
||||
return this._key;
|
||||
}
|
||||
|
||||
set id(value: string) {
|
||||
this._id = value;
|
||||
set key(value: string) {
|
||||
this._key = value;
|
||||
}
|
||||
|
||||
private _value?: V | undefined;
|
||||
|
@ -47,10 +47,8 @@ export class TreeNode<V = any> {
|
|||
}
|
||||
|
||||
getHeight() {
|
||||
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||
const beginRoot = this;
|
||||
let maxDepth = 1;
|
||||
if (beginRoot) {
|
||||
let maxDepth = 0;
|
||||
if (this) {
|
||||
const bfs = (node: TreeNode<V>, level: number) => {
|
||||
if (level > maxDepth) {
|
||||
maxDepth = level;
|
||||
|
@ -62,7 +60,7 @@ export class TreeNode<V = any> {
|
|||
}
|
||||
}
|
||||
};
|
||||
bfs(beginRoot, 1);
|
||||
bfs(this, 0);
|
||||
}
|
||||
return maxDepth;
|
||||
}
|
||||
|
|
|
@ -5,21 +5,26 @@
|
|||
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
|
||||
* @license MIT License
|
||||
*/
|
||||
|
||||
/**
|
||||
* TrieNode represents a node in the Trie data structure. It holds a character key, a map of children nodes,
|
||||
* and a flag indicating whether it's the end of a word.
|
||||
*/
|
||||
export class TrieNode {
|
||||
constructor(v: string) {
|
||||
this._val = v;
|
||||
constructor(key: string) {
|
||||
this._key = key;
|
||||
this._isEnd = false;
|
||||
this._children = new Map<string, TrieNode>();
|
||||
}
|
||||
|
||||
private _val;
|
||||
private _key;
|
||||
|
||||
get val(): string {
|
||||
return this._val;
|
||||
get key(): string {
|
||||
return this._key;
|
||||
}
|
||||
|
||||
set val(v: string) {
|
||||
this._val = v;
|
||||
set key(v: string) {
|
||||
this._key = v;
|
||||
}
|
||||
|
||||
protected _children: Map<string, TrieNode>;
|
||||
|
@ -43,9 +48,13 @@ export class TrieNode {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Trie represents a Trie data structure. It provides basic Trie operations and additional methods.
|
||||
*/
|
||||
export class Trie {
|
||||
constructor(words?: string[]) {
|
||||
constructor(words?: string[], caseSensitive = true) {
|
||||
this._root = new TrieNode('');
|
||||
this._caseSensitive = caseSensitive;
|
||||
if (words) {
|
||||
for (const i of words) {
|
||||
this.add(i);
|
||||
|
@ -63,8 +72,16 @@ export class Trie {
|
|||
this._root = v;
|
||||
}
|
||||
|
||||
private readonly _caseSensitive: boolean;
|
||||
|
||||
/**
|
||||
* Add a word to the Trie structure.
|
||||
* @param {string} word - The word to add.
|
||||
* @returns {boolean} True if the word was successfully added.
|
||||
*/
|
||||
add(word: string): boolean {
|
||||
let cur = this._root;
|
||||
word = this._caseProcess(word);
|
||||
let cur = this.root;
|
||||
for (const c of word) {
|
||||
let nodeC = cur.children.get(c);
|
||||
if (!nodeC) {
|
||||
|
@ -77,9 +94,15 @@ export class Trie {
|
|||
return true;
|
||||
}
|
||||
|
||||
has(input: string): boolean {
|
||||
let cur = this._root;
|
||||
for (const c of input) {
|
||||
/**
|
||||
* Check if the Trie contains a given word.
|
||||
* @param {string} word - The word to check for.
|
||||
* @returns {boolean} True if the word is present in the Trie.
|
||||
*/
|
||||
has(word: string): boolean {
|
||||
word = this._caseProcess(word);
|
||||
let cur = this.root;
|
||||
for (const c of word) {
|
||||
const nodeC = cur.children.get(c);
|
||||
if (!nodeC) return false;
|
||||
cur = nodeC;
|
||||
|
@ -87,7 +110,20 @@ export class Trie {
|
|||
return cur.isEnd;
|
||||
}
|
||||
|
||||
private _caseProcess(str: string) {
|
||||
if (!this._caseSensitive) {
|
||||
str = str.toLowerCase(); // Convert str to lowercase if case-insensitive
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a word from the Trie structure.
|
||||
* @param{string} word - The word to remove.
|
||||
* @returns {boolean} True if the word was successfully removed.
|
||||
*/
|
||||
remove(word: string) {
|
||||
word = this._caseProcess(word);
|
||||
let isDeleted = false;
|
||||
const dfs = (cur: TrieNode, i: number): boolean => {
|
||||
const char = word[i];
|
||||
|
@ -119,14 +155,35 @@ export class Trie {
|
|||
return isDeleted;
|
||||
}
|
||||
|
||||
getHeight() {
|
||||
const beginRoot = this.root;
|
||||
let maxDepth = 0;
|
||||
if (beginRoot) {
|
||||
const bfs = (node: TrieNode, level: number) => {
|
||||
if (level > maxDepth) {
|
||||
maxDepth = level;
|
||||
}
|
||||
const {children} = node;
|
||||
if (children) {
|
||||
for (const child of children.entries()) {
|
||||
bfs(child[1], level + 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
bfs(beginRoot, 0);
|
||||
}
|
||||
return maxDepth;
|
||||
}
|
||||
|
||||
// --- start additional methods ---
|
||||
/**
|
||||
* The function checks if a given input string has an absolute prefix in a tree data structure.Only can present as a prefix, not a word
|
||||
* @param {string} input - The input parameter is a string that represents the input value for the function.
|
||||
* @returns a boolean value.
|
||||
* Check if a given input string has an absolute prefix in the Trie, meaning it's not a complete word.
|
||||
* @param {string} input - The input string to check.
|
||||
* @returns {boolean} True if it's an absolute prefix in the Trie.
|
||||
*/
|
||||
isAbsPrefix(input: string): boolean {
|
||||
let cur = this._root;
|
||||
hasPurePrefix(input: string): boolean {
|
||||
input = this._caseProcess(input);
|
||||
let cur = this.root;
|
||||
for (const c of input) {
|
||||
const nodeC = cur.children.get(c);
|
||||
if (!nodeC) return false;
|
||||
|
@ -136,12 +193,13 @@ export class Trie {
|
|||
}
|
||||
|
||||
/**
|
||||
* The function checks if a given input string is a prefix of any existing string in a tree structure.Can present as a abs prefix or word
|
||||
* @param {string} input - The input parameter is a string that represents the prefix we want to check.
|
||||
* @returns a boolean value.
|
||||
* Check if a given input string is a prefix of any existing word in the Trie, whether as an absolute prefix or a complete word.
|
||||
* @param {string} input - The input string representing the prefix to check.
|
||||
* @returns {boolean} True if it's a prefix in the Trie.
|
||||
*/
|
||||
isPrefix(input: string): boolean {
|
||||
let cur = this._root;
|
||||
hasPrefix(input: string): boolean {
|
||||
input = this._caseProcess(input);
|
||||
let cur = this.root;
|
||||
for (const c of input) {
|
||||
const nodeC = cur.children.get(c);
|
||||
if (!nodeC) return false;
|
||||
|
@ -151,50 +209,51 @@ export class Trie {
|
|||
}
|
||||
|
||||
/**
|
||||
* The function checks if the input string is a common prefix in a Trie data structure.Check if the input string is the common prefix of all the words
|
||||
* @param {string} input - The input parameter is a string that represents the common prefix that we want to check for
|
||||
* in the Trie data structure.
|
||||
* @returns a boolean value indicating whether the input string is a common prefix in the Trie data structure.
|
||||
* Check if the input string is a common prefix in the Trie, meaning it's a prefix shared by all words in the Trie.
|
||||
* @param {string} input - The input string representing the common prefix to check for.
|
||||
* @returns {boolean} True if it's a common prefix in the Trie.
|
||||
*/
|
||||
isCommonPrefix(input: string): boolean {
|
||||
hasCommonPrefix(input: string): boolean {
|
||||
input = this._caseProcess(input);
|
||||
let commonPre = '';
|
||||
const dfs = (cur: TrieNode) => {
|
||||
commonPre += cur.val;
|
||||
commonPre += cur.key;
|
||||
if (commonPre === input) return;
|
||||
if (cur.isEnd) return;
|
||||
if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]);
|
||||
else return;
|
||||
};
|
||||
dfs(this._root);
|
||||
dfs(this.root);
|
||||
return commonPre === input;
|
||||
}
|
||||
|
||||
/**
|
||||
* The function `getLongestCommonPrefix` returns the longest common prefix among all the words stored in a Trie data
|
||||
* structure.
|
||||
* @returns The function `getLongestCommonPrefix` returns a string, which is the longest common prefix found in the
|
||||
* Trie.
|
||||
* Get the longest common prefix among all the words stored in the Trie.
|
||||
* @returns {string} The longest common prefix found in the Trie.
|
||||
*/
|
||||
getLongestCommonPrefix(): string {
|
||||
let commonPre = '';
|
||||
const dfs = (cur: TrieNode) => {
|
||||
commonPre += cur.val;
|
||||
commonPre += cur.key;
|
||||
if (cur.isEnd) return;
|
||||
if (cur && cur.children && cur.children.size === 1) dfs(Array.from(cur.children.values())[0]);
|
||||
else return;
|
||||
};
|
||||
dfs(this._root);
|
||||
dfs(this.root);
|
||||
return commonPre;
|
||||
}
|
||||
|
||||
/**
|
||||
* The `getAll` function returns an array of all words in a Trie data structure that start with a given prefix.
|
||||
* @param [prefix] - The `prefix` parameter is a string that represents the prefix that we want to search for in the
|
||||
* @param {string} prefix - The `prefix` parameter is a string that represents the prefix that we want to search for in the
|
||||
* trie. It is an optional parameter, so if no prefix is provided, it will default to an empty string.
|
||||
* @returns an array of strings.
|
||||
* @param {number} max - The max count of words will be found
|
||||
* @returns {string[]} an array of strings.
|
||||
*/
|
||||
getAll(prefix = ''): string[] {
|
||||
getWords(prefix = '', max = Number.MAX_SAFE_INTEGER): string[] {
|
||||
prefix = this._caseProcess(prefix);
|
||||
const words: string[] = [];
|
||||
let found = 0;
|
||||
|
||||
function dfs(node: TrieNode, word: string) {
|
||||
for (const char of node.children.keys()) {
|
||||
|
@ -204,11 +263,13 @@ export class Trie {
|
|||
}
|
||||
}
|
||||
if (node.isEnd) {
|
||||
if (found > max - 1) return;
|
||||
words.push(word);
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
let startNode = this._root;
|
||||
let startNode = this.root;
|
||||
|
||||
if (prefix) {
|
||||
for (const c of prefix) {
|
||||
|
@ -216,8 +277,8 @@ export class Trie {
|
|||
if (nodeC) startNode = nodeC;
|
||||
}
|
||||
}
|
||||
if (startNode !== this.root) dfs(startNode, prefix);
|
||||
|
||||
dfs(startNode, prefix);
|
||||
return words;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,189 +0,0 @@
|
|||
import {
|
||||
AbstractBinaryTreeNodeProperties,
|
||||
AbstractBinaryTreeNodeProperty,
|
||||
BinaryTreeDeletedResult,
|
||||
BinaryTreeNodeId,
|
||||
BinaryTreeNodePropertyName,
|
||||
DFSOrderPattern,
|
||||
FamilyPosition,
|
||||
LoopType,
|
||||
NodeOrPropertyName
|
||||
} from '../types';
|
||||
import {AbstractBinaryTreeNode} from '../data-structures';
|
||||
|
||||
export interface IAbstractBinaryTreeNode<T, NEIGHBOR extends IAbstractBinaryTreeNode<T, NEIGHBOR>> {
|
||||
get id(): BinaryTreeNodeId;
|
||||
|
||||
set id(v: BinaryTreeNodeId);
|
||||
|
||||
get val(): T | undefined;
|
||||
|
||||
set val(v: T | undefined);
|
||||
|
||||
get left(): NEIGHBOR | null | undefined;
|
||||
|
||||
set left(v: NEIGHBOR | null | undefined);
|
||||
|
||||
get right(): NEIGHBOR | null | undefined;
|
||||
|
||||
set right(v: NEIGHBOR | null | undefined);
|
||||
|
||||
get parent(): NEIGHBOR | null | undefined;
|
||||
|
||||
set parent(v: NEIGHBOR | null | undefined);
|
||||
|
||||
get familyPosition(): FamilyPosition;
|
||||
|
||||
get height(): number;
|
||||
|
||||
set height(v: number);
|
||||
}
|
||||
|
||||
export interface IAbstractBinaryTree<N extends AbstractBinaryTreeNode<N['val'], N>> {
|
||||
createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N | null;
|
||||
|
||||
get loopType(): LoopType;
|
||||
|
||||
get visitedId(): BinaryTreeNodeId[];
|
||||
|
||||
get visitedVal(): Array<N['val']>;
|
||||
|
||||
get visitedNode(): N[];
|
||||
|
||||
get root(): N | null;
|
||||
|
||||
get size(): number;
|
||||
|
||||
swapLocation(srcNode: N, destNode: N): N;
|
||||
|
||||
clear(): void;
|
||||
|
||||
isEmpty(): boolean;
|
||||
|
||||
add(id: BinaryTreeNodeId | N, val?: N['val']): N | null | undefined;
|
||||
|
||||
addMany(idsOrNodes: (BinaryTreeNodeId | N | null)[], data?: N['val'][]): (N | null | undefined)[];
|
||||
|
||||
fill(idsOrNodes: (BinaryTreeNodeId | N | null)[], data?: N[] | Array<N['val']>): boolean;
|
||||
|
||||
remove(id: BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[];
|
||||
|
||||
getDepth(node: N): number;
|
||||
|
||||
getHeight(beginRoot?: N | null): number;
|
||||
|
||||
getMinHeight(beginRoot?: N | null): number;
|
||||
|
||||
isPerfectlyBalanced(beginRoot?: N | null): boolean;
|
||||
|
||||
getNodes(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName, onlyOne?: boolean): N[];
|
||||
|
||||
has(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): boolean;
|
||||
|
||||
get(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): N | null;
|
||||
|
||||
getPathToRoot(node: N): N[];
|
||||
|
||||
getLeftMost(): N | null;
|
||||
|
||||
getLeftMost(node: N): N;
|
||||
|
||||
getLeftMost(node?: N | null): N | null;
|
||||
|
||||
getRightMost(): N | null;
|
||||
|
||||
getRightMost(node: N): N;
|
||||
|
||||
getRightMost(node?: N | null): N | null;
|
||||
|
||||
isSubtreeBST(node: N | null): boolean;
|
||||
|
||||
isBST(): boolean;
|
||||
|
||||
getSubTreeSize(subTreeRoot: N | null | undefined): number;
|
||||
|
||||
// --- start additional methods ---
|
||||
|
||||
subTreeSum(subTreeRoot: N, propertyName?: BinaryTreeNodePropertyName): number;
|
||||
|
||||
subTreeAdd(subTreeRoot: N, delta: number, propertyName?: BinaryTreeNodePropertyName): boolean;
|
||||
|
||||
BFS(): BinaryTreeNodeId[];
|
||||
|
||||
BFS(nodeOrPropertyName: 'id'): BinaryTreeNodeId[];
|
||||
|
||||
BFS(nodeOrPropertyName: 'val'): N['val'][];
|
||||
|
||||
BFS(nodeOrPropertyName: 'node'): N[];
|
||||
|
||||
BFS(nodeOrPropertyName: 'count'): number[];
|
||||
|
||||
BFS(nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>;
|
||||
|
||||
DFS(): BinaryTreeNodeId[];
|
||||
|
||||
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
|
||||
|
||||
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): N[];
|
||||
|
||||
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): N[];
|
||||
|
||||
DFS(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[];
|
||||
|
||||
DFS(pattern?: 'in' | 'pre' | 'post', nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>;
|
||||
|
||||
DFSIterative(): BinaryTreeNodeId[];
|
||||
|
||||
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
|
||||
|
||||
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): N[];
|
||||
|
||||
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): N[];
|
||||
|
||||
DFSIterative(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[];
|
||||
|
||||
DFSIterative(
|
||||
pattern?: 'in' | 'pre' | 'post',
|
||||
nodeOrPropertyName?: NodeOrPropertyName
|
||||
): AbstractBinaryTreeNodeProperties<N>;
|
||||
|
||||
levelIterative(node: N | null): BinaryTreeNodeId[];
|
||||
|
||||
levelIterative(node: N | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
|
||||
|
||||
levelIterative(node: N | null, nodeOrPropertyName?: 'val'): N['val'][];
|
||||
|
||||
levelIterative(node: N | null, nodeOrPropertyName?: 'node'): N[];
|
||||
|
||||
levelIterative(node: N | null, nodeOrPropertyName?: 'count'): number[];
|
||||
|
||||
levelIterative(node: N | null, nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>;
|
||||
|
||||
listLevels(node: N | null): BinaryTreeNodeId[][];
|
||||
|
||||
listLevels(node: N | null, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[][];
|
||||
|
||||
listLevels(node: N | null, nodeOrPropertyName?: 'val'): N['val'][][];
|
||||
|
||||
listLevels(node: N | null, nodeOrPropertyName?: 'node'): N[][];
|
||||
|
||||
listLevels(node: N | null, nodeOrPropertyName?: 'count'): number[][];
|
||||
|
||||
listLevels(node: N | null, nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperty<N>[][];
|
||||
|
||||
getPredecessor(node: N): N;
|
||||
|
||||
morris(): BinaryTreeNodeId[];
|
||||
|
||||
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'id'): BinaryTreeNodeId[];
|
||||
|
||||
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'val'): N[];
|
||||
|
||||
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'node'): N[];
|
||||
|
||||
morris(pattern?: DFSOrderPattern, nodeOrPropertyName?: 'count'): number[];
|
||||
|
||||
morris(pattern?: 'in' | 'pre' | 'post', nodeOrPropertyName?: NodeOrPropertyName): AbstractBinaryTreeNodeProperties<N>;
|
||||
|
||||
// --- end additional methods ---
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
import {VertexId} from '../types';
|
||||
|
||||
export interface IAbstractGraph<V, E> {
|
||||
hasVertex(vertexOrId: V | VertexId): boolean;
|
||||
|
||||
addVertex(id: VertexId, val?: V): boolean;
|
||||
|
||||
removeVertex(vertexOrId: V | VertexId): boolean;
|
||||
|
||||
removeAllVertices(vertices: V[] | VertexId[]): boolean;
|
||||
|
||||
degreeOf(vertexOrId: V | VertexId): number;
|
||||
|
||||
edgesOf(vertexOrId: V | VertexId): E[];
|
||||
|
||||
hasEdge(src: V | VertexId, dest: V | VertexId): boolean;
|
||||
|
||||
getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
|
||||
|
||||
edgeSet(): E[];
|
||||
|
||||
addEdge(src: V | VertexId, dest: V | VertexId, weight: number, val: E): boolean;
|
||||
|
||||
removeEdge(edge: E): E | null;
|
||||
|
||||
setEdgeWeight(srcOrId: V | VertexId, destOrId: V | VertexId, weight: number): boolean;
|
||||
|
||||
getMinPathBetween(v1: V | VertexId, v2: V | VertexId, isWeight?: boolean): V[] | null;
|
||||
|
||||
getNeighbors(vertexOrId: V | VertexId): V[];
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
import {AVLTreeNode} from '../data-structures';
|
||||
import {IBST, IBSTNode} from './bst';
|
||||
import {BinaryTreeDeletedResult, BinaryTreeNodeId} from '../types';
|
||||
|
||||
export type IAVLTreeNode<T, NEIGHBOR extends IAVLTreeNode<T, NEIGHBOR>> = IBSTNode<T, NEIGHBOR>;
|
||||
|
||||
export interface IAVLTree<N extends AVLTreeNode<N['val'], N>> extends IBST<N> {
|
||||
add(id: BinaryTreeNodeId, val?: N['val'] | null): N | null | undefined;
|
||||
|
||||
remove(id: BinaryTreeNodeId): BinaryTreeDeletedResult<N>[];
|
||||
|
||||
// _balanceFactor(node: N): number
|
||||
//
|
||||
// _updateHeight(node: N): void
|
||||
//
|
||||
// _balancePath(node: N): void
|
||||
//
|
||||
// _balanceLL(A: N): void
|
||||
//
|
||||
// _balanceLR(A: N): void
|
||||
//
|
||||
// _balanceRR(A: N): void
|
||||
//
|
||||
// _balanceRL(A: N): void
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
import {BinaryTreeNode} from '../data-structures';
|
||||
import {IAbstractBinaryTree, IAbstractBinaryTreeNode} from './abstract-binary-tree';
|
||||
import {BinaryTreeDeletedResult, BinaryTreeNodeKey} from '../types';
|
||||
|
||||
export type IBinaryTreeNode<T, NEIGHBOR extends IBinaryTreeNode<T, NEIGHBOR>> = IAbstractBinaryTreeNode<T, NEIGHBOR>;
|
||||
export interface IBinaryTree<N extends BinaryTreeNode<N['val'], N>> {
|
||||
createNode(key: BinaryTreeNodeKey, val?: N['val']): N;
|
||||
|
||||
export type IBinaryTree<N extends BinaryTreeNode<N['val'], N>> = IAbstractBinaryTree<N>;
|
||||
add(keyOrNode: BinaryTreeNodeKey | N | null, val?: N['val']): N | null | undefined;
|
||||
|
||||
remove(nodeOrKey: N | BinaryTreeNodeKey): BinaryTreeDeletedResult<N>[];
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
import {BSTNode} from '../data-structures';
|
||||
import {IBinaryTree, IBinaryTreeNode} from './binary-tree';
|
||||
import {BinaryTreeDeletedResult, BinaryTreeNodeId, BinaryTreeNodePropertyName} from '../types';
|
||||
|
||||
export type IBSTNode<T, NEIGHBOR extends IBSTNode<T, NEIGHBOR>> = IBinaryTreeNode<T, NEIGHBOR>;
|
||||
|
||||
export interface IBST<N extends BSTNode<N['val'], N>> extends IBinaryTree<N> {
|
||||
createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N;
|
||||
|
||||
add(id: BinaryTreeNodeId, val?: N['val'] | null, count?: number): N | null | undefined;
|
||||
|
||||
get(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName): N | null;
|
||||
|
||||
lastKey(): BinaryTreeNodeId;
|
||||
|
||||
remove(id: BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeletedResult<N>[];
|
||||
|
||||
getNodes(nodeProperty: BinaryTreeNodeId | N, propertyName?: BinaryTreeNodePropertyName, onlyOne?: boolean): N[];
|
||||
|
||||
// --- start additional functions
|
||||
|
||||
lesserSum(id: BinaryTreeNodeId, propertyName?: BinaryTreeNodePropertyName): number;
|
||||
|
||||
allGreaterNodesAdd(node: N, delta: number, propertyName?: BinaryTreeNodePropertyName): boolean;
|
||||
|
||||
perfectlyBalance(): boolean;
|
||||
|
||||
isAVLBalanced(): boolean;
|
||||
|
||||
// --- end additional functions
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
import {VertexId} from '../types';
|
||||
import {IAbstractGraph} from './abstract-graph';
|
||||
|
||||
export interface IDirectedGraph<V, E> extends IAbstractGraph<V, E> {
|
||||
incomingEdgesOf(vertex: V): E[];
|
||||
|
||||
outgoingEdgesOf(vertex: V): E[];
|
||||
|
||||
inDegreeOf(vertexOrId: V | VertexId): number;
|
||||
|
||||
outDegreeOf(vertexOrId: V | VertexId): number;
|
||||
|
||||
getEdgeSrc(e: E): V | null;
|
||||
|
||||
getEdgeDest(e: E): V | null;
|
||||
|
||||
removeEdgeSrcToDest(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
|
||||
|
||||
removeEdgesBetween(v1: V | VertexId, v2: V | VertexId): E[];
|
||||
}
|
7
src/interfaces/graph.ts
Normal file
7
src/interfaces/graph.ts
Normal file
|
@ -0,0 +1,7 @@
|
|||
import {VertexKey} from '../types';
|
||||
|
||||
export interface IGraph<V, E> {
|
||||
createVertex(key: VertexKey, val?: V): V;
|
||||
|
||||
createEdge(srcOrV1: VertexKey | string, destOrV2: VertexKey | string, weight?: number, val?: E): E;
|
||||
}
|
|
@ -1,15 +1,8 @@
|
|||
export * from './abstract-binary-tree';
|
||||
export * from './abstract-graph';
|
||||
export * from './avl-tree';
|
||||
export * from './graph';
|
||||
export * from './binary-tree';
|
||||
export * from './bst';
|
||||
export * from './directed-graph';
|
||||
export * from './doubly-linked-list';
|
||||
export * from './heap';
|
||||
export * from './navigator';
|
||||
export * from './priority-queue';
|
||||
export * from './rb-tree';
|
||||
export * from './segment-tree';
|
||||
export * from './singly-linked-list';
|
||||
export * from './tree-multiset';
|
||||
export * from './undirected-graph';
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
import {RBTreeNode} from '../data-structures';
|
||||
import {IBST, IBSTNode} from './bst';
|
||||
import {BinaryTreeNodeId} from '../types';
|
||||
|
||||
export type IRBTreeNode<T, NEIGHBOR extends IRBTreeNode<T, NEIGHBOR>> = IBSTNode<T, NEIGHBOR>;
|
||||
|
||||
export interface IRBTree<N extends RBTreeNode<N['val'], N>> extends IBST<N> {
|
||||
createNode(id: BinaryTreeNodeId, val?: N['val'], count?: number): N;
|
||||
}
|
|
@ -1,7 +0,0 @@
|
|||
import {TreeMultisetNode} from '../data-structures';
|
||||
import {IBSTNode} from './bst';
|
||||
import {IAVLTree} from './avl-tree';
|
||||
|
||||
export type ITreeMultisetNode<T, NEIGHBOR extends ITreeMultisetNode<T, NEIGHBOR>> = IBSTNode<T, NEIGHBOR>;
|
||||
|
||||
export type ITreeMultiset<N extends TreeMultisetNode<N['val'], N>> = IAVLTree<N>;
|
|
@ -1,6 +0,0 @@
|
|||
import {VertexId} from '../types';
|
||||
import {IAbstractGraph} from './abstract-graph';
|
||||
|
||||
export interface IUNDirectedGraph<V, E> extends IAbstractGraph<V, E> {
|
||||
removeEdgeBetween(v1: V | VertexId, v2: V | VertexId): E | null;
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
import {AbstractBinaryTreeNode} from '../../data-structures';
|
||||
|
||||
/**
|
||||
* Enum representing different loop types.
|
||||
*
|
||||
* - `iterative`: Indicates the iterative loop type (with loops that use iterations).
|
||||
* - `recursive`: Indicates the recursive loop type (with loops that call themselves).
|
||||
*/
|
||||
|
||||
export enum LoopType {
|
||||
ITERATIVE = 'ITERATIVE',
|
||||
RECURSIVE = 'RECURSIVE'
|
||||
}
|
||||
|
||||
/* This enumeration defines the position of a node within a family tree composed of three associated nodes, where 'root' represents the root node of the family tree, 'left' represents the left child node, and 'right' represents the right child node. */
|
||||
export enum FamilyPosition {
|
||||
ROOT = 'ROOT',
|
||||
LEFT = 'LEFT',
|
||||
RIGHT = 'RIGHT',
|
||||
ROOT_LEFT = 'ROOT_LEFT',
|
||||
ROOT_RIGHT = 'ROOT_RIGHT',
|
||||
ISOLATED = 'ISOLATED',
|
||||
MAL_NODE = 'MAL_NODE'
|
||||
}
|
||||
|
||||
export type BinaryTreeNodePropertyName = 'id' | 'val';
|
||||
|
||||
export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName;
|
||||
|
||||
export type DFSOrderPattern = 'in' | 'pre' | 'post';
|
||||
|
||||
export type BinaryTreeNodeId = number;
|
||||
|
||||
export type BinaryTreeDeletedResult<N> = { deleted: N | null | undefined; needBalanced: N | null };
|
||||
|
||||
export type AbstractBinaryTreeNodeProperty<N extends AbstractBinaryTreeNode<N['val'], N>> =
|
||||
| N['val']
|
||||
| N
|
||||
| number
|
||||
| BinaryTreeNodeId;
|
||||
|
||||
|
||||
export type AbstractBinaryTreeNodeProperties<N extends AbstractBinaryTreeNode<N['val'], N>> =
|
||||
AbstractBinaryTreeNodeProperty<N>[];
|
||||
|
||||
export type AbstractBinaryTreeNodeNested<T> = AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, AbstractBinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>;
|
||||
|
||||
export type AbstractBinaryTreeOptions = {
|
||||
loopType?: LoopType
|
||||
};
|
|
@ -1,5 +1,5 @@
|
|||
export type VertexId = string | number;
|
||||
export type EdgeId = string;
|
||||
export type VertexKey = string | number;
|
||||
|
||||
export type DijkstraResult<V> = {
|
||||
distMap: Map<V, number>;
|
||||
distPaths?: Map<V, V[]>;
|
||||
|
|
|
@ -1,5 +1,45 @@
|
|||
import {BinaryTreeNode} from '../../data-structures/binary-tree';
|
||||
import {AbstractBinaryTreeOptions} from './abstract-binary-tree';
|
||||
|
||||
/**
|
||||
* Enum representing different loop types.
|
||||
*
|
||||
* - `iterative`: Indicates the iterative loop type (with loops that use iterations).
|
||||
* - `recursive`: Indicates the recursive loop type (with loops that call themselves).
|
||||
*/
|
||||
|
||||
export enum LoopType {
|
||||
ITERATIVE = 'ITERATIVE',
|
||||
RECURSIVE = 'RECURSIVE'
|
||||
}
|
||||
|
||||
export enum FamilyPosition {
|
||||
ROOT = 'ROOT',
|
||||
LEFT = 'LEFT',
|
||||
RIGHT = 'RIGHT',
|
||||
ROOT_LEFT = 'ROOT_LEFT',
|
||||
ROOT_RIGHT = 'ROOT_RIGHT',
|
||||
ISOLATED = 'ISOLATED',
|
||||
MAL_NODE = 'MAL_NODE'
|
||||
}
|
||||
|
||||
export type BinaryTreeNodePropertyName = 'key' | 'val';
|
||||
|
||||
export type NodeOrPropertyName = 'node' | BinaryTreeNodePropertyName;
|
||||
|
||||
export type DFSOrderPattern = 'in' | 'pre' | 'post';
|
||||
|
||||
export type BinaryTreeNodeKey = number;
|
||||
|
||||
export type BinaryTreeNodeProperty<N extends BinaryTreeNode<N['val'], N>> =
|
||||
| N['val']
|
||||
| N
|
||||
| number
|
||||
| BinaryTreeNodeKey;
|
||||
export type BinaryTreeDeletedResult<N> = { deleted: N | null | undefined; needBalanced: N | null };
|
||||
|
||||
export type BinaryTreeNodeProperties<N extends BinaryTreeNode<N['val'], N>> =
|
||||
BinaryTreeNodeProperty<N>[];
|
||||
|
||||
export type BinaryTreeNodeNested<T> = BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, BinaryTreeNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
export type BinaryTreeOptions = AbstractBinaryTreeOptions & {}
|
||||
|
||||
export type BinaryTreeOptions = { loopType?: LoopType }
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
import {BSTNode} from '../../data-structures/binary-tree';
|
||||
import type {BinaryTreeOptions} from './binary-tree';
|
||||
import {BinaryTreeNodeId} from './abstract-binary-tree';
|
||||
import type {BinaryTreeNodeKey, BinaryTreeOptions} from './binary-tree';
|
||||
|
||||
export type BSTComparator = (a: BinaryTreeNodeId, b: BinaryTreeNodeId) => number;
|
||||
export type BSTComparator = (a: BinaryTreeNodeKey, b: BinaryTreeNodeKey) => number;
|
||||
|
||||
// prettier-ignore
|
||||
export type BSTNodeNested<T> = BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, BSTNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
export type BSTOptions = BinaryTreeOptions & {
|
||||
comparator?: BSTComparator,
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
export type HeapOptions<T> = {
|
||||
priorityExtractor?: (element: T) => number;
|
||||
// TODO there is an idea that support chaining which is for conveniently using the data structure
|
||||
// isChaining? : boolean
|
||||
};
|
||||
export type HeapComparator<T> = (a: T, b: T) => number;
|
||||
|
||||
export type HeapDFSOrderPattern = 'pre' | 'in' | 'post';
|
||||
|
|
|
@ -5,10 +5,8 @@ export * from './segment-tree';
|
|||
export * from './tree-multiset';
|
||||
export * from './abstract-graph';
|
||||
export * from './map-graph';
|
||||
export * from './abstract-binary-tree';
|
||||
export * from './rb-tree';
|
||||
export * from './directed-graph';
|
||||
export * from './priority-queue';
|
||||
export * from './heap';
|
||||
export * from './singly-linked-list';
|
||||
export * from './doubly-linked-list';
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
export type Direction = 'up' | 'right' | 'down' | 'left';
|
||||
|
||||
export type Turning = {[key in Direction]: Direction};
|
||||
|
||||
export type NavigatorParams<T = any> = {
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
export type PriorityQueueComparator<T> = (a: T, b: T) => number;
|
||||
|
||||
export type PriorityQueueOptions<T> = {
|
||||
nodes?: T[];
|
||||
isFix?: boolean;
|
||||
comparator: PriorityQueueComparator<T>;
|
||||
};
|
||||
|
||||
export type PriorityQueueDFSOrderPattern = 'pre' | 'in' | 'post';
|
|
@ -3,4 +3,4 @@ import {AVLTreeOptions} from './avl-tree';
|
|||
|
||||
export type TreeMultisetNodeNested<T> = TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, TreeMultisetNode<T, any>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
|
||||
|
||||
export type TreeMultisetOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedNodeById'> & {}
|
||||
export type TreeMultisetOptions = Omit<AVLTreeOptions, 'isMergeDuplicatedNodeByKey'> & {}
|
||||
|
|
|
@ -1,26 +1,26 @@
|
|||
export type KeyValueObject = {[key: string]: any};
|
||||
|
||||
export type KeyValueObjectWithId = {[key: string]: any; id: string | number | symbol};
|
||||
export type KeyValueObjectWithKey = {[key: string]: any; key: string | number | symbol};
|
||||
|
||||
export type NonNumberNonObjectButDefined = string | boolean | symbol | null;
|
||||
|
||||
export type ObjectWithoutId = Omit<KeyValueObject, 'id'>;
|
||||
export type ObjectWithoutKey = Omit<KeyValueObject, 'key'>;
|
||||
|
||||
export type ObjectWithNonNumberId = {
|
||||
export type ObjectWithNonNumberKey = {
|
||||
[key: string]: any;
|
||||
id: string | boolean | symbol | null | object | undefined;
|
||||
key: string | boolean | symbol | null | object | undefined;
|
||||
};
|
||||
|
||||
export type ObjectWithNumberId = {
|
||||
export type ObjectWithNumberKey = {
|
||||
[key: string]: any;
|
||||
id: number;
|
||||
key: number;
|
||||
};
|
||||
|
||||
export type RestrictValById =
|
||||
export type RestrictValByKey =
|
||||
| NonNumberNonObjectButDefined
|
||||
| ObjectWithoutId
|
||||
| ObjectWithNonNumberId
|
||||
| ObjectWithNumberId;
|
||||
| ObjectWithoutKey
|
||||
| ObjectWithNonNumberKey
|
||||
| ObjectWithNumberKey;
|
||||
|
||||
export type DummyAny =
|
||||
| string
|
||||
|
|
|
@ -12,15 +12,15 @@ describe('AVL Tree Test', () => {
|
|||
expect(node6 && tree.getHeight(node6)).toBe(3);
|
||||
expect(node6 && tree.getDepth(node6)).toBe(1);
|
||||
|
||||
const getNodeById = tree.get(10, 'id');
|
||||
expect(getNodeById?.id).toBe(10);
|
||||
const getNodeById = tree.get(10, 'key');
|
||||
expect(getNodeById?.key).toBe(10);
|
||||
|
||||
const getMinNodeByRoot = tree.getLeftMost();
|
||||
expect(getMinNodeByRoot?.id).toBe(1);
|
||||
expect(getMinNodeByRoot?.key).toBe(1);
|
||||
|
||||
const node15 = tree.get(15);
|
||||
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15);
|
||||
expect(getMinNodeBySpecificNode?.id).toBe(12);
|
||||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
const subTreeSum = node15 && tree.subTreeSum(node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
@ -31,78 +31,78 @@ describe('AVL Tree Test', () => {
|
|||
// node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class.
|
||||
expect(node15?.val).toBe(15);
|
||||
|
||||
const dfs = tree.DFS('in', 'node');
|
||||
expect(dfs[0].id).toBe(1);
|
||||
expect(dfs[dfs.length - 1].id).toBe(16);
|
||||
const dfs = tree.dfs('in', 'node');
|
||||
expect(dfs[0].key).toBe(1);
|
||||
expect(dfs[dfs.length - 1].key).toBe(16);
|
||||
|
||||
tree.perfectlyBalance();
|
||||
const bfs = tree.BFS('node');
|
||||
const bfs = tree.bfs('node');
|
||||
expect(tree.isPerfectlyBalanced()).toBe(true);
|
||||
expect(bfs[0].id).toBe(8);
|
||||
expect(bfs[bfs.length - 1].id).toBe(16);
|
||||
expect(bfs[0].key).toBe(8);
|
||||
expect(bfs[bfs.length - 1].key).toBe(16);
|
||||
|
||||
expect(tree.remove(11)[0].deleted?.id).toBe(11);
|
||||
expect(tree.remove(11)[0].deleted?.key).toBe(11);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(node15 && tree.getHeight(node15)).toBe(2);
|
||||
|
||||
expect(tree.remove(1)[0].deleted?.id).toBe(1);
|
||||
expect(tree.remove(1)[0].deleted?.key).toBe(1);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(4);
|
||||
|
||||
expect(tree.remove(4)[0].deleted?.id).toBe(4);
|
||||
expect(tree.remove(4)[0].deleted?.key).toBe(4);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(4);
|
||||
|
||||
expect(tree.remove(10)[0].deleted?.id).toBe(10);
|
||||
expect(tree.remove(10)[0].deleted?.key).toBe(10);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(15)[0].deleted?.id).toBe(15);
|
||||
expect(tree.remove(15)[0].deleted?.key).toBe(15);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(5)[0].deleted?.id).toBe(5);
|
||||
expect(tree.remove(5)[0].deleted?.key).toBe(5);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(13)[0].deleted?.id).toBe(13);
|
||||
expect(tree.remove(13)[0].deleted?.key).toBe(13);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(3)[0].deleted?.id).toBe(3);
|
||||
expect(tree.remove(3)[0].deleted?.key).toBe(3);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(8)[0].deleted?.id).toBe(8);
|
||||
expect(tree.remove(8)[0].deleted?.key).toBe(8);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(6)[0].deleted?.id).toBe(6);
|
||||
expect(tree.remove(6)[0].deleted?.key).toBe(6);
|
||||
expect(tree.remove(6).length).toBe(0);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(2);
|
||||
|
||||
expect(tree.remove(7)[0].deleted?.id).toBe(7);
|
||||
expect(tree.remove(7)[0].deleted?.key).toBe(7);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(2);
|
||||
|
||||
expect(tree.remove(9)[0].deleted?.id).toBe(9);
|
||||
expect(tree.remove(9)[0].deleted?.key).toBe(9);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(2);
|
||||
expect(tree.remove(14)[0].deleted?.id).toBe(14);
|
||||
expect(tree.remove(14)[0].deleted?.key).toBe(14);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(1);
|
||||
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
const lastBFSIds = tree.BFS();
|
||||
const lastBFSIds = tree.bfs();
|
||||
expect(lastBFSIds[0]).toBe(12);
|
||||
expect(lastBFSIds[1]).toBe(2);
|
||||
expect(lastBFSIds[2]).toBe(16);
|
||||
|
||||
const lastBFSNodes = tree.BFS('node');
|
||||
expect(lastBFSNodes[0].id).toBe(12);
|
||||
expect(lastBFSNodes[1].id).toBe(2);
|
||||
expect(lastBFSNodes[2].id).toBe(16);
|
||||
const lastBFSNodes = tree.bfs('node');
|
||||
expect(lastBFSNodes[0].key).toBe(12);
|
||||
expect(lastBFSNodes[1].key).toBe(2);
|
||||
expect(lastBFSNodes[2].key).toBe(16);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ describe('Individual package BST operations test', () => {
|
|||
bst.addMany(idsOrVals, idsOrVals);
|
||||
expect(bst.root).toBeInstanceOf(BSTNode);
|
||||
|
||||
if (bst.root) expect(bst.root.id).toBe(11);
|
||||
if (bst.root) expect(bst.root.key).toBe(11);
|
||||
|
||||
expect(bst.size).toBe(16);
|
||||
|
||||
|
@ -21,17 +21,17 @@ describe('Individual package BST operations test', () => {
|
|||
expect(node6 && bst.getDepth(6)).toBe(3);
|
||||
|
||||
const nodeId10 = bst.get(10);
|
||||
expect(nodeId10?.id).toBe(10);
|
||||
expect(nodeId10?.key).toBe(10);
|
||||
|
||||
const nodeVal9 = bst.get(9, 'val');
|
||||
expect(nodeVal9?.id).toBe(9);
|
||||
expect(nodeVal9?.key).toBe(9);
|
||||
|
||||
const leftMost = bst.getLeftMost();
|
||||
expect(leftMost?.id).toBe(1);
|
||||
expect(leftMost?.key).toBe(1);
|
||||
|
||||
const node15 = bst.get(15);
|
||||
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
|
||||
expect(minNodeBySpecificNode?.id).toBe(12);
|
||||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
const subTreeSum = node15 && bst.subTreeSum(15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
@ -44,23 +44,23 @@ describe('Individual package BST operations test', () => {
|
|||
const node11 = bst.get(11);
|
||||
expect(node11).toBeInstanceOf(BSTNode);
|
||||
|
||||
const dfsInorderNodes = bst.DFS('in', 'node');
|
||||
expect(dfsInorderNodes[0].id).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
|
||||
const dfsInorderNodes = bst.dfs('in', 'node');
|
||||
expect(dfsInorderNodes[0].key).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
|
||||
|
||||
bst.perfectlyBalance();
|
||||
expect(bst.isPerfectlyBalanced()).toBe(true);
|
||||
|
||||
const bfsNodesAfterBalanced = bst.BFS('node');
|
||||
expect(bfsNodesAfterBalanced[0].id).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
|
||||
const bfsNodesAfterBalanced = bst.bfs('node');
|
||||
expect(bfsNodesAfterBalanced[0].key).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
|
||||
|
||||
const removed11 = bst.remove(11);
|
||||
expect(removed11).toBeInstanceOf(Array);
|
||||
expect(removed11[0]).toBeDefined();
|
||||
expect(removed11[0].deleted).toBeDefined();
|
||||
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -70,7 +70,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed1).toBeInstanceOf(Array);
|
||||
expect(removed1[0]).toBeDefined();
|
||||
expect(removed1[0].deleted).toBeDefined();
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -80,7 +80,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed4).toBeInstanceOf(Array);
|
||||
expect(removed4[0]).toBeDefined();
|
||||
expect(removed4[0].deleted).toBeDefined();
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(4);
|
||||
|
||||
|
@ -88,7 +88,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed10).toBeInstanceOf(Array);
|
||||
expect(removed10[0]).toBeDefined();
|
||||
expect(removed10[0].deleted).toBeDefined();
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(4);
|
||||
|
||||
|
@ -96,7 +96,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed15).toBeInstanceOf(Array);
|
||||
expect(removed15[0]).toBeDefined();
|
||||
expect(removed15[0].deleted).toBeDefined();
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
@ -105,7 +105,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed5).toBeInstanceOf(Array);
|
||||
expect(removed5[0]).toBeDefined();
|
||||
expect(removed5[0].deleted).toBeDefined();
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
@ -114,7 +114,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed13).toBeInstanceOf(Array);
|
||||
expect(removed13[0]).toBeDefined();
|
||||
expect(removed13[0].deleted).toBeDefined();
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -122,7 +122,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed3).toBeInstanceOf(Array);
|
||||
expect(removed3[0]).toBeDefined();
|
||||
expect(removed3[0].deleted).toBeDefined();
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -130,7 +130,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed8).toBeInstanceOf(Array);
|
||||
expect(removed8[0]).toBeDefined();
|
||||
expect(removed8[0].deleted).toBeDefined();
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -138,7 +138,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed6).toBeInstanceOf(Array);
|
||||
expect(removed6[0]).toBeDefined();
|
||||
expect(removed6[0].deleted).toBeDefined();
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
|
||||
expect(bst.remove(6).length).toBe(0);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
@ -147,7 +147,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed7).toBeInstanceOf(Array);
|
||||
expect(removed7[0]).toBeDefined();
|
||||
expect(removed7[0].deleted).toBeDefined();
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -155,7 +155,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed9).toBeInstanceOf(Array);
|
||||
expect(removed9[0]).toBeDefined();
|
||||
expect(removed9[0].deleted).toBeDefined();
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -163,53 +163,53 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed14).toBeInstanceOf(Array);
|
||||
expect(removed14[0]).toBeDefined();
|
||||
expect(removed14[0].deleted).toBeDefined();
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(2);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
|
||||
const bfsIDs = bst.BFS();
|
||||
const bfsIDs = bst.bfs();
|
||||
expect(bfsIDs[0]).toBe(2);
|
||||
expect(bfsIDs[1]).toBe(12);
|
||||
expect(bfsIDs[2]).toBe(16);
|
||||
|
||||
const bfsNodes = bst.BFS('node');
|
||||
expect(bfsNodes[0].id).toBe(2);
|
||||
expect(bfsNodes[1].id).toBe(12);
|
||||
expect(bfsNodes[2].id).toBe(16);
|
||||
const bfsNodes = bst.bfs('node');
|
||||
expect(bfsNodes[0].key).toBe(2);
|
||||
expect(bfsNodes[1].key).toBe(12);
|
||||
expect(bfsNodes[2].key).toBe(16);
|
||||
});
|
||||
|
||||
it('should perform various operations on a Binary Search Tree with object values', () => {
|
||||
const objBST = new BST<BSTNode<{id: number; keyA: number}>>();
|
||||
const objBST = new BST<BSTNode<{key: number; keyA: number}>>();
|
||||
expect(objBST).toBeInstanceOf(BST);
|
||||
objBST.add(11, {id: 11, keyA: 11});
|
||||
objBST.add(3, {id: 3, keyA: 3});
|
||||
objBST.add(11, {key: 11, keyA: 11});
|
||||
objBST.add(3, {key: 3, keyA: 3});
|
||||
const values = [
|
||||
{id: 15, keyA: 15},
|
||||
{id: 1, keyA: 1},
|
||||
{id: 8, keyA: 8},
|
||||
{id: 13, keyA: 13},
|
||||
{id: 16, keyA: 16},
|
||||
{id: 2, keyA: 2},
|
||||
{id: 6, keyA: 6},
|
||||
{id: 9, keyA: 9},
|
||||
{id: 12, keyA: 12},
|
||||
{id: 14, keyA: 14},
|
||||
{id: 4, keyA: 4},
|
||||
{id: 7, keyA: 7},
|
||||
{id: 10, keyA: 10},
|
||||
{id: 5, keyA: 5}
|
||||
{key: 15, keyA: 15},
|
||||
{key: 1, keyA: 1},
|
||||
{key: 8, keyA: 8},
|
||||
{key: 13, keyA: 13},
|
||||
{key: 16, keyA: 16},
|
||||
{key: 2, keyA: 2},
|
||||
{key: 6, keyA: 6},
|
||||
{key: 9, keyA: 9},
|
||||
{key: 12, keyA: 12},
|
||||
{key: 14, keyA: 14},
|
||||
{key: 4, keyA: 4},
|
||||
{key: 7, keyA: 7},
|
||||
{key: 10, keyA: 10},
|
||||
{key: 5, keyA: 5}
|
||||
];
|
||||
|
||||
objBST.addMany(
|
||||
values.map(item => item.id),
|
||||
values.map(item => item.key),
|
||||
values
|
||||
);
|
||||
|
||||
expect(objBST.root).toBeInstanceOf(BSTNode);
|
||||
|
||||
if (objBST.root) expect(objBST.root.id).toBe(11);
|
||||
if (objBST.root) expect(objBST.root.key).toBe(11);
|
||||
|
||||
expect(objBST.has(6)).toBe(true);
|
||||
|
||||
|
@ -217,19 +217,19 @@ describe('Individual package BST operations test', () => {
|
|||
expect(node6 && objBST.getHeight(node6)).toBe(2);
|
||||
expect(node6 && objBST.getDepth(node6)).toBe(3);
|
||||
|
||||
const nodeId10 = objBST.get(10, 'id');
|
||||
expect(nodeId10?.id).toBe(10);
|
||||
const nodeId10 = objBST.get(10, 'key');
|
||||
expect(nodeId10?.key).toBe(10);
|
||||
|
||||
const nodeVal9 = objBST.get(9, 'id');
|
||||
expect(nodeVal9?.id).toBe(9);
|
||||
const nodeVal9 = objBST.get(9, 'key');
|
||||
expect(nodeVal9?.key).toBe(9);
|
||||
|
||||
const leftMost = objBST.getLeftMost();
|
||||
expect(leftMost?.id).toBe(1);
|
||||
expect(leftMost?.key).toBe(1);
|
||||
|
||||
const node15 = objBST.get(15);
|
||||
expect(node15?.val).toEqual({id: 15, keyA: 15});
|
||||
expect(node15?.val).toEqual({key: 15, keyA: 15});
|
||||
const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15);
|
||||
expect(minNodeBySpecificNode?.id).toBe(12);
|
||||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
const subTreeSum = node15 && objBST.subTreeSum(node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
@ -242,23 +242,23 @@ describe('Individual package BST operations test', () => {
|
|||
const node11 = objBST.get(11);
|
||||
expect(node11).toBeInstanceOf(BSTNode);
|
||||
|
||||
const dfsInorderNodes = objBST.DFS('in', 'node');
|
||||
expect(dfsInorderNodes[0].id).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
|
||||
const dfsInorderNodes = objBST.dfs('in', 'node');
|
||||
expect(dfsInorderNodes[0].key).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
|
||||
|
||||
objBST.perfectlyBalance();
|
||||
expect(objBST.isPerfectlyBalanced()).toBe(true);
|
||||
|
||||
const bfsNodesAfterBalanced = objBST.BFS('node');
|
||||
expect(bfsNodesAfterBalanced[0].id).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
|
||||
const bfsNodesAfterBalanced = objBST.bfs('node');
|
||||
expect(bfsNodesAfterBalanced[0].key).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
|
||||
|
||||
const removed11 = objBST.remove(11);
|
||||
expect(removed11).toBeInstanceOf(Array);
|
||||
expect(removed11[0]).toBeDefined();
|
||||
expect(removed11[0].deleted).toBeDefined();
|
||||
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -268,7 +268,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed1).toBeInstanceOf(Array);
|
||||
expect(removed1[0]).toBeDefined();
|
||||
expect(removed1[0].deleted).toBeDefined();
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -278,7 +278,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed4).toBeInstanceOf(Array);
|
||||
expect(removed4[0]).toBeDefined();
|
||||
expect(removed4[0].deleted).toBeDefined();
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(4);
|
||||
|
||||
|
@ -286,7 +286,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed10).toBeInstanceOf(Array);
|
||||
expect(removed10[0]).toBeDefined();
|
||||
expect(removed10[0].deleted).toBeDefined();
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(4);
|
||||
|
||||
|
@ -294,7 +294,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed15).toBeInstanceOf(Array);
|
||||
expect(removed15[0]).toBeDefined();
|
||||
expect(removed15[0].deleted).toBeDefined();
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
@ -303,7 +303,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed5).toBeInstanceOf(Array);
|
||||
expect(removed5[0]).toBeDefined();
|
||||
expect(removed5[0].deleted).toBeDefined();
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
@ -312,7 +312,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed13).toBeInstanceOf(Array);
|
||||
expect(removed13[0]).toBeDefined();
|
||||
expect(removed13[0].deleted).toBeDefined();
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -320,7 +320,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed3).toBeInstanceOf(Array);
|
||||
expect(removed3[0]).toBeDefined();
|
||||
expect(removed3[0].deleted).toBeDefined();
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -328,7 +328,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed8).toBeInstanceOf(Array);
|
||||
expect(removed8[0]).toBeDefined();
|
||||
expect(removed8[0].deleted).toBeDefined();
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -336,7 +336,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed6).toBeInstanceOf(Array);
|
||||
expect(removed6[0]).toBeDefined();
|
||||
expect(removed6[0].deleted).toBeDefined();
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
|
||||
expect(objBST.remove(6).length).toBe(0);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
@ -345,7 +345,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed7).toBeInstanceOf(Array);
|
||||
expect(removed7[0]).toBeDefined();
|
||||
expect(removed7[0].deleted).toBeDefined();
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -353,7 +353,7 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed9).toBeInstanceOf(Array);
|
||||
expect(removed9[0]).toBeDefined();
|
||||
expect(removed9[0].deleted).toBeDefined();
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -361,20 +361,20 @@ describe('Individual package BST operations test', () => {
|
|||
expect(removed14).toBeInstanceOf(Array);
|
||||
expect(removed14[0]).toBeDefined();
|
||||
expect(removed14[0].deleted).toBeDefined();
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(2);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
|
||||
const bfsIDs = objBST.BFS();
|
||||
const bfsIDs = objBST.bfs();
|
||||
expect(bfsIDs[0]).toBe(2);
|
||||
expect(bfsIDs[1]).toBe(12);
|
||||
expect(bfsIDs[2]).toBe(16);
|
||||
|
||||
const bfsNodes = objBST.BFS('node');
|
||||
expect(bfsNodes[0].id).toBe(2);
|
||||
expect(bfsNodes[1].id).toBe(12);
|
||||
expect(bfsNodes[2].id).toBe(16);
|
||||
const bfsNodes = objBST.bfs('node');
|
||||
expect(bfsNodes[0].key).toBe(2);
|
||||
expect(bfsNodes[1].key).toBe(12);
|
||||
expect(bfsNodes[2].key).toBe(16);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,15 +12,15 @@ describe('AVLTree operations', () => {
|
|||
expect(node6 && tree.getHeight(node6)).toBe(3);
|
||||
expect(node6 && tree.getDepth(node6)).toBe(1);
|
||||
|
||||
const getNodeById = tree.get(10, 'id');
|
||||
expect(getNodeById?.id).toBe(10);
|
||||
const getNodeById = tree.get(10, 'key');
|
||||
expect(getNodeById?.key).toBe(10);
|
||||
|
||||
const getMinNodeByRoot = tree.getLeftMost();
|
||||
expect(getMinNodeByRoot?.id).toBe(1);
|
||||
expect(getMinNodeByRoot?.key).toBe(1);
|
||||
|
||||
const node15 = tree.get(15);
|
||||
const getMinNodeBySpecificNode = node15 && tree.getLeftMost(node15);
|
||||
expect(getMinNodeBySpecificNode?.id).toBe(12);
|
||||
expect(getMinNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
const subTreeSum = node15 && tree.subTreeSum(node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
@ -31,78 +31,78 @@ describe('AVLTree operations', () => {
|
|||
// node15 has type problem. After the uniform design, the generics of containers (DirectedGraph, BST) are based on the type of value. However, this design has a drawback: when I attempt to inherit from the Vertex or BSTNode classes, the types of the results obtained by all methods are those of the parent class.
|
||||
expect(node15?.val).toBe(15);
|
||||
|
||||
const dfs = tree.DFS('in', 'node');
|
||||
expect(dfs[0].id).toBe(1);
|
||||
expect(dfs[dfs.length - 1].id).toBe(16);
|
||||
const dfs = tree.dfs('in', 'node');
|
||||
expect(dfs[0].key).toBe(1);
|
||||
expect(dfs[dfs.length - 1].key).toBe(16);
|
||||
|
||||
tree.perfectlyBalance();
|
||||
const bfs = tree.BFS('node');
|
||||
const bfs = tree.bfs('node');
|
||||
expect(tree.isPerfectlyBalanced()).toBe(true);
|
||||
expect(bfs[0].id).toBe(8);
|
||||
expect(bfs[bfs.length - 1].id).toBe(16);
|
||||
expect(bfs[0].key).toBe(8);
|
||||
expect(bfs[bfs.length - 1].key).toBe(16);
|
||||
|
||||
expect(tree.remove(11)[0].deleted?.id).toBe(11);
|
||||
expect(tree.remove(11)[0].deleted?.key).toBe(11);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(node15 && tree.getHeight(node15)).toBe(2);
|
||||
|
||||
expect(tree.remove(1)[0].deleted?.id).toBe(1);
|
||||
expect(tree.remove(1)[0].deleted?.key).toBe(1);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(4);
|
||||
|
||||
expect(tree.remove(4)[0].deleted?.id).toBe(4);
|
||||
expect(tree.remove(4)[0].deleted?.key).toBe(4);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(4);
|
||||
|
||||
expect(tree.remove(10)[0].deleted?.id).toBe(10);
|
||||
expect(tree.remove(10)[0].deleted?.key).toBe(10);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(15)[0].deleted?.id).toBe(15);
|
||||
expect(tree.remove(15)[0].deleted?.key).toBe(15);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(5)[0].deleted?.id).toBe(5);
|
||||
expect(tree.remove(5)[0].deleted?.key).toBe(5);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(13)[0].deleted?.id).toBe(13);
|
||||
expect(tree.remove(13)[0].deleted?.key).toBe(13);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(3)[0].deleted?.id).toBe(3);
|
||||
expect(tree.remove(3)[0].deleted?.key).toBe(3);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(8)[0].deleted?.id).toBe(8);
|
||||
expect(tree.remove(8)[0].deleted?.key).toBe(8);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(3);
|
||||
|
||||
expect(tree.remove(6)[0].deleted?.id).toBe(6);
|
||||
expect(tree.remove(6)[0].deleted?.key).toBe(6);
|
||||
expect(tree.remove(6).length).toBe(0);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(2);
|
||||
|
||||
expect(tree.remove(7)[0].deleted?.id).toBe(7);
|
||||
expect(tree.remove(7)[0].deleted?.key).toBe(7);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(2);
|
||||
|
||||
expect(tree.remove(9)[0].deleted?.id).toBe(9);
|
||||
expect(tree.remove(9)[0].deleted?.key).toBe(9);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(2);
|
||||
expect(tree.remove(14)[0].deleted?.id).toBe(14);
|
||||
expect(tree.remove(14)[0].deleted?.key).toBe(14);
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
expect(tree.getHeight()).toBe(1);
|
||||
|
||||
expect(tree.isAVLBalanced()).toBe(true);
|
||||
const lastBFSIds = tree.BFS();
|
||||
const lastBFSIds = tree.bfs();
|
||||
expect(lastBFSIds[0]).toBe(12);
|
||||
expect(lastBFSIds[1]).toBe(2);
|
||||
expect(lastBFSIds[2]).toBe(16);
|
||||
|
||||
const lastBFSNodes = tree.BFS('node');
|
||||
expect(lastBFSNodes[0].id).toBe(12);
|
||||
expect(lastBFSNodes[1].id).toBe(2);
|
||||
expect(lastBFSNodes[2].id).toBe(16);
|
||||
const lastBFSNodes = tree.bfs('node');
|
||||
expect(lastBFSNodes[0].key).toBe(12);
|
||||
expect(lastBFSNodes[1].key).toBe(2);
|
||||
expect(lastBFSNodes[2].key).toBe(16);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -8,10 +8,10 @@ describe('BinaryTreeNode', () => {
|
|||
|
||||
it('should set and get the ID correctly', () => {
|
||||
const node = new BinaryTreeNode<number>(1);
|
||||
expect(node.id).toBe(1);
|
||||
expect(node.key).toBe(1);
|
||||
|
||||
node.id = 2;
|
||||
expect(node.id).toBe(2);
|
||||
node.key = 2;
|
||||
expect(node.key).toBe(2);
|
||||
});
|
||||
|
||||
it('should set and get the value correctly', () => {
|
||||
|
@ -52,14 +52,6 @@ describe('BinaryTreeNode', () => {
|
|||
expect(node1.left).toBe(node2);
|
||||
});
|
||||
|
||||
it('should set and get the height correctly', () => {
|
||||
const node = new BinaryTreeNode<number>(1);
|
||||
expect(node.height).toBe(0);
|
||||
|
||||
node.height = 3;
|
||||
expect(node.height).toBe(3);
|
||||
});
|
||||
|
||||
it('should determine family position correctly', () => {
|
||||
const root = new BinaryTreeNode<number>(1);
|
||||
const leftChild = new BinaryTreeNode<number>(2);
|
||||
|
@ -113,6 +105,19 @@ describe('BinaryTree', () => {
|
|||
expect(binaryTree.has(4)).toBe(false);
|
||||
});
|
||||
|
||||
test('should getDepth return correct depth', () => {
|
||||
binaryTree.add(1);
|
||||
expect(binaryTree.getDepth(1)).toBe(0);
|
||||
binaryTree.add(2);
|
||||
expect(binaryTree.getDepth(2)).toBe(1);
|
||||
binaryTree.add(3);
|
||||
expect(binaryTree.getDepth(3, 1)).toBe(1);
|
||||
binaryTree.add(4);
|
||||
expect(binaryTree.getDepth(4, 1)).toBe(2);
|
||||
expect(binaryTree.getDepth(4)).toBe(2);
|
||||
expect(binaryTree.getDepth(4, 2)).toBe(1);
|
||||
});
|
||||
|
||||
test('should traverse in-order', () => {
|
||||
binaryTree.add(4);
|
||||
binaryTree.add(2);
|
||||
|
@ -122,7 +127,7 @@ describe('BinaryTree', () => {
|
|||
binaryTree.add(5);
|
||||
binaryTree.add(7);
|
||||
|
||||
const inOrder = binaryTree.DFS('in');
|
||||
const inOrder = binaryTree.dfs('in');
|
||||
|
||||
expect(inOrder).toEqual([1, 2, 3, 4, 5, 6, 7]);
|
||||
});
|
||||
|
|
|
@ -10,7 +10,7 @@ describe('BST operations test', () => {
|
|||
bst.addMany(idsAndValues, idsAndValues);
|
||||
expect(bst.root).toBeInstanceOf(BSTNode);
|
||||
|
||||
if (bst.root) expect(bst.root.id).toBe(11);
|
||||
if (bst.root) expect(bst.root.key).toBe(11);
|
||||
|
||||
expect(bst.size).toBe(16);
|
||||
|
||||
|
@ -21,17 +21,17 @@ describe('BST operations test', () => {
|
|||
expect(node6 && bst.getDepth(6)).toBe(3);
|
||||
|
||||
const nodeId10 = bst.get(10);
|
||||
expect(nodeId10?.id).toBe(10);
|
||||
expect(nodeId10?.key).toBe(10);
|
||||
|
||||
const nodeVal9 = bst.get(9, 'val');
|
||||
expect(nodeVal9?.id).toBe(9);
|
||||
expect(nodeVal9?.key).toBe(9);
|
||||
|
||||
const leftMost = bst.getLeftMost();
|
||||
expect(leftMost?.id).toBe(1);
|
||||
expect(leftMost?.key).toBe(1);
|
||||
|
||||
const node15 = bst.get(15);
|
||||
const minNodeBySpecificNode = node15 && bst.getLeftMost(node15);
|
||||
expect(minNodeBySpecificNode?.id).toBe(12);
|
||||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
const subTreeSum = node15 && bst.subTreeSum(15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
@ -44,23 +44,23 @@ describe('BST operations test', () => {
|
|||
const node11 = bst.get(11);
|
||||
expect(node11).toBeInstanceOf(BSTNode);
|
||||
|
||||
const dfsInorderNodes = bst.DFS('in', 'node');
|
||||
expect(dfsInorderNodes[0].id).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
|
||||
const dfsInorderNodes = bst.dfs('in', 'node');
|
||||
expect(dfsInorderNodes[0].key).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
|
||||
|
||||
bst.perfectlyBalance();
|
||||
expect(bst.isPerfectlyBalanced()).toBe(true);
|
||||
|
||||
const bfsNodesAfterBalanced = bst.BFS('node');
|
||||
expect(bfsNodesAfterBalanced[0].id).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
|
||||
const bfsNodesAfterBalanced = bst.bfs('node');
|
||||
expect(bfsNodesAfterBalanced[0].key).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
|
||||
|
||||
const removed11 = bst.remove(11);
|
||||
expect(removed11).toBeInstanceOf(Array);
|
||||
expect(removed11[0]).toBeDefined();
|
||||
expect(removed11[0].deleted).toBeDefined();
|
||||
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -70,7 +70,7 @@ describe('BST operations test', () => {
|
|||
expect(removed1).toBeInstanceOf(Array);
|
||||
expect(removed1[0]).toBeDefined();
|
||||
expect(removed1[0].deleted).toBeDefined();
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -80,7 +80,7 @@ describe('BST operations test', () => {
|
|||
expect(removed4).toBeInstanceOf(Array);
|
||||
expect(removed4[0]).toBeDefined();
|
||||
expect(removed4[0].deleted).toBeDefined();
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(4);
|
||||
|
||||
|
@ -88,7 +88,7 @@ describe('BST operations test', () => {
|
|||
expect(removed10).toBeInstanceOf(Array);
|
||||
expect(removed10[0]).toBeDefined();
|
||||
expect(removed10[0].deleted).toBeDefined();
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(4);
|
||||
|
||||
|
@ -96,7 +96,7 @@ describe('BST operations test', () => {
|
|||
expect(removed15).toBeInstanceOf(Array);
|
||||
expect(removed15[0]).toBeDefined();
|
||||
expect(removed15[0].deleted).toBeDefined();
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
@ -105,7 +105,7 @@ describe('BST operations test', () => {
|
|||
expect(removed5).toBeInstanceOf(Array);
|
||||
expect(removed5[0]).toBeDefined();
|
||||
expect(removed5[0].deleted).toBeDefined();
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
@ -114,7 +114,7 @@ describe('BST operations test', () => {
|
|||
expect(removed13).toBeInstanceOf(Array);
|
||||
expect(removed13[0]).toBeDefined();
|
||||
expect(removed13[0].deleted).toBeDefined();
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -122,7 +122,7 @@ describe('BST operations test', () => {
|
|||
expect(removed3).toBeInstanceOf(Array);
|
||||
expect(removed3[0]).toBeDefined();
|
||||
expect(removed3[0].deleted).toBeDefined();
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -130,7 +130,7 @@ describe('BST operations test', () => {
|
|||
expect(removed8).toBeInstanceOf(Array);
|
||||
expect(removed8[0]).toBeDefined();
|
||||
expect(removed8[0].deleted).toBeDefined();
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -138,7 +138,7 @@ describe('BST operations test', () => {
|
|||
expect(removed6).toBeInstanceOf(Array);
|
||||
expect(removed6[0]).toBeDefined();
|
||||
expect(removed6[0].deleted).toBeDefined();
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
|
||||
expect(bst.remove(6).length).toBe(0);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
@ -147,7 +147,7 @@ describe('BST operations test', () => {
|
|||
expect(removed7).toBeInstanceOf(Array);
|
||||
expect(removed7[0]).toBeDefined();
|
||||
expect(removed7[0].deleted).toBeDefined();
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -155,7 +155,7 @@ describe('BST operations test', () => {
|
|||
expect(removed9).toBeInstanceOf(Array);
|
||||
expect(removed9[0]).toBeDefined();
|
||||
expect(removed9[0].deleted).toBeDefined();
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(3);
|
||||
|
||||
|
@ -163,53 +163,53 @@ describe('BST operations test', () => {
|
|||
expect(removed14).toBeInstanceOf(Array);
|
||||
expect(removed14[0]).toBeDefined();
|
||||
expect(removed14[0].deleted).toBeDefined();
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
expect(bst.getHeight()).toBe(2);
|
||||
|
||||
expect(bst.isAVLBalanced()).toBe(false);
|
||||
|
||||
const bfsIDs = bst.BFS();
|
||||
const bfsIDs = bst.bfs();
|
||||
expect(bfsIDs[0]).toBe(2);
|
||||
expect(bfsIDs[1]).toBe(12);
|
||||
expect(bfsIDs[2]).toBe(16);
|
||||
|
||||
const bfsNodes = bst.BFS('node');
|
||||
expect(bfsNodes[0].id).toBe(2);
|
||||
expect(bfsNodes[1].id).toBe(12);
|
||||
expect(bfsNodes[2].id).toBe(16);
|
||||
const bfsNodes = bst.bfs('node');
|
||||
expect(bfsNodes[0].key).toBe(2);
|
||||
expect(bfsNodes[1].key).toBe(12);
|
||||
expect(bfsNodes[2].key).toBe(16);
|
||||
});
|
||||
|
||||
it('should perform various operations on a Binary Search Tree with object values', () => {
|
||||
const objBST = new BST<BSTNode<{id: number; keyA: number}>>();
|
||||
const objBST = new BST<BSTNode<{key: number; keyA: number}>>();
|
||||
expect(objBST).toBeInstanceOf(BST);
|
||||
objBST.add(11, {id: 11, keyA: 11});
|
||||
objBST.add(3, {id: 3, keyA: 3});
|
||||
objBST.add(11, {key: 11, keyA: 11});
|
||||
objBST.add(3, {key: 3, keyA: 3});
|
||||
const values = [
|
||||
{id: 15, keyA: 15},
|
||||
{id: 1, keyA: 1},
|
||||
{id: 8, keyA: 8},
|
||||
{id: 13, keyA: 13},
|
||||
{id: 16, keyA: 16},
|
||||
{id: 2, keyA: 2},
|
||||
{id: 6, keyA: 6},
|
||||
{id: 9, keyA: 9},
|
||||
{id: 12, keyA: 12},
|
||||
{id: 14, keyA: 14},
|
||||
{id: 4, keyA: 4},
|
||||
{id: 7, keyA: 7},
|
||||
{id: 10, keyA: 10},
|
||||
{id: 5, keyA: 5}
|
||||
{key: 15, keyA: 15},
|
||||
{key: 1, keyA: 1},
|
||||
{key: 8, keyA: 8},
|
||||
{key: 13, keyA: 13},
|
||||
{key: 16, keyA: 16},
|
||||
{key: 2, keyA: 2},
|
||||
{key: 6, keyA: 6},
|
||||
{key: 9, keyA: 9},
|
||||
{key: 12, keyA: 12},
|
||||
{key: 14, keyA: 14},
|
||||
{key: 4, keyA: 4},
|
||||
{key: 7, keyA: 7},
|
||||
{key: 10, keyA: 10},
|
||||
{key: 5, keyA: 5}
|
||||
];
|
||||
|
||||
objBST.addMany(
|
||||
values.map(item => item.id),
|
||||
values.map(item => item.key),
|
||||
values
|
||||
);
|
||||
|
||||
expect(objBST.root).toBeInstanceOf(BSTNode);
|
||||
|
||||
if (objBST.root) expect(objBST.root.id).toBe(11);
|
||||
if (objBST.root) expect(objBST.root.key).toBe(11);
|
||||
|
||||
expect(objBST.has(6)).toBe(true);
|
||||
|
||||
|
@ -217,19 +217,19 @@ describe('BST operations test', () => {
|
|||
expect(node6 && objBST.getHeight(node6)).toBe(2);
|
||||
expect(node6 && objBST.getDepth(node6)).toBe(3);
|
||||
|
||||
const nodeId10 = objBST.get(10, 'id');
|
||||
expect(nodeId10?.id).toBe(10);
|
||||
const nodeId10 = objBST.get(10, 'key');
|
||||
expect(nodeId10?.key).toBe(10);
|
||||
|
||||
const nodeVal9 = objBST.get(9, 'id');
|
||||
expect(nodeVal9?.id).toBe(9);
|
||||
const nodeVal9 = objBST.get(9, 'key');
|
||||
expect(nodeVal9?.key).toBe(9);
|
||||
|
||||
const leftMost = objBST.getLeftMost();
|
||||
expect(leftMost?.id).toBe(1);
|
||||
expect(leftMost?.key).toBe(1);
|
||||
|
||||
const node15 = objBST.get(15);
|
||||
expect(node15?.val).toEqual({id: 15, keyA: 15});
|
||||
expect(node15?.val).toEqual({key: 15, keyA: 15});
|
||||
const minNodeBySpecificNode = node15 && objBST.getLeftMost(node15);
|
||||
expect(minNodeBySpecificNode?.id).toBe(12);
|
||||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
const subTreeSum = node15 && objBST.subTreeSum(node15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
@ -242,23 +242,23 @@ describe('BST operations test', () => {
|
|||
const node11 = objBST.get(11);
|
||||
expect(node11).toBeInstanceOf(BSTNode);
|
||||
|
||||
const dfsInorderNodes = objBST.DFS('in', 'node');
|
||||
expect(dfsInorderNodes[0].id).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
|
||||
const dfsInorderNodes = objBST.dfs('in', 'node');
|
||||
expect(dfsInorderNodes[0].key).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
|
||||
|
||||
objBST.perfectlyBalance();
|
||||
expect(objBST.isPerfectlyBalanced()).toBe(true);
|
||||
|
||||
const bfsNodesAfterBalanced = objBST.BFS('node');
|
||||
expect(bfsNodesAfterBalanced[0].id).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
|
||||
const bfsNodesAfterBalanced = objBST.bfs('node');
|
||||
expect(bfsNodesAfterBalanced[0].key).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
|
||||
|
||||
const removed11 = objBST.remove(11);
|
||||
expect(removed11).toBeInstanceOf(Array);
|
||||
expect(removed11[0]).toBeDefined();
|
||||
expect(removed11[0].deleted).toBeDefined();
|
||||
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -268,7 +268,7 @@ describe('BST operations test', () => {
|
|||
expect(removed1).toBeInstanceOf(Array);
|
||||
expect(removed1[0]).toBeDefined();
|
||||
expect(removed1[0].deleted).toBeDefined();
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -278,7 +278,7 @@ describe('BST operations test', () => {
|
|||
expect(removed4).toBeInstanceOf(Array);
|
||||
expect(removed4[0]).toBeDefined();
|
||||
expect(removed4[0].deleted).toBeDefined();
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(4);
|
||||
|
||||
|
@ -286,7 +286,7 @@ describe('BST operations test', () => {
|
|||
expect(removed10).toBeInstanceOf(Array);
|
||||
expect(removed10[0]).toBeDefined();
|
||||
expect(removed10[0].deleted).toBeDefined();
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(4);
|
||||
|
||||
|
@ -294,7 +294,7 @@ describe('BST operations test', () => {
|
|||
expect(removed15).toBeInstanceOf(Array);
|
||||
expect(removed15[0]).toBeDefined();
|
||||
expect(removed15[0].deleted).toBeDefined();
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
@ -303,7 +303,7 @@ describe('BST operations test', () => {
|
|||
expect(removed5).toBeInstanceOf(Array);
|
||||
expect(removed5[0]).toBeDefined();
|
||||
expect(removed5[0].deleted).toBeDefined();
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
@ -312,7 +312,7 @@ describe('BST operations test', () => {
|
|||
expect(removed13).toBeInstanceOf(Array);
|
||||
expect(removed13[0]).toBeDefined();
|
||||
expect(removed13[0].deleted).toBeDefined();
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -320,7 +320,7 @@ describe('BST operations test', () => {
|
|||
expect(removed3).toBeInstanceOf(Array);
|
||||
expect(removed3[0]).toBeDefined();
|
||||
expect(removed3[0].deleted).toBeDefined();
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -328,7 +328,7 @@ describe('BST operations test', () => {
|
|||
expect(removed8).toBeInstanceOf(Array);
|
||||
expect(removed8[0]).toBeDefined();
|
||||
expect(removed8[0].deleted).toBeDefined();
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
|
||||
expect(objBST.isAVLBalanced()).toBe(true);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -336,7 +336,7 @@ describe('BST operations test', () => {
|
|||
expect(removed6).toBeInstanceOf(Array);
|
||||
expect(removed6[0]).toBeDefined();
|
||||
expect(removed6[0].deleted).toBeDefined();
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
|
||||
expect(objBST.remove(6).length).toBe(0);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
@ -345,7 +345,7 @@ describe('BST operations test', () => {
|
|||
expect(removed7).toBeInstanceOf(Array);
|
||||
expect(removed7[0]).toBeDefined();
|
||||
expect(removed7[0].deleted).toBeDefined();
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -353,7 +353,7 @@ describe('BST operations test', () => {
|
|||
expect(removed9).toBeInstanceOf(Array);
|
||||
expect(removed9[0]).toBeDefined();
|
||||
expect(removed9[0].deleted).toBeDefined();
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(3);
|
||||
|
||||
|
@ -361,20 +361,20 @@ describe('BST operations test', () => {
|
|||
expect(removed14).toBeInstanceOf(Array);
|
||||
expect(removed14[0]).toBeDefined();
|
||||
expect(removed14[0].deleted).toBeDefined();
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
expect(objBST.getHeight()).toBe(2);
|
||||
|
||||
expect(objBST.isAVLBalanced()).toBe(false);
|
||||
|
||||
const bfsIDs = objBST.BFS();
|
||||
const bfsIDs = objBST.bfs();
|
||||
expect(bfsIDs[0]).toBe(2);
|
||||
expect(bfsIDs[1]).toBe(12);
|
||||
expect(bfsIDs[2]).toBe(16);
|
||||
|
||||
const bfsNodes = objBST.BFS('node');
|
||||
expect(bfsNodes[0].id).toBe(2);
|
||||
expect(bfsNodes[1].id).toBe(12);
|
||||
expect(bfsNodes[2].id).toBe(16);
|
||||
const bfsNodes = objBST.bfs('node');
|
||||
expect(bfsNodes[0].key).toBe(2);
|
||||
expect(bfsNodes[1].key).toBe(12);
|
||||
expect(bfsNodes[2].key).toBe(16);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,38 +17,38 @@ describe('Overall BinaryTree Test', () => {
|
|||
expect(bst.getHeight()).toBe(5); // true
|
||||
expect(bst.getDepth(6)).toBe(3); // true
|
||||
const leftMost = bst.getLeftMost();
|
||||
leftMost?.id === 1; // true
|
||||
expect(leftMost?.id).toBe(1);
|
||||
leftMost?.key === 1; // true
|
||||
expect(leftMost?.key).toBe(1);
|
||||
bst.remove(6);
|
||||
bst.get(6); // null
|
||||
expect(bst.get(6)).toBeNull();
|
||||
bst.isAVLBalanced(); // true or false
|
||||
expect(bst.isAVLBalanced()).toBe(true);
|
||||
const bfsIDs = bst.BFS();
|
||||
const bfsIDs = bst.bfs();
|
||||
bfsIDs[0] === 11; // true
|
||||
expect(bfsIDs[0]).toBe(11);
|
||||
|
||||
const objBST = new BST<BSTNode<{id: number; keyA: number}>>();
|
||||
objBST.add(11, {id: 11, keyA: 11});
|
||||
objBST.add(3, {id: 3, keyA: 3});
|
||||
const objBST = new BST<BSTNode<{key: number; keyA: number}>>();
|
||||
objBST.add(11, {key: 11, keyA: 11});
|
||||
objBST.add(3, {key: 3, keyA: 3});
|
||||
|
||||
objBST.addMany(
|
||||
[15, 1, 8, 13, 16, 2, 6, 9, 12, 14, 4, 7, 10, 5],
|
||||
[
|
||||
{id: 15, keyA: 15},
|
||||
{id: 1, keyA: 1},
|
||||
{id: 8, keyA: 8},
|
||||
{id: 13, keyA: 13},
|
||||
{id: 16, keyA: 16},
|
||||
{id: 2, keyA: 2},
|
||||
{id: 6, keyA: 6},
|
||||
{id: 9, keyA: 9},
|
||||
{id: 12, keyA: 12},
|
||||
{id: 14, keyA: 14},
|
||||
{id: 4, keyA: 4},
|
||||
{id: 7, keyA: 7},
|
||||
{id: 10, keyA: 10},
|
||||
{id: 5, keyA: 5}
|
||||
{key: 15, keyA: 15},
|
||||
{key: 1, keyA: 1},
|
||||
{key: 8, keyA: 8},
|
||||
{key: 13, keyA: 13},
|
||||
{key: 16, keyA: 16},
|
||||
{key: 2, keyA: 2},
|
||||
{key: 6, keyA: 6},
|
||||
{key: 9, keyA: 9},
|
||||
{key: 12, keyA: 12},
|
||||
{key: 14, keyA: 14},
|
||||
{key: 4, keyA: 4},
|
||||
{key: 7, keyA: 7},
|
||||
{key: 10, keyA: 10},
|
||||
{key: 5, keyA: 5}
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -11,21 +11,21 @@ describe('TreeMultiset operations test', () => {
|
|||
treeMultiset.addMany(idAndValues, idAndValues);
|
||||
expect(treeMultiset.root instanceof TreeMultisetNode);
|
||||
|
||||
if (treeMultiset.root) expect(treeMultiset.root.id == 11);
|
||||
if (treeMultiset.root) expect(treeMultiset.root.key == 11);
|
||||
|
||||
expect(treeMultiset.size).toBe(16);
|
||||
expect(treeMultiset.count).toBe(18);
|
||||
expect(treeMultiset.BFS('id'));
|
||||
expect(treeMultiset.bfs('key'));
|
||||
|
||||
expect(treeMultiset.has(6));
|
||||
|
||||
expect(treeMultiset.getHeight(6)).toBe(3);
|
||||
expect(treeMultiset.getDepth(6)).toBe(1);
|
||||
const nodeId10 = treeMultiset.get(10);
|
||||
expect(nodeId10?.id).toBe(10);
|
||||
expect(nodeId10?.key).toBe(10);
|
||||
|
||||
const nodeVal9 = treeMultiset.get(9, 'val');
|
||||
expect(nodeVal9?.id).toBe(9);
|
||||
expect(nodeVal9?.key).toBe(9);
|
||||
|
||||
const nodesByCount1 = treeMultiset.getNodesByCount(1);
|
||||
expect(nodesByCount1.length).toBe(14);
|
||||
|
@ -33,11 +33,11 @@ describe('TreeMultiset operations test', () => {
|
|||
const nodesByCount2 = treeMultiset.getNodesByCount(2);
|
||||
expect(nodesByCount2.length).toBe(2);
|
||||
const leftMost = treeMultiset.getLeftMost();
|
||||
expect(leftMost?.id).toBe(1);
|
||||
expect(leftMost?.key).toBe(1);
|
||||
|
||||
const node15 = treeMultiset.get(15);
|
||||
const minNodeBySpecificNode = node15 && treeMultiset.getLeftMost(node15);
|
||||
expect(minNodeBySpecificNode?.id).toBe(12);
|
||||
expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
|
||||
const subTreeSum = node15 && treeMultiset.subTreeSum(15);
|
||||
expect(subTreeSum).toBe(70);
|
||||
|
@ -56,9 +56,9 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(allGreaterNodesAdded);
|
||||
}
|
||||
|
||||
const dfsInorderNodes = treeMultiset.DFS('in', 'node');
|
||||
expect(dfsInorderNodes[0].id).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
|
||||
const dfsInorderNodes = treeMultiset.dfs('in', 'node');
|
||||
expect(dfsInorderNodes[0].key).toBe(1);
|
||||
expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
|
||||
expect(treeMultiset.isPerfectlyBalanced()).toBe(false);
|
||||
|
||||
treeMultiset.perfectlyBalance();
|
||||
|
@ -66,16 +66,16 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(treeMultiset.isPerfectlyBalanced()).toBe(true);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
|
||||
const bfsNodesAfterBalanced = treeMultiset.BFS('node');
|
||||
expect(bfsNodesAfterBalanced[0].id).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
|
||||
const bfsNodesAfterBalanced = treeMultiset.bfs('node');
|
||||
expect(bfsNodesAfterBalanced[0].key).toBe(8);
|
||||
expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
|
||||
|
||||
const removed11 = treeMultiset.remove(11, true);
|
||||
expect(removed11 instanceof Array);
|
||||
expect(removed11[0]);
|
||||
expect(removed11[0].deleted);
|
||||
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
|
||||
if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
|
||||
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -85,7 +85,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed1 instanceof Array);
|
||||
expect(removed1[0]);
|
||||
expect(removed1[0].deleted);
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
|
||||
if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
|
||||
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -95,7 +95,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed4 instanceof Array);
|
||||
expect(removed4[0]);
|
||||
expect(removed4[0].deleted);
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
|
||||
if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
|
||||
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(4);
|
||||
|
@ -104,7 +104,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed10 instanceof Array);
|
||||
expect(removed10[0]);
|
||||
expect(removed10[0].deleted);
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
|
||||
if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
|
||||
expect(treeMultiset.getHeight()).toBe(3);
|
||||
|
@ -113,7 +113,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed15 instanceof Array);
|
||||
expect(removed15[0]);
|
||||
expect(removed15[0].deleted);
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
|
||||
if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
|
||||
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(3);
|
||||
|
@ -122,7 +122,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed5 instanceof Array);
|
||||
expect(removed5[0]);
|
||||
expect(removed5[0].deleted);
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
|
||||
if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
|
||||
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(3);
|
||||
|
@ -131,7 +131,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed13 instanceof Array);
|
||||
expect(removed13[0]);
|
||||
expect(removed13[0].deleted);
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
|
||||
if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(3);
|
||||
|
||||
|
@ -139,7 +139,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed3 instanceof Array);
|
||||
expect(removed3[0]);
|
||||
expect(removed3[0].deleted);
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
|
||||
if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(3);
|
||||
|
||||
|
@ -147,7 +147,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed8 instanceof Array);
|
||||
expect(removed8[0]);
|
||||
expect(removed8[0].deleted);
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
|
||||
if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(3);
|
||||
|
||||
|
@ -155,7 +155,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed6 instanceof Array);
|
||||
expect(removed6[0]);
|
||||
expect(removed6[0].deleted);
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
|
||||
if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
|
||||
expect(treeMultiset.remove(6, true).length).toBe(0);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
|
||||
|
@ -165,7 +165,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed7 instanceof Array);
|
||||
expect(removed7[0]);
|
||||
expect(removed7[0].deleted);
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
|
||||
if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(2);
|
||||
|
||||
|
@ -173,7 +173,7 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed9 instanceof Array);
|
||||
expect(removed9[0]);
|
||||
expect(removed9[0].deleted);
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
|
||||
if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(2);
|
||||
|
||||
|
@ -181,57 +181,57 @@ describe('TreeMultiset operations test', () => {
|
|||
expect(removed14 instanceof Array);
|
||||
expect(removed14[0]);
|
||||
expect(removed14[0].deleted);
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
|
||||
if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
expect(treeMultiset.getHeight()).toBe(1);
|
||||
|
||||
expect(treeMultiset.isAVLBalanced()).toBe(true);
|
||||
|
||||
const bfsIDs = treeMultiset.BFS();
|
||||
const bfsIDs = treeMultiset.bfs();
|
||||
|
||||
expect(bfsIDs[0]).toBe(12);
|
||||
expect(bfsIDs[1]).toBe(2);
|
||||
expect(bfsIDs[2]).toBe(16);
|
||||
|
||||
const bfsNodes = treeMultiset.BFS('node');
|
||||
const bfsNodes = treeMultiset.bfs('node');
|
||||
|
||||
expect(bfsNodes[0].id).toBe(12);
|
||||
expect(bfsNodes[1].id).toBe(2);
|
||||
expect(bfsNodes[2].id).toBe(16);
|
||||
expect(bfsNodes[0].key).toBe(12);
|
||||
expect(bfsNodes[1].key).toBe(2);
|
||||
expect(bfsNodes[2].key).toBe(16);
|
||||
|
||||
expect(treeMultiset.count).toBe(9);
|
||||
});
|
||||
|
||||
it('should perform various operations on a Binary Search Tree with object values', () => {
|
||||
const objTreeMultiset = new TreeMultiset<TreeMultisetNode<{id: number; keyA: number}>>();
|
||||
const objTreeMultiset = new TreeMultiset<TreeMultisetNode<{key: number; keyA: number}>>();
|
||||
expect(objTreeMultiset).toBeInstanceOf(TreeMultiset);
|
||||
objTreeMultiset.add(11, {id: 11, keyA: 11});
|
||||
objTreeMultiset.add(3, {id: 3, keyA: 3});
|
||||
objTreeMultiset.add(11, {key: 11, keyA: 11});
|
||||
objTreeMultiset.add(3, {key: 3, keyA: 3});
|
||||
const values = [
|
||||
{id: 15, keyA: 15},
|
||||
{id: 1, keyA: 1},
|
||||
{id: 8, keyA: 8},
|
||||
{id: 13, keyA: 13},
|
||||
{id: 16, keyA: 16},
|
||||
{id: 2, keyA: 2},
|
||||
{id: 6, keyA: 6},
|
||||
{id: 9, keyA: 9},
|
||||
{id: 12, keyA: 12},
|
||||
{id: 14, keyA: 14},
|
||||
{id: 4, keyA: 4},
|
||||
{id: 7, keyA: 7},
|
||||
{id: 10, keyA: 10},
|
||||
{id: 5, keyA: 5}
|
||||
{key: 15, keyA: 15},
|
||||
{key: 1, keyA: 1},
|
||||
{key: 8, keyA: 8},
|
||||
{key: 13, keyA: 13},
|
||||
{key: 16, keyA: 16},
|
||||
{key: 2, keyA: 2},
|
||||
{key: 6, keyA: 6},
|
||||
{key: 9, keyA: 9},
|
||||
{key: 12, keyA: 12},
|
||||
{key: 14, keyA: 14},
|
||||
{key: 4, keyA: 4},
|
||||
{key: 7, keyA: 7},
|
||||
{key: 10, keyA: 10},
|
||||
{key: 5, keyA: 5}
|
||||
];
|
||||
|
||||
objTreeMultiset.addMany(
|
||||
values.map(item => item.id),
|
||||
values.map(item => item.key),
|
||||
values
|
||||
);
|
||||
|
||||
expect(objTreeMultiset.root).toBeInstanceOf(TreeMultisetNode);
|
||||
|
||||
if (objTreeMultiset.root) expect(objTreeMultiset.root.id).toBe(11);
|
||||
if (objTreeMultiset.root) expect(objTreeMultiset.root.key).toBe(11);
|
||||
|
||||
expect(objTreeMultiset.count).toBe(16);
|
||||
|
||||
|
@ -241,22 +241,22 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(node6 && objTreeMultiset.getHeight(node6)).toBe(2);
|
||||
// expect(node6 && objTreeMultiset.getDepth(node6)).toBe(3);
|
||||
//
|
||||
// const nodeId10 = objTreeMultiset.get(10, 'id');
|
||||
// expect(nodeId10?.id).toBe(10);
|
||||
// const nodeId10 = objTreeMultiset.get(10, 'key');
|
||||
// expect(nodeId10?.key).toBe(10);
|
||||
//
|
||||
// const nodeVal9 = objTreeMultiset.get(9, 'id');
|
||||
// expect(nodeVal9?.id).toBe(9);
|
||||
// const nodeVal9 = objTreeMultiset.get(9, 'key');
|
||||
// expect(nodeVal9?.key).toBe(9);
|
||||
//
|
||||
// const nodesByCount1 = objTreeMultiset.getNodesByCount(1);
|
||||
// expect(nodesByCount1.length).toBe(16);
|
||||
//
|
||||
// const leftMost = objTreeMultiset.getLeftMost();
|
||||
// expect(leftMost?.id).toBe(1);
|
||||
// expect(leftMost?.key).toBe(1);
|
||||
//
|
||||
// const node15 = objTreeMultiset.get(15);
|
||||
// expect(node15?.val).toEqual({id: 15, keyA: 15});
|
||||
// expect(node15?.val).toEqual({key: 15, keyA: 15});
|
||||
// const minNodeBySpecificNode = node15 && objTreeMultiset.getLeftMost(node15);
|
||||
// expect(minNodeBySpecificNode?.id).toBe(12);
|
||||
// expect(minNodeBySpecificNode?.key).toBe(12);
|
||||
//
|
||||
// const subTreeSum = node15 && objTreeMultiset.subTreeSum(node15);
|
||||
// expect(subTreeSum).toBe(70);
|
||||
|
@ -277,23 +277,23 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(allGreaterNodesAdded).toBeDefined();
|
||||
// }
|
||||
//
|
||||
// const dfsInorderNodes = objTreeMultiset.DFS('in', 'node');
|
||||
// expect(dfsInorderNodes[0].id).toBe(1);
|
||||
// expect(dfsInorderNodes[dfsInorderNodes.length - 1].id).toBe(16);
|
||||
// const dfsInorderNodes = objTreeMultiset.dfs('in', 'node');
|
||||
// expect(dfsInorderNodes[0].key).toBe(1);
|
||||
// expect(dfsInorderNodes[dfsInorderNodes.length - 1].key).toBe(16);
|
||||
//
|
||||
// objTreeMultiset.perfectlyBalance();
|
||||
// expect(objTreeMultiset.isPerfectlyBalanced()).toBe(true);
|
||||
//
|
||||
// const bfsNodesAfterBalanced = objTreeMultiset.BFS('node');
|
||||
// expect(bfsNodesAfterBalanced[0].id).toBe(8);
|
||||
// expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].id).toBe(16);
|
||||
// const bfsNodesAfterBalanced = objTreeMultiset.bfs('node');
|
||||
// expect(bfsNodesAfterBalanced[0].key).toBe(8);
|
||||
// expect(bfsNodesAfterBalanced[bfsNodesAfterBalanced.length - 1].key).toBe(16);
|
||||
//
|
||||
// const removed11 = objTreeMultiset.remove(11, true);
|
||||
// expect(removed11).toBeInstanceOf(Array);
|
||||
// expect(removed11[0]).toBeDefined();
|
||||
// expect(removed11[0].deleted).toBeDefined();
|
||||
//
|
||||
// if (removed11[0].deleted) expect(removed11[0].deleted.id).toBe(11);
|
||||
// if (removed11[0].deleted) expect(removed11[0].deleted.key).toBe(11);
|
||||
//
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
|
||||
//
|
||||
|
@ -303,7 +303,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed1).toBeInstanceOf(Array);
|
||||
// expect(removed1[0]).toBeDefined();
|
||||
// expect(removed1[0].deleted).toBeDefined();
|
||||
// if (removed1[0].deleted) expect(removed1[0].deleted.id).toBe(1);
|
||||
// if (removed1[0].deleted) expect(removed1[0].deleted.key).toBe(1);
|
||||
//
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
|
||||
//
|
||||
|
@ -313,7 +313,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed4).toBeInstanceOf(Array);
|
||||
// expect(removed4[0]).toBeDefined();
|
||||
// expect(removed4[0].deleted).toBeDefined();
|
||||
// if (removed4[0].deleted) expect(removed4[0].deleted.id).toBe(4);
|
||||
// if (removed4[0].deleted) expect(removed4[0].deleted.key).toBe(4);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(4);
|
||||
//
|
||||
|
@ -321,7 +321,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed10).toBeInstanceOf(Array);
|
||||
// expect(removed10[0]).toBeDefined();
|
||||
// expect(removed10[0].deleted).toBeDefined();
|
||||
// if (removed10[0].deleted) expect(removed10[0].deleted.id).toBe(10);
|
||||
// if (removed10[0].deleted) expect(removed10[0].deleted.key).toBe(10);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(4);
|
||||
//
|
||||
|
@ -329,7 +329,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed15).toBeInstanceOf(Array);
|
||||
// expect(removed15[0]).toBeDefined();
|
||||
// expect(removed15[0].deleted).toBeDefined();
|
||||
// if (removed15[0].deleted) expect(removed15[0].deleted.id).toBe(15);
|
||||
// if (removed15[0].deleted) expect(removed15[0].deleted.key).toBe(15);
|
||||
//
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(3);
|
||||
|
@ -338,7 +338,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed5).toBeInstanceOf(Array);
|
||||
// expect(removed5[0]).toBeDefined();
|
||||
// expect(removed5[0].deleted).toBeDefined();
|
||||
// if (removed5[0].deleted) expect(removed5[0].deleted.id).toBe(5);
|
||||
// if (removed5[0].deleted) expect(removed5[0].deleted.key).toBe(5);
|
||||
//
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(3);
|
||||
|
@ -347,7 +347,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed13).toBeInstanceOf(Array);
|
||||
// expect(removed13[0]).toBeDefined();
|
||||
// expect(removed13[0].deleted).toBeDefined();
|
||||
// if (removed13[0].deleted) expect(removed13[0].deleted.id).toBe(13);
|
||||
// if (removed13[0].deleted) expect(removed13[0].deleted.key).toBe(13);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(3);
|
||||
//
|
||||
|
@ -355,7 +355,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed3).toBeInstanceOf(Array);
|
||||
// expect(removed3[0]).toBeDefined();
|
||||
// expect(removed3[0].deleted).toBeDefined();
|
||||
// if (removed3[0].deleted) expect(removed3[0].deleted.id).toBe(3);
|
||||
// if (removed3[0].deleted) expect(removed3[0].deleted.key).toBe(3);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(3);
|
||||
//
|
||||
|
@ -363,7 +363,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed8).toBeInstanceOf(Array);
|
||||
// expect(removed8[0]).toBeDefined();
|
||||
// expect(removed8[0].deleted).toBeDefined();
|
||||
// if (removed8[0].deleted) expect(removed8[0].deleted.id).toBe(8);
|
||||
// if (removed8[0].deleted) expect(removed8[0].deleted.key).toBe(8);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(true);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(3);
|
||||
//
|
||||
|
@ -371,7 +371,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed6).toBeInstanceOf(Array);
|
||||
// expect(removed6[0]).toBeDefined();
|
||||
// expect(removed6[0].deleted).toBeDefined();
|
||||
// if (removed6[0].deleted) expect(removed6[0].deleted.id).toBe(6);
|
||||
// if (removed6[0].deleted) expect(removed6[0].deleted.key).toBe(6);
|
||||
// expect(objTreeMultiset.remove(6, true).length).toBe(0);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(3);
|
||||
|
@ -380,7 +380,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed7).toBeInstanceOf(Array);
|
||||
// expect(removed7[0]).toBeDefined();
|
||||
// expect(removed7[0].deleted).toBeDefined();
|
||||
// if (removed7[0].deleted) expect(removed7[0].deleted.id).toBe(7);
|
||||
// if (removed7[0].deleted) expect(removed7[0].deleted.key).toBe(7);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(3);
|
||||
//
|
||||
|
@ -388,7 +388,7 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed9).toBeInstanceOf(Array);
|
||||
// expect(removed9[0]).toBeDefined();
|
||||
// expect(removed9[0].deleted).toBeDefined();
|
||||
// if (removed9[0].deleted) expect(removed9[0].deleted.id).toBe(9);
|
||||
// if (removed9[0].deleted) expect(removed9[0].deleted.key).toBe(9);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(3);
|
||||
//
|
||||
|
@ -396,22 +396,22 @@ describe('TreeMultiset operations test', () => {
|
|||
// expect(removed14).toBeInstanceOf(Array);
|
||||
// expect(removed14[0]).toBeDefined();
|
||||
// expect(removed14[0].deleted).toBeDefined();
|
||||
// if (removed14[0].deleted) expect(removed14[0].deleted.id).toBe(14);
|
||||
// if (removed14[0].deleted) expect(removed14[0].deleted.key).toBe(14);
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
|
||||
// expect(objTreeMultiset.getHeight()).toBe(2);
|
||||
//
|
||||
//
|
||||
// expect(objTreeMultiset.isAVLBalanced()).toBe(false);
|
||||
//
|
||||
// const bfsIDs = objTreeMultiset.BFS();
|
||||
// const bfsIDs = objTreeMultiset.bfs();
|
||||
// expect(bfsIDs[0]).toBe(2);
|
||||
// expect(bfsIDs[1]).toBe(12);
|
||||
// expect(bfsIDs[2]).toBe(16);
|
||||
//
|
||||
// const bfsNodes = objTreeMultiset.BFS('node');
|
||||
// expect(bfsNodes[0].id).toBe(2);
|
||||
// expect(bfsNodes[1].id).toBe(12);
|
||||
// expect(bfsNodes[2].id).toBe(16);
|
||||
// const bfsNodes = objTreeMultiset.bfs('node');
|
||||
// expect(bfsNodes[0].key).toBe(2);
|
||||
// expect(bfsNodes[1].key).toBe(12);
|
||||
// expect(bfsNodes[2].key).toBe(16);
|
||||
//
|
||||
// expect(objTreeMultiset.count).toBe(5);
|
||||
});
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import {DirectedEdge, DirectedGraph, DirectedVertex, VertexId} from '../../../../src';
|
||||
import {DirectedEdge, DirectedGraph, DirectedVertex, VertexKey} from '../../../../src';
|
||||
|
||||
describe('DirectedGraph Operation Test', () => {
|
||||
let graph: DirectedGraph;
|
||||
|
@ -63,8 +63,8 @@ describe('DirectedGraph Operation Test', () => {
|
|||
});
|
||||
|
||||
class MyVertex<V extends string> extends DirectedVertex<V> {
|
||||
constructor(id: VertexId, val?: V) {
|
||||
super(id, val);
|
||||
constructor(key: VertexKey, val?: V) {
|
||||
super(key, val);
|
||||
this._data = val;
|
||||
}
|
||||
|
||||
|
@ -80,7 +80,7 @@ class MyVertex<V extends string> extends DirectedVertex<V> {
|
|||
}
|
||||
|
||||
class MyEdge<E extends string> extends DirectedEdge<E> {
|
||||
constructor(v1: VertexId, v2: VertexId, weight?: number, val?: E) {
|
||||
constructor(v1: VertexKey, v2: VertexKey, weight?: number, val?: E) {
|
||||
super(v1, v2, weight, val);
|
||||
this._data = val;
|
||||
}
|
||||
|
@ -97,11 +97,11 @@ class MyEdge<E extends string> extends DirectedEdge<E> {
|
|||
}
|
||||
|
||||
class MyDirectedGraph<V extends MyVertex<string>, E extends MyEdge<string>> extends DirectedGraph<V, E> {
|
||||
createVertex(id: VertexId, val: V['val']): V {
|
||||
return new MyVertex(id, val) as V;
|
||||
createVertex(key: VertexKey, val: V['val']): V {
|
||||
return new MyVertex(key, val) as V;
|
||||
}
|
||||
|
||||
createEdge(src: VertexId, dest: VertexId, weight?: number, val?: E['val']): E {
|
||||
createEdge(src: VertexKey, dest: VertexKey, weight?: number, val?: E['val']): E {
|
||||
return new MyEdge(src, dest, weight ?? 1, val) as E;
|
||||
}
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ describe('Inherit from DirectedGraph and perform operations', () => {
|
|||
expect(sorted.length).toBe(9);
|
||||
if (sorted[0] instanceof MyVertex) expect(sorted[0].data).toBe('data9');
|
||||
sorted[3] instanceof MyVertex && expect(sorted[3].data).toBe('data6');
|
||||
sorted[8] instanceof MyVertex && expect(sorted[8].id).toBe(1);
|
||||
sorted[8] instanceof MyVertex && expect(sorted[8].key).toBe(1);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -266,9 +266,9 @@ describe('Inherit from DirectedGraph and perform operations test2.', () => {
|
|||
if (minPath1to7 && minPath1to7.length > 0) {
|
||||
expect(minPath1to7).toHaveLength(3);
|
||||
expect(minPath1to7[0]).toBeInstanceOf(MyVertex);
|
||||
expect(minPath1to7[0].id).toBe(1);
|
||||
expect(minPath1to7[1].id).toBe(9);
|
||||
expect(minPath1to7[2].id).toBe(7);
|
||||
expect(minPath1to7[0].key).toBe(1);
|
||||
expect(minPath1to7[1].key).toBe(9);
|
||||
expect(minPath1to7[2].key).toBe(7);
|
||||
}
|
||||
|
||||
const fordResult1 = myGraph.bellmanFord(1);
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
export * from './directed-graph.test';
|
||||
export * from './undirected-graph.test';
|
|
@ -30,16 +30,16 @@ describe('MapGraph Operation Test', () => {
|
|||
const expected1 = ['Surin', 'Lotus', 'The Breeza', 'Trinity Auto', 'Saanen Goat Farm'];
|
||||
|
||||
const minPathBetween = mapGraph.getMinPathBetween('Surin', 'Saanen Goat Farm');
|
||||
expect(minPathBetween?.map(v => v.id)).toEqual(expected1);
|
||||
expect(minPathBetween?.map(v => v.key)).toEqual(expected1);
|
||||
const surinToSaanenGoatFarmDij = mapGraph.dijkstra('Surin', 'Saanen Goat Farm', true, true);
|
||||
expect(surinToSaanenGoatFarmDij?.minPath.map(v => v.id)).toEqual(expected1);
|
||||
expect(surinToSaanenGoatFarmDij?.minPath.map(v => v.key)).toEqual(expected1);
|
||||
expect(surinToSaanenGoatFarmDij?.minDist).toBe(41.1);
|
||||
mapGraph.addEdge('Surin', 'Batu Feringgi Beach', 1.5);
|
||||
const expected2 = ['Surin', 'Batu Feringgi Beach', 'Hard Rock Hotel', 'Saanen Goat Farm'];
|
||||
const minPathBetweenViaBFB = mapGraph.getMinPathBetween('Surin', 'Saanen Goat Farm', true);
|
||||
expect(minPathBetweenViaBFB?.map(v => v.id)).toEqual(expected2);
|
||||
expect(minPathBetweenViaBFB?.map(v => v.key)).toEqual(expected2);
|
||||
const surinToSaanenGoatFarmViaDij = mapGraph.dijkstra('Surin', 'Saanen Goat Farm', true, true);
|
||||
expect(surinToSaanenGoatFarmViaDij?.minPath.map(v => v.id)).toEqual(expected2);
|
||||
expect(surinToSaanenGoatFarmViaDij?.minPath.map(v => v.key)).toEqual(expected2);
|
||||
expect(surinToSaanenGoatFarmViaDij?.minDist).toBe(25.2);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -29,8 +29,8 @@ describe('Overall Graph Operation Test', () => {
|
|||
graph.addEdge('A', 'B');
|
||||
graph.addEdge('B', 'C');
|
||||
|
||||
const topologicalOrderIds = graph.topologicalSort();
|
||||
expect(topologicalOrderIds).toEqual(['A', 'B', 'C']);
|
||||
const topologicalOrderKeys = graph.topologicalSort();
|
||||
expect(topologicalOrderKeys).toEqual(['A', 'B', 'C']);
|
||||
});
|
||||
it('Overall UndirectedGraph Operation Test', () => {
|
||||
const graph = new UndirectedGraph();
|
||||
|
@ -43,7 +43,7 @@ describe('Overall Graph Operation Test', () => {
|
|||
graph.addEdge('B', 'D');
|
||||
|
||||
const dijkstraResult = graph.dijkstra('A');
|
||||
Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id); // ['A', 'B', 'D']
|
||||
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id)).toEqual(['A', 'B', 'D']);
|
||||
Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key); // ['A', 'B', 'D']
|
||||
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key)).toEqual(['A', 'B', 'D']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -54,6 +54,6 @@ describe('UndirectedGraph Operation Test', () => {
|
|||
graph.addEdge('B', 'D');
|
||||
|
||||
const dijkstraResult = graph.dijkstra('A');
|
||||
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.id)).toEqual(['A', 'B', 'D']);
|
||||
expect(Array.from(dijkstraResult?.seen ?? []).map(vertex => vertex.key)).toEqual(['A', 'B', 'D']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -21,34 +21,41 @@ describe('Heap Operation Test', () => {
|
|||
});
|
||||
|
||||
it('should object heap work well', function () {
|
||||
const minHeap = new MinHeap<{a: string}>();
|
||||
minHeap.add(1, {a: 'a1'});
|
||||
minHeap.add(6, {a: 'a6'});
|
||||
minHeap.add(2, {a: 'a2'});
|
||||
minHeap.add(0, {a: 'a0'});
|
||||
const minHeap = new MinHeap<{a: string; key: number}>((a, b) => a.key - b.key);
|
||||
minHeap.add({key: 1, a: 'a1'});
|
||||
minHeap.add({key: 6, a: 'a6'});
|
||||
minHeap.add({key: 2, a: 'a2'});
|
||||
minHeap.add({key: 0, a: 'a0'});
|
||||
|
||||
expect(minHeap.peek()).toEqual({a: 'a0'});
|
||||
expect(minHeap.toArray()).toEqual([{a: 'a0'}, {a: 'a1'}, {a: 'a2'}, {a: 'a6'}]);
|
||||
expect(minHeap.peek()).toEqual({a: 'a0', key: 0});
|
||||
expect(minHeap.toArray().map(item => ({a: item.a}))).toEqual([{a: 'a0'}, {a: 'a1'}, {a: 'a2'}, {a: 'a6'}]);
|
||||
let i = 0;
|
||||
const expectPolled = [{a: 'a0'}, {a: 'a1'}, {a: 'a2'}, {a: 'a6'}];
|
||||
while (minHeap.size > 0) {
|
||||
expect(minHeap.poll()).toEqual(expectPolled[i]);
|
||||
expect({a: minHeap.poll()?.a}).toEqual(expectPolled[i]);
|
||||
i++;
|
||||
}
|
||||
|
||||
const maxHeap = new MaxHeap<{a: string}>();
|
||||
maxHeap.add(1, {a: 'a1'});
|
||||
maxHeap.add(6, {a: 'a6'});
|
||||
maxHeap.add(5, {a: 'a5'});
|
||||
maxHeap.add(2, {a: 'a2'});
|
||||
maxHeap.add(0, {a: 'a0'});
|
||||
maxHeap.add(9, {a: 'a9'});
|
||||
expect(maxHeap.peek()).toEqual({a: 'a9'});
|
||||
expect(maxHeap.toArray()).toEqual([{a: 'a9'}, {a: 'a2'}, {a: 'a6'}, {a: 'a1'}, {a: 'a0'}, {a: 'a5'}]);
|
||||
const maxHeap = new MaxHeap<{key: number; a: string}>((a, b) => b.key - a.key);
|
||||
maxHeap.add({key: 1, a: 'a1'});
|
||||
maxHeap.add({key: 6, a: 'a6'});
|
||||
maxHeap.add({key: 5, a: 'a5'});
|
||||
maxHeap.add({key: 2, a: 'a2'});
|
||||
maxHeap.add({key: 0, a: 'a0'});
|
||||
maxHeap.add({key: 9, a: 'a9'});
|
||||
expect(maxHeap.peek()).toEqual({a: 'a9', key: 9});
|
||||
expect(maxHeap.toArray().map(item => ({a: item.a}))).toEqual([
|
||||
{a: 'a9'},
|
||||
{a: 'a2'},
|
||||
{a: 'a6'},
|
||||
{a: 'a1'},
|
||||
{a: 'a0'},
|
||||
{a: 'a5'}
|
||||
]);
|
||||
const maxExpectPolled = [{a: 'a9'}, {a: 'a6'}, {a: 'a5'}, {a: 'a2'}, {a: 'a1'}, {a: 'a0'}];
|
||||
let maxI = 0;
|
||||
while (maxHeap.size > 0) {
|
||||
expect(maxHeap.poll()).toEqual(maxExpectPolled[maxI]);
|
||||
expect({a: maxHeap.poll()?.a}).toEqual(maxExpectPolled[maxI]);
|
||||
maxI++;
|
||||
}
|
||||
});
|
||||
|
|
|
@ -1,44 +1,52 @@
|
|||
import {HeapItem, MaxHeap} from '../../../../src';
|
||||
import {HeapComparator, MaxHeap} from '../../../../src';
|
||||
|
||||
describe('MaxHeap Operation Test', () => {
|
||||
it('should object Max Heap operations be proper', function () {
|
||||
const maxHeap = new MaxHeap<{keyA: string}>();
|
||||
const myObj1 = {keyA: 'a1'},
|
||||
myObj6 = {keyA: 'a6'},
|
||||
myObj5 = {keyA: 'a5'},
|
||||
myObj2 = {keyA: 'a2'},
|
||||
myObj0 = {keyA: 'a0'},
|
||||
myObj9 = {keyA: 'a9'};
|
||||
maxHeap.add(1, myObj1);
|
||||
expect(maxHeap.has(myObj1)).toBe(true);
|
||||
expect(maxHeap.has(myObj9)).toBe(false);
|
||||
maxHeap.add(6, myObj6);
|
||||
expect(maxHeap.has(myObj6)).toBe(true);
|
||||
maxHeap.add(5, myObj5);
|
||||
expect(maxHeap.has(myObj5)).toBe(true);
|
||||
maxHeap.add(2, myObj2);
|
||||
expect(maxHeap.has(myObj2)).toBe(true);
|
||||
expect(maxHeap.has(myObj6)).toBe(true);
|
||||
maxHeap.add(0, myObj0);
|
||||
expect(maxHeap.has(myObj0)).toBe(true);
|
||||
expect(maxHeap.has(myObj9)).toBe(false);
|
||||
maxHeap.add(9, myObj9);
|
||||
expect(maxHeap.has(myObj9)).toBe(true);
|
||||
describe('MaxHeap', () => {
|
||||
const numberComparator: HeapComparator<number> = (a, b) => b - a;
|
||||
let maxHeap: MaxHeap<number>;
|
||||
|
||||
const peek9 = maxHeap.peek(true);
|
||||
peek9 && peek9.val && expect(peek9.val.keyA).toBe('a9');
|
||||
beforeEach(() => {
|
||||
maxHeap = new MaxHeap(numberComparator);
|
||||
});
|
||||
|
||||
const heapToArr = maxHeap.toArray(true);
|
||||
expect(heapToArr.map(item => item?.val?.keyA)).toEqual(['a9', 'a2', 'a6', 'a1', 'a0', 'a5']);
|
||||
test('add and poll elements in descending order', () => {
|
||||
maxHeap.add(3);
|
||||
maxHeap.add(1);
|
||||
maxHeap.add(4);
|
||||
maxHeap.add(2);
|
||||
|
||||
const values = ['a9', 'a6', 'a5', 'a2', 'a1', 'a0'];
|
||||
let i = 0;
|
||||
while (maxHeap.size > 0) {
|
||||
const polled = maxHeap.poll(true);
|
||||
expect(polled).toBeInstanceOf(HeapItem);
|
||||
polled && expect(polled.val).toHaveProperty('keyA');
|
||||
polled && polled.val && expect(polled.val.keyA).toBe(values[i]);
|
||||
i++;
|
||||
}
|
||||
expect(maxHeap.poll()).toBe(4);
|
||||
expect(maxHeap.poll()).toBe(3);
|
||||
expect(maxHeap.poll()).toBe(2);
|
||||
expect(maxHeap.poll()).toBe(1);
|
||||
});
|
||||
|
||||
test('peek at the top element without removing it', () => {
|
||||
maxHeap.add(3);
|
||||
maxHeap.add(1);
|
||||
maxHeap.add(4);
|
||||
maxHeap.add(2);
|
||||
|
||||
expect(maxHeap.peek()).toBe(4);
|
||||
expect(maxHeap.size).toBe(4);
|
||||
});
|
||||
|
||||
test('sort elements in descending order', () => {
|
||||
maxHeap.add(3);
|
||||
maxHeap.add(1);
|
||||
maxHeap.add(4);
|
||||
maxHeap.add(2);
|
||||
|
||||
const sortedArray = maxHeap.sort();
|
||||
expect(sortedArray).toEqual([4, 3, 2, 1]);
|
||||
});
|
||||
|
||||
test('check if the heap is empty', () => {
|
||||
expect(maxHeap.isEmpty()).toBe(true);
|
||||
|
||||
maxHeap.add(5);
|
||||
expect(maxHeap.isEmpty()).toBe(false);
|
||||
|
||||
maxHeap.poll();
|
||||
expect(maxHeap.isEmpty()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,82 +1,52 @@
|
|||
import {HeapItem, MinHeap} from '../../../../src';
|
||||
import {HeapComparator, MinHeap} from '../../../../src';
|
||||
|
||||
describe('MinHeap Operation Test', () => {
|
||||
it('should numeric Min Heap operations be proper', function () {
|
||||
const minNumHeap = new MinHeap<number>();
|
||||
expect(minNumHeap).toBeInstanceOf(MinHeap);
|
||||
describe('MinHeap', () => {
|
||||
const numberComparator: HeapComparator<number> = (a, b) => a - b;
|
||||
let minHeap: MinHeap<number>;
|
||||
|
||||
minNumHeap.add(1);
|
||||
expect(minNumHeap.has(1)).toBe(true);
|
||||
minNumHeap.add(6);
|
||||
expect(minNumHeap.has(2)).toBe(false);
|
||||
expect(minNumHeap.has(6)).toBe(true);
|
||||
minNumHeap.add(2);
|
||||
expect(minNumHeap.has(2)).toBe(true);
|
||||
minNumHeap.add(0);
|
||||
expect(minNumHeap.has(0)).toBe(true);
|
||||
minNumHeap.add(5);
|
||||
expect(minNumHeap.has(5)).toBe(true);
|
||||
minNumHeap.add(9);
|
||||
expect(minNumHeap.has(9)).toBe(true);
|
||||
expect(minNumHeap.size).toBe(6);
|
||||
|
||||
const poll1 = minNumHeap.poll(true);
|
||||
expect(poll1).toBeInstanceOf(HeapItem);
|
||||
poll1 instanceof HeapItem && expect(poll1.val).toBe(0);
|
||||
|
||||
const poll2 = minNumHeap.poll(true);
|
||||
expect(poll2).toBeInstanceOf(HeapItem);
|
||||
poll2 instanceof HeapItem && expect(poll2.val).toBe(1);
|
||||
|
||||
const peek1 = minNumHeap.peek(true);
|
||||
expect(peek1).toBeInstanceOf(HeapItem);
|
||||
peek1 instanceof HeapItem && expect(peek1.val).toBe(2);
|
||||
|
||||
const heapArray = minNumHeap.toArray(true);
|
||||
expect(heapArray).toBeInstanceOf(Array);
|
||||
expect(heapArray.map(item => item?.priority)).toEqual([2, 5, 9, 6]);
|
||||
expect(minNumHeap.size).toBe(4);
|
||||
beforeEach(() => {
|
||||
minHeap = new MinHeap(numberComparator);
|
||||
});
|
||||
|
||||
it('should object Min Heap operations be proper', function () {
|
||||
class MyObject {
|
||||
keyA: string;
|
||||
test('add and poll elements in ascending order', () => {
|
||||
minHeap.add(3);
|
||||
minHeap.add(1);
|
||||
minHeap.add(4);
|
||||
minHeap.add(2);
|
||||
|
||||
constructor(keyA: string) {
|
||||
this.keyA = keyA;
|
||||
}
|
||||
}
|
||||
expect(minHeap.poll()).toBe(1);
|
||||
expect(minHeap.poll()).toBe(2);
|
||||
expect(minHeap.poll()).toBe(3);
|
||||
expect(minHeap.poll()).toBe(4);
|
||||
});
|
||||
|
||||
const minObjHeap = new MinHeap<MyObject>();
|
||||
test('peek at the top element without removing it', () => {
|
||||
minHeap.add(3);
|
||||
minHeap.add(1);
|
||||
minHeap.add(4);
|
||||
minHeap.add(2);
|
||||
|
||||
const obj1 = new MyObject('a1'),
|
||||
obj6 = new MyObject('a6'),
|
||||
obj2 = new MyObject('a2'),
|
||||
obj0 = new MyObject('a0');
|
||||
minObjHeap.add(1, obj1);
|
||||
expect(minObjHeap.has(obj1)).toBe(true);
|
||||
expect(minObjHeap.has(obj6)).toBe(false);
|
||||
minObjHeap.add(6, obj6);
|
||||
expect(minObjHeap.has(obj6)).toBe(true);
|
||||
minObjHeap.add(2, obj2);
|
||||
expect(minObjHeap.has(obj2)).toBe(true);
|
||||
minObjHeap.add(0, obj0);
|
||||
expect(minObjHeap.has(obj0)).toBe(true);
|
||||
expect(minHeap.peek()).toBe(1);
|
||||
expect(minHeap.size).toBe(4);
|
||||
});
|
||||
|
||||
const peek = minObjHeap.peek(true);
|
||||
peek && peek.val && expect(peek.val.keyA).toBe('a0');
|
||||
test('sort elements in ascending order', () => {
|
||||
minHeap.add(3);
|
||||
minHeap.add(1);
|
||||
minHeap.add(4);
|
||||
minHeap.add(2);
|
||||
|
||||
const heapToArr = minObjHeap.toArray(true);
|
||||
expect(heapToArr.map(item => item?.val?.keyA)).toEqual(['a0', 'a1', 'a2', 'a6']);
|
||||
const sortedArray = minHeap.sort();
|
||||
expect(sortedArray).toEqual([1, 2, 3, 4]);
|
||||
});
|
||||
|
||||
const values = ['a0', 'a1', 'a2', 'a6'];
|
||||
let i = 0;
|
||||
while (minObjHeap.size > 0) {
|
||||
const polled = minObjHeap.poll(true);
|
||||
expect(polled).toBeInstanceOf(HeapItem);
|
||||
polled && expect(polled.val).toBeInstanceOf(MyObject);
|
||||
polled && polled.val && expect(polled.val.keyA).toBe(values[i]);
|
||||
i++;
|
||||
}
|
||||
test('check if the heap is empty', () => {
|
||||
expect(minHeap.isEmpty()).toBe(true);
|
||||
|
||||
minHeap.add(5);
|
||||
expect(minHeap.isEmpty()).toBe(false);
|
||||
|
||||
minHeap.poll();
|
||||
expect(minHeap.isEmpty()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -349,7 +349,7 @@ describe('DoublyLinkedList Performance Test', () => {
|
|||
for (let i = 0; i < magnitude.LINEAR; i++) {
|
||||
list.unshift(i);
|
||||
}
|
||||
expect(performance.now() - startPushTime).toBeLessThan(bigO.LINEAR * 10);
|
||||
expect(performance.now() - startPushTime).toBeLessThan(bigO.LINEAR * 20);
|
||||
|
||||
expect(list.length).toBeGreaterThan(0);
|
||||
const startPopTime = performance.now();
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
export * from './singly-linked-list.test';
|
||||
export * from './doubly-linked-list.test';
|
||||
export * from './linked-list.test';
|
||||
export * from './skip-linked-list.test';
|
|
@ -384,7 +384,7 @@ describe('SinglyLinkedList Performance Test', () => {
|
|||
for (let i = 0; i < magnitude.LINEAR; i++) {
|
||||
list.push(i);
|
||||
}
|
||||
expect(performance.now() - startPushTime).toBeLessThan(bigO.LINEAR * 10);
|
||||
expect(performance.now() - startPushTime).toBeLessThan(bigO.LINEAR * 20);
|
||||
|
||||
const startPopTime = performance.now();
|
||||
|
||||
|
|
|
@ -17,11 +17,8 @@ describe('MaxPriorityQueue Operation Test', () => {
|
|||
});
|
||||
|
||||
it('should add elements and maintain heap property in a object MaxPriorityQueue', () => {
|
||||
const priorityQueue = new MaxPriorityQueue<{keyA: number}>({
|
||||
nodes: [{keyA: 5}, {keyA: 3}, {keyA: 1}],
|
||||
comparator: (a, b) => b.keyA - a.keyA
|
||||
});
|
||||
|
||||
const priorityQueue = new MaxPriorityQueue<{keyA: number}>((a, b) => b.keyA - a.keyA);
|
||||
priorityQueue.refill([{keyA: 5}, {keyA: 3}, {keyA: 1}]);
|
||||
priorityQueue.add({keyA: 7});
|
||||
|
||||
expect(priorityQueue.poll()?.keyA).toBe(7);
|
||||
|
@ -56,7 +53,8 @@ describe('MaxPriorityQueue Operation Test', () => {
|
|||
|
||||
it('should correctly heapify an array', () => {
|
||||
const array = [5, 3, 7, 1];
|
||||
const heap = MaxPriorityQueue.heapify<number>({nodes: array});
|
||||
const heap = MaxPriorityQueue.heapify<number>(array, (a, b) => b - a);
|
||||
heap.refill(array);
|
||||
|
||||
expect(heap.poll()).toBe(7);
|
||||
expect(heap.poll()).toBe(5);
|
||||
|
@ -66,7 +64,7 @@ describe('MaxPriorityQueue Operation Test', () => {
|
|||
|
||||
it('should correctly heapify an object array', () => {
|
||||
const nodes = [{keyA: 5}, {keyA: 3}, {keyA: 7}, {keyA: 1}];
|
||||
const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>({nodes, comparator: (a, b) => b.keyA - a.keyA});
|
||||
const maxPQ = MaxPriorityQueue.heapify<{keyA: number}>(nodes, (a, b) => b.keyA - a.keyA);
|
||||
|
||||
expect(maxPQ.poll()?.keyA).toBe(7);
|
||||
expect(maxPQ.poll()?.keyA).toBe(5);
|
||||
|
@ -81,8 +79,8 @@ describe('MaxPriorityQueue Performance Test', () => {
|
|||
new Set<number>(Array.from(new Array(magnitude.LINEAR), () => Math.floor(Math.random() * magnitude.LINEAR * 100)))
|
||||
);
|
||||
expect(nodes.length).toBeGreaterThan(magnitude.LINEAR / 2);
|
||||
const maxPQ = new MaxPriorityQueue<number>({nodes});
|
||||
|
||||
const maxPQ = new MaxPriorityQueue<number>();
|
||||
maxPQ.refill(nodes);
|
||||
let prev = Number.MAX_SAFE_INTEGER;
|
||||
const startTime = performance.now();
|
||||
while (maxPQ.size > 0) {
|
||||
|
@ -91,7 +89,8 @@ describe('MaxPriorityQueue Performance Test', () => {
|
|||
prev = polled;
|
||||
}
|
||||
}
|
||||
expect(performance.now() - startTime).toBeLessThan(bigO.LINEAR * 50);
|
||||
const cost = performance.now() - startTime;
|
||||
expect(cost).toBeLessThan(bigO.LINEAR * 20);
|
||||
expect(prev).toBeGreaterThan(0);
|
||||
});
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ describe('MinPriorityQueue Operation Test', () => {
|
|||
priorityQueue.add(3);
|
||||
priorityQueue.add(7);
|
||||
|
||||
expect(priorityQueue.leaf()).toBe(7);
|
||||
expect(priorityQueue.leaf).toBe(7);
|
||||
});
|
||||
|
||||
it('should check if the queue is empty', () => {
|
||||
|
|
|
@ -2,69 +2,52 @@ import {PriorityQueue} from '../../../../src';
|
|||
import {getRandomInt} from '../../../utils';
|
||||
|
||||
describe('PriorityQueue Operation Test', () => {
|
||||
it('should validate a priority queue', () => {
|
||||
const minPQ = new PriorityQueue<number>({nodes: [1, 5, 7, 9, 3, 6, 2], comparator: (a, b) => a - b});
|
||||
|
||||
expect(minPQ.isValid()).toBe(true);
|
||||
expect(PriorityQueue.isPriorityQueueified({nodes: minPQ.nodes, comparator: (a, b) => a - b})).toBe(true);
|
||||
expect(PriorityQueue.isPriorityQueueified({nodes: minPQ.nodes, comparator: (a, b) => b - a})).toBe(false);
|
||||
expect(
|
||||
PriorityQueue.isPriorityQueueified({
|
||||
nodes: [1, 5, 7, 9, 3, 6, 2],
|
||||
comparator: (a, b) => b - a
|
||||
})
|
||||
).toBe(false);
|
||||
});
|
||||
|
||||
it('should PriorityQueue poll, pee, heapify, toArray work well', function () {
|
||||
const minPQ = new PriorityQueue<number>({nodes: [5, 2, 3, 4, 6, 1], comparator: (a, b) => a - b});
|
||||
const minPQ = new PriorityQueue<number>((a, b) => a - b);
|
||||
minPQ.refill([5, 2, 3, 4, 6, 1]);
|
||||
expect(minPQ.toArray()).toEqual([1, 2, 3, 4, 6, 5]);
|
||||
minPQ.poll();
|
||||
minPQ.poll();
|
||||
minPQ.poll();
|
||||
expect(minPQ.toArray()).toEqual([4, 5, 6]);
|
||||
expect(minPQ.peek()).toBe(4);
|
||||
expect(
|
||||
PriorityQueue.heapify({
|
||||
nodes: [3, 2, 1, 5, 6, 7, 8, 9, 10],
|
||||
comparator: (a, b) => a - b
|
||||
}).toArray()
|
||||
).toEqual([1, 2, 3, 5, 6, 7, 8, 9, 10]);
|
||||
expect(PriorityQueue.heapify([3, 2, 1, 5, 6, 7, 8, 9, 10], (a, b) => a - b).toArray()).toEqual([
|
||||
1, 2, 3, 5, 6, 7, 8, 9, 10
|
||||
]);
|
||||
});
|
||||
|
||||
it('should Max PriorityQueue poll, peek, heapify, toArray work well', function () {
|
||||
const maxPriorityQueue = new PriorityQueue<number>({nodes: [5, 2, 3, 4, 6, 1], comparator: (a, b) => b - a});
|
||||
const maxPriorityQueue = new PriorityQueue<number>((a, b) => b - a);
|
||||
maxPriorityQueue.refill([5, 2, 3, 4, 6, 1]);
|
||||
expect(maxPriorityQueue.toArray()).toEqual([6, 5, 3, 4, 2, 1]);
|
||||
maxPriorityQueue.poll();
|
||||
maxPriorityQueue.poll();
|
||||
maxPriorityQueue.poll();
|
||||
expect(maxPriorityQueue.toArray()).toEqual([3, 2, 1]);
|
||||
expect(maxPriorityQueue.peek()).toBe(3);
|
||||
expect(
|
||||
PriorityQueue.heapify({
|
||||
nodes: [3, 2, 1, 5, 6, 7, 8, 9, 10],
|
||||
comparator: (a, b) => a - b
|
||||
}).toArray()
|
||||
).toEqual([1, 2, 3, 5, 6, 7, 8, 9, 10]);
|
||||
expect(PriorityQueue.heapify([3, 2, 1, 5, 6, 7, 8, 9, 10], (a, b) => a - b).toArray()).toEqual([
|
||||
1, 2, 3, 5, 6, 7, 8, 9, 10
|
||||
]);
|
||||
});
|
||||
|
||||
it('should PriorityQueue clone, sort, getNodes, DFS work well', function () {
|
||||
const minPQ1 = new PriorityQueue<number>({nodes: [2, 5, 8, 3, 1, 6, 7, 4], comparator: (a, b) => a - b});
|
||||
it('should PriorityQueue clone, sort, getNodes, dfs work well', function () {
|
||||
const minPQ1 = new PriorityQueue<number>((a, b) => a - b);
|
||||
minPQ1.refill([2, 5, 8, 3, 1, 6, 7, 4]);
|
||||
const clonedPriorityQueue = minPQ1.clone();
|
||||
expect(clonedPriorityQueue.getNodes()).toEqual(minPQ1.getNodes());
|
||||
expect(clonedPriorityQueue.sort()).toEqual([1, 2, 3, 4, 5, 6, 7, 8]);
|
||||
expect(minPQ1.DFS('in')).toEqual([4, 3, 2, 5, 1, 8, 6, 7]);
|
||||
expect(minPQ1.DFS('post')).toEqual([4, 3, 5, 2, 8, 7, 6, 1]);
|
||||
expect(minPQ1.DFS('pre')).toEqual([1, 2, 3, 4, 5, 6, 8, 7]);
|
||||
expect(minPQ1.dfs('in')).toEqual([4, 3, 2, 5, 1, 8, 6, 7]);
|
||||
expect(minPQ1.dfs('post')).toEqual([4, 3, 5, 2, 8, 7, 6, 1]);
|
||||
expect(minPQ1.dfs('pre')).toEqual([1, 2, 3, 4, 5, 6, 8, 7]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Priority Queue Performance Test', () => {
|
||||
it('should numeric heap work well', function () {
|
||||
const values = Array.from(new Array(10000), () => getRandomInt(1, 10000000));
|
||||
const minPriorityQueue = new PriorityQueue<number>({nodes: values, comparator: (a, b) => a - b});
|
||||
const minPriorityQueue = new PriorityQueue<number>((a, b) => a - b);
|
||||
minPriorityQueue.refill(values);
|
||||
const sorted = minPriorityQueue.sort();
|
||||
expect(sorted).toEqual(values.sort((a, b) => a - b));
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import {TreeNode} from '../../../../src';
|
||||
|
||||
describe('TreeNode', () => {
|
||||
it('should create a TreeNode with the given id and value', () => {
|
||||
it('should create a TreeNode with the given key and value', () => {
|
||||
const node = new TreeNode<string>('1', 'Node 1');
|
||||
expect(node.id).toBe('1');
|
||||
expect(node.key).toBe('1');
|
||||
expect(node.value).toBe('Node 1');
|
||||
expect(node.children).toEqual([]);
|
||||
});
|
||||
|
@ -29,11 +29,11 @@ describe('TreeNode', () => {
|
|||
child1.addChildren([grandchild1]);
|
||||
child2.addChildren([grandchild2]);
|
||||
|
||||
expect(rootNode.getHeight()).toBe(3); // Height of the tree should be 3
|
||||
expect(rootNode.getHeight()).toBe(2); // Height of the tree should be 2
|
||||
});
|
||||
|
||||
it('should handle nodes without children when calculating height', () => {
|
||||
const rootNode = new TreeNode<string>('1', 'Root Node');
|
||||
expect(rootNode.getHeight()).toBe(1); // Height of a single node should be 1
|
||||
expect(rootNode.getHeight()).toBe(0); // Height of a single node should be 0
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import {Trie, TrieNode} from '../../../../src';
|
|||
describe('TrieNode', () => {
|
||||
it('should create a TrieNode with the given value', () => {
|
||||
const node = new TrieNode('a');
|
||||
expect(node.val).toBe('a');
|
||||
expect(node.key).toBe('a');
|
||||
expect(node.isEnd).toBe(false);
|
||||
expect(node.children.size).toBe(0);
|
||||
});
|
||||
|
@ -27,7 +27,7 @@ describe('TrieNode', () => {
|
|||
describe('Trie', () => {
|
||||
it('should create an empty Trie', () => {
|
||||
const trie = new Trie();
|
||||
expect(trie.root.val).toBe('');
|
||||
expect(trie.root.key).toBe('');
|
||||
expect(trie.root.children.size).toBe(0);
|
||||
});
|
||||
|
||||
|
@ -44,25 +44,25 @@ describe('Trie', () => {
|
|||
const trie = new Trie();
|
||||
trie.add('apple');
|
||||
trie.add('app');
|
||||
expect(trie.isAbsPrefix('appl')).toBe(true);
|
||||
expect(trie.isAbsPrefix('apples')).toBe(false);
|
||||
expect(trie.hasPurePrefix('appl')).toBe(true);
|
||||
expect(trie.hasPurePrefix('apples')).toBe(false);
|
||||
});
|
||||
|
||||
it('should check if a string is a prefix', () => {
|
||||
const trie = new Trie();
|
||||
trie.add('apple');
|
||||
trie.add('app');
|
||||
expect(trie.isPrefix('app')).toBe(true);
|
||||
expect(trie.isPrefix('banana')).toBe(false);
|
||||
expect(trie.hasPrefix('app')).toBe(true);
|
||||
expect(trie.hasPrefix('banana')).toBe(false);
|
||||
});
|
||||
|
||||
it('should check if a string is a common prefix', () => {
|
||||
const trie = new Trie();
|
||||
trie.add('apple');
|
||||
trie.add('app');
|
||||
expect(trie.isCommonPrefix('ap')).toBe(true);
|
||||
expect(trie.isCommonPrefix('app')).toBe(true);
|
||||
expect(trie.isCommonPrefix('b')).toBe(false);
|
||||
expect(trie.hasCommonPrefix('ap')).toBe(true);
|
||||
expect(trie.hasCommonPrefix('app')).toBe(true);
|
||||
expect(trie.hasCommonPrefix('b')).toBe(false);
|
||||
});
|
||||
|
||||
it('should get the longest common prefix', () => {
|
||||
|
@ -77,7 +77,7 @@ describe('Trie', () => {
|
|||
trie.add('apple');
|
||||
trie.add('app');
|
||||
trie.add('application');
|
||||
const words = trie.getAll('app');
|
||||
const words = trie.getWords('app');
|
||||
expect(words).toEqual(['apple', 'application', 'app']);
|
||||
});
|
||||
|
||||
|
@ -92,4 +92,734 @@ describe('Trie', () => {
|
|||
trie.remove('app');
|
||||
expect(trie.has('app')).toBe(false);
|
||||
});
|
||||
|
||||
it('should suggestion Trie work well', () => {
|
||||
const trie = new Trie();
|
||||
const products = ['carpet', 'cart', 'car', 'camera'];
|
||||
products.forEach(product => trie.add(product));
|
||||
expect(trie.getWords('car', 2)).toEqual(['carpet', 'cart']);
|
||||
const prods = [
|
||||
'Phone',
|
||||
'TV',
|
||||
'Laptop',
|
||||
'Washing Machine',
|
||||
'Refrigerator',
|
||||
'Air Conditioner',
|
||||
'Mouse',
|
||||
'Keyboard',
|
||||
'Headphones',
|
||||
'Watch',
|
||||
'Fan',
|
||||
'Chair',
|
||||
'Table',
|
||||
'Bookshelf',
|
||||
'Lamp',
|
||||
'Camera',
|
||||
'Gaming Console',
|
||||
'Projector',
|
||||
'Printer',
|
||||
'Robot Vacuum',
|
||||
'Microwave',
|
||||
'Toaster',
|
||||
'Coffee Maker',
|
||||
'Blender',
|
||||
'Vacuum Cleaner',
|
||||
'Drill',
|
||||
'Router',
|
||||
'Monitor',
|
||||
'Tablet',
|
||||
'Speakers',
|
||||
'Smartwatch',
|
||||
'Hair Dryer',
|
||||
'Iron',
|
||||
'Microwave Oven',
|
||||
'Oven',
|
||||
'Blu-ray Player',
|
||||
'Carpet Cleaner',
|
||||
'Recliner',
|
||||
'Desk',
|
||||
'Pen',
|
||||
'Pencil',
|
||||
'Notepad',
|
||||
'Backpack',
|
||||
'Sunglasses',
|
||||
'Umbrella',
|
||||
'Jacket',
|
||||
'Shoes',
|
||||
'Bracelet',
|
||||
'Socks',
|
||||
'Hat',
|
||||
'Scarf',
|
||||
'Gloves',
|
||||
'Bicycle',
|
||||
'Scooter',
|
||||
'Skateboard',
|
||||
'Surfboard',
|
||||
'Soccer Ball',
|
||||
'Basketball',
|
||||
'Tennis Racket',
|
||||
'Golf Clubs',
|
||||
'Baseball Bat',
|
||||
'Fishing Rod',
|
||||
'Hiking Boots',
|
||||
'Tent',
|
||||
'Sleeping Bag',
|
||||
'Camp Stove',
|
||||
'Duffle Bag',
|
||||
'Guitar',
|
||||
'Piano',
|
||||
'Violin',
|
||||
'Drums',
|
||||
'Trumpet',
|
||||
'Harmonica',
|
||||
'Flute',
|
||||
'Microphone',
|
||||
'Amplifier',
|
||||
'Speaker System',
|
||||
'Couch',
|
||||
'Coffee Table',
|
||||
'Dining Table',
|
||||
'Sideboard',
|
||||
'Bed',
|
||||
'Mattress',
|
||||
'Pillow',
|
||||
'Blanket',
|
||||
'Rug',
|
||||
'Dresser',
|
||||
'Wardrobe',
|
||||
'Dining Chair',
|
||||
'Cabinet',
|
||||
'Shower Curtain',
|
||||
'Toothbrush',
|
||||
'Toothpaste',
|
||||
'Shampoo',
|
||||
'Soap',
|
||||
'Razor',
|
||||
'Towel',
|
||||
'Toilet Paper',
|
||||
'Laundry Detergent',
|
||||
'Dish Soap',
|
||||
'Broom',
|
||||
'Mop',
|
||||
'Trash Can',
|
||||
'Ironing Board',
|
||||
'Food Processor',
|
||||
'Slow Cooker',
|
||||
'Stand Mixer',
|
||||
'Cutting Board',
|
||||
'Knife Set',
|
||||
'Dining Set',
|
||||
'Silverware Set',
|
||||
'Bakeware Set',
|
||||
'Cookware Set',
|
||||
'Frying Pan',
|
||||
'Baking Sheet',
|
||||
'Mixing Bowls',
|
||||
'Can Opener',
|
||||
'Peeler',
|
||||
'Measuring Cups',
|
||||
'Utensil Set',
|
||||
'Dish Rack',
|
||||
'Storage Containers',
|
||||
'Trash Bags',
|
||||
'Aluminum Foil',
|
||||
'Plastic Wrap',
|
||||
'Ziplock Bags',
|
||||
'Cleaning Supplies',
|
||||
'Bath Towels',
|
||||
'Hand Towels',
|
||||
'Face Towels',
|
||||
'Bath Mat',
|
||||
'Shower Caddy',
|
||||
'Soap Dispenser',
|
||||
'Toothbrush Holder',
|
||||
'Shower Head',
|
||||
'Toilet Brush',
|
||||
'Plunger',
|
||||
'Hair Straightener',
|
||||
'Curling Iron',
|
||||
'Makeup Mirror',
|
||||
'Shaving Kit',
|
||||
'Cosmetic Bag',
|
||||
'Perfume',
|
||||
'Cologne',
|
||||
'Shower Gel',
|
||||
'Lotion',
|
||||
'Deodorant',
|
||||
'Sunscreen',
|
||||
'Toilet Paper Holder',
|
||||
'Laundry Basket',
|
||||
'Step Stool',
|
||||
'Flashlight',
|
||||
'Batteries',
|
||||
'Power Strip',
|
||||
'Extension Cord',
|
||||
'Toolbox',
|
||||
'Screwdriver Set',
|
||||
'Wrench',
|
||||
'Pliers',
|
||||
'Hammer',
|
||||
'Tape Measure',
|
||||
'Level',
|
||||
'Utility Knife',
|
||||
'Cordless Drill',
|
||||
'Safety Glasses',
|
||||
'Tool Belt',
|
||||
'Ladder',
|
||||
'Paint Brushes',
|
||||
'Paint Rollers',
|
||||
'Drop Cloth',
|
||||
"Painter's Tape",
|
||||
'Paint Cans',
|
||||
'Wallpaper',
|
||||
'Wallpaper Paste',
|
||||
'Wallpaper Brush',
|
||||
'Wallpaper Roller',
|
||||
'Curtains',
|
||||
'Curtain Rod',
|
||||
'Curtain Rings',
|
||||
'Blinds',
|
||||
'Rugs',
|
||||
'Wall Clock',
|
||||
'Alarm Clock',
|
||||
'Desk Lamp',
|
||||
'Ceiling Fan',
|
||||
'Chandelier',
|
||||
'Floor Lamp',
|
||||
'Bedside Lamp',
|
||||
'Lawn Mower',
|
||||
'Hedge Trimmer',
|
||||
'Leaf Blower',
|
||||
'Garden Hose',
|
||||
'Sprinkler',
|
||||
'Gardening Tools',
|
||||
'Grill',
|
||||
'BBQ Tools',
|
||||
'Cooler',
|
||||
'Picnic Basket',
|
||||
'Camping Gear',
|
||||
'Pocket Knife',
|
||||
'Fishing Gear',
|
||||
'Boat',
|
||||
'Life Jacket',
|
||||
'Swimwear',
|
||||
'Beach Towel',
|
||||
'Beach Umbrella',
|
||||
'Wetsuit',
|
||||
'Snowboard',
|
||||
'Ski Equipment',
|
||||
'Snow Boots',
|
||||
'Snow Gloves',
|
||||
'Snow Goggles',
|
||||
'Snowshoes',
|
||||
'Sled',
|
||||
'Ice Skates',
|
||||
'Frisbee',
|
||||
'Pool Table',
|
||||
'Ping Pong Table',
|
||||
'Dartboard',
|
||||
'Chess Set',
|
||||
'Board Games',
|
||||
'Playing Cards',
|
||||
'Puzzle',
|
||||
'Video Games',
|
||||
'Gaming Chair',
|
||||
'VR Headset',
|
||||
'Binoculars',
|
||||
'Telescope',
|
||||
'Drone',
|
||||
'Action Camera',
|
||||
'Smartphone',
|
||||
'Desktop Computer',
|
||||
'Scanner',
|
||||
'External Hard Drive',
|
||||
'USB Flash Drive',
|
||||
'Computer Keyboard',
|
||||
'Computer Mouse',
|
||||
'Webcam',
|
||||
'Modem',
|
||||
'Ethernet Cable',
|
||||
'Wireless Headphones',
|
||||
'Bluetooth Speaker',
|
||||
'Earbuds',
|
||||
'Fitness Tracker',
|
||||
'Running Shoes',
|
||||
'Cycling Helmet',
|
||||
'Yoga Mat',
|
||||
'Dumbbells',
|
||||
'Resistance Bands',
|
||||
'Exercise Ball',
|
||||
'Jump Rope',
|
||||
'Treadmill',
|
||||
'Exercise Bike',
|
||||
'Elliptical Machine',
|
||||
'Weight Bench',
|
||||
'Gym Bag',
|
||||
'Tennis Shoes',
|
||||
'Swimsuit',
|
||||
'Goggles',
|
||||
'Snorkel',
|
||||
'Life Vest',
|
||||
'Bicycle Helmet',
|
||||
'Roller Skates',
|
||||
'Inline Skates',
|
||||
'Luggage Set',
|
||||
'Travel Pillow',
|
||||
'Suitcase',
|
||||
'Carry-On Bag',
|
||||
'Checked Bag',
|
||||
'Tote Bag',
|
||||
'Travel Adapter',
|
||||
'Neck Pillow',
|
||||
'Sleep Mask',
|
||||
'Portable Charger',
|
||||
'Camera Bag',
|
||||
'Laptop Bag',
|
||||
'Briefcase',
|
||||
'Hiking Backpack',
|
||||
'Hydration Pack',
|
||||
'Duffel Bag',
|
||||
'Messenger Bag',
|
||||
'Shoulder Bag',
|
||||
'Clutch',
|
||||
'Wallet',
|
||||
'Crossbody Bag',
|
||||
'Satchel',
|
||||
'Bucket Bag',
|
||||
'Hobo Bag',
|
||||
'Tennis Bag',
|
||||
'Golf Bag',
|
||||
'Weekender Bag',
|
||||
'Beach Bag',
|
||||
'Ski Bag',
|
||||
'Snowboard Bag',
|
||||
'Snowshoe Bag',
|
||||
'Surfboard Bag',
|
||||
'Wakeboard Bag',
|
||||
'Kiteboard Bag',
|
||||
'Skateboard Bag',
|
||||
'Roller Skates Bag',
|
||||
'Scuba Gear Bag',
|
||||
'Fishing Rod Bag',
|
||||
'Guitar Case',
|
||||
'Violin Case',
|
||||
'Trumpet Case',
|
||||
'Flute Case',
|
||||
'Clarinet Case',
|
||||
'Saxophone Case',
|
||||
'Keyboard Case',
|
||||
'Drum Case',
|
||||
'Speaker Case',
|
||||
'Microphone Case',
|
||||
'Camera Case',
|
||||
'Tripod Bag',
|
||||
'Binocular Case',
|
||||
'Telescope Case',
|
||||
'Art Supplies',
|
||||
'Paints',
|
||||
'Brushes',
|
||||
'Canvas',
|
||||
'Easel',
|
||||
'Sketchbook',
|
||||
'Pencils',
|
||||
'Watercolors',
|
||||
'Oil Paints',
|
||||
'Acrylic Paints',
|
||||
'Charcoal',
|
||||
'Pastels',
|
||||
'Markers',
|
||||
'Colored Pencils',
|
||||
'Crayons',
|
||||
'Chalk',
|
||||
'Ink',
|
||||
'Pottery Wheel',
|
||||
'Clay',
|
||||
'Pottery Tools',
|
||||
'Knitting Needles',
|
||||
'Yarn',
|
||||
'Crochet Hooks',
|
||||
'Sewing Machine',
|
||||
'Fabric',
|
||||
'Thread',
|
||||
'Sewing Needles',
|
||||
'Embroidery Hoop',
|
||||
'Cross-Stitch Kit',
|
||||
'Quilting Kit',
|
||||
'Model Kit',
|
||||
'Remote Control Car',
|
||||
'Train Set',
|
||||
'LEGO Set',
|
||||
'Building Blocks',
|
||||
'Dollhouse',
|
||||
'Action Figures',
|
||||
'Video Game Console',
|
||||
'Controller',
|
||||
'Virtual Reality Headset',
|
||||
'Poker Set',
|
||||
'Checkers Set',
|
||||
'Backgammon Set',
|
||||
'Dominoes Set',
|
||||
'Jigsaw Puzzle',
|
||||
'Racing Game',
|
||||
'Adventure Game',
|
||||
'Role-Playing Game',
|
||||
'First-Person Shooter',
|
||||
'Simulation Game',
|
||||
'Strategy Game',
|
||||
'Sports Game',
|
||||
'RPG Game',
|
||||
'Action-Adventure Game',
|
||||
'Fighting Game',
|
||||
'Platform Game',
|
||||
'Music Game',
|
||||
'Educational Game',
|
||||
'Puzzle Game',
|
||||
'Arcade Game',
|
||||
'Card Game',
|
||||
'Board Game',
|
||||
'Outdoor Game',
|
||||
'Indoor Game',
|
||||
'Word Game',
|
||||
'Brain Teaser',
|
||||
'Logic Puzzle',
|
||||
'Trivia Game',
|
||||
'Classic Game',
|
||||
'Party Game',
|
||||
'Family Game',
|
||||
"Children's Game",
|
||||
'Adult Game',
|
||||
'Dice Game',
|
||||
'Tile Game',
|
||||
'Electronic Game',
|
||||
'Video Game',
|
||||
'Retro Game',
|
||||
'Computer Game',
|
||||
'Console Game',
|
||||
'Mobile Game',
|
||||
'PC Game',
|
||||
'VR Game',
|
||||
'Deck-Building Game',
|
||||
'Cooperative Game',
|
||||
'Competitive Game',
|
||||
'Social Deduction Game',
|
||||
'Trading Card Game',
|
||||
'Collectible Card Game',
|
||||
'Miniatures Game',
|
||||
'Tabletop Game',
|
||||
'War Game',
|
||||
'Fantasy Game',
|
||||
'Science Fiction Game',
|
||||
'Horror Game',
|
||||
'Mystery Game',
|
||||
'Abstract Game',
|
||||
'Eurogame',
|
||||
'Ameritrash Game',
|
||||
'Wargame',
|
||||
'2-Player Game',
|
||||
'Drinking Game',
|
||||
'Action Figure',
|
||||
'Playset',
|
||||
'Educational Toy',
|
||||
'Stuffed Animal',
|
||||
'Doll',
|
||||
'Remote Control Toy',
|
||||
'Toy Car',
|
||||
'Toy Train',
|
||||
'Pretend Play Toy',
|
||||
'Construction Toy',
|
||||
'Art and Craft Kit',
|
||||
'Musical Toy',
|
||||
'Science Toy',
|
||||
'STEM Toy',
|
||||
'Puzzle Toy',
|
||||
'Building Toy',
|
||||
'Magnetic Toy',
|
||||
'Robot Toy',
|
||||
'Outdoor Toy',
|
||||
'Sports Toy',
|
||||
'Board Game Expansion',
|
||||
'Shooter Game',
|
||||
'Learning Toy',
|
||||
'Teaching Aid',
|
||||
'Flashcards',
|
||||
'Alphabet Blocks',
|
||||
'Educational Books',
|
||||
'Math Toy',
|
||||
'Science Kit',
|
||||
'Geography Toy',
|
||||
'History Toy',
|
||||
'Language Learning Toy',
|
||||
'Music Toy',
|
||||
'Art Toy',
|
||||
'STEM Kit',
|
||||
'Coding Toy',
|
||||
'Robotics Kit',
|
||||
'Building Kit',
|
||||
'Logic Toy',
|
||||
'Spelling Game',
|
||||
'Memory Game',
|
||||
'Problem-Solving Toy',
|
||||
'Critical Thinking Toy',
|
||||
'Math Game',
|
||||
'Science Game',
|
||||
'Geography Game',
|
||||
'History Game',
|
||||
'Language Learning Game',
|
||||
'Art Game',
|
||||
'Coding Game',
|
||||
'Robotics Game',
|
||||
'Building Game',
|
||||
'Memory Card',
|
||||
'Flash Drive',
|
||||
'Internal Hard Drive',
|
||||
'Solid State Drive',
|
||||
'Optical Drive',
|
||||
'USB Hub',
|
||||
'Computer Monitor',
|
||||
'Mouse Pad',
|
||||
'Laptop Stand',
|
||||
'Ink Cartridges',
|
||||
'Printer Paper',
|
||||
'Wireless Router',
|
||||
'Wi-Fi Extender',
|
||||
'Network Switch',
|
||||
'Headset',
|
||||
'External Sound Card',
|
||||
'Surge Protector',
|
||||
'Uninterruptible Power Supply',
|
||||
'Cable Management',
|
||||
'Office Chair',
|
||||
'File Cabinet',
|
||||
'Shelves',
|
||||
'Filing Supplies',
|
||||
'Stapler',
|
||||
'Staples',
|
||||
'Paper Clips',
|
||||
'Binder Clips',
|
||||
'Rubber Bands',
|
||||
'Envelopes',
|
||||
'Mailing Labels',
|
||||
'Address Labels',
|
||||
'Tape Dispenser',
|
||||
'Scissors',
|
||||
'Tape',
|
||||
'Glue',
|
||||
'Whiteboard',
|
||||
'Dry Erase Markers',
|
||||
'Corkboard',
|
||||
'Bulletin Board',
|
||||
'Push Pins',
|
||||
'Thumbtacks',
|
||||
'Desktop Organizer',
|
||||
'Calendar',
|
||||
'Planner',
|
||||
'Notebooks',
|
||||
'Legal Pads',
|
||||
'Notepads',
|
||||
'Ballpoint Pens',
|
||||
'Rollerball Pens',
|
||||
'Gel Pens',
|
||||
'Fountain Pens',
|
||||
'Highlighters',
|
||||
'Erasers',
|
||||
'Pencil Sharpeners',
|
||||
'Watercolor Paints',
|
||||
'Paintbrushes',
|
||||
'Easels',
|
||||
'Sketchbooks',
|
||||
'Drawing Paper',
|
||||
'Scrapbooking Supplies',
|
||||
'Craft Paper',
|
||||
'Craft Tools',
|
||||
'Origami Paper',
|
||||
'Calligraphy Supplies',
|
||||
'Printmaking Supplies',
|
||||
'Molding Clay',
|
||||
'Glazes',
|
||||
'Kiln',
|
||||
'Palette',
|
||||
'Canvas Boards',
|
||||
'Canvas Rolls',
|
||||
'Canvas Panels',
|
||||
'Stretched Canvas',
|
||||
'Oil Pastels',
|
||||
'Watercolor Pencils',
|
||||
'Pastel Paper',
|
||||
'Fixative Spray',
|
||||
'Eraser',
|
||||
'Pencil Sharpener',
|
||||
'Drawing Pens',
|
||||
'Calligraphy Set',
|
||||
'Ink Pens',
|
||||
'Sketching Charcoal',
|
||||
'Blending Stumps',
|
||||
'Watercolor Paper',
|
||||
'Watercolor Brushes',
|
||||
'Watercolor Palette',
|
||||
'Watercolor Mediums',
|
||||
'Watercolor Ground',
|
||||
'Watercolor Markers',
|
||||
'Acrylic Brushes',
|
||||
'Acrylic Mediums',
|
||||
'Palette Knives',
|
||||
'Gesso',
|
||||
'Acrylic Paper',
|
||||
'Airbrush Supplies',
|
||||
'Oil Brushes',
|
||||
'Oil Mediums',
|
||||
'Linseed Oil',
|
||||
'Turpentine',
|
||||
'Odorless Mineral Spirits',
|
||||
'Paper',
|
||||
'Drawing Ink',
|
||||
'Modeling Tools',
|
||||
'Pottery Brushes',
|
||||
'Throwing Bats',
|
||||
'Apron',
|
||||
'Wheel Throwing Kit',
|
||||
'Kiln Accessories',
|
||||
'Pottery Stamps',
|
||||
'Pottery Books',
|
||||
'Sculpting Tools',
|
||||
'Carving Tools',
|
||||
'Wood Carving Tools',
|
||||
'Stone Carving Tools',
|
||||
'Clay Sculpting Tools',
|
||||
'Pottery Tool Set',
|
||||
'Pottery Tool Kit',
|
||||
'Clay Extruder',
|
||||
'Pottery Rib Tools',
|
||||
'Sponge',
|
||||
'Kiln Furniture',
|
||||
'Pyrometer',
|
||||
'Kiln Shelves',
|
||||
'Kiln Posts',
|
||||
'Kiln Stilts',
|
||||
'Pottery Wire',
|
||||
'Ceramic Tiles',
|
||||
'Ceramic Glaze',
|
||||
'Raku Glaze',
|
||||
'Porcelain Glaze',
|
||||
'High-Fire Glaze',
|
||||
'Low-Fire Glaze',
|
||||
'Cone 6 Glaze',
|
||||
'Cone 10 Glaze',
|
||||
'Underglaze',
|
||||
'Slip',
|
||||
'Pottery Clay',
|
||||
'Clay Sculpture',
|
||||
'Pottery Figurines',
|
||||
'Pottery Mugs',
|
||||
'Pottery Bowls',
|
||||
'Pottery Plates',
|
||||
'Pottery Vases',
|
||||
'Pottery Teapots',
|
||||
'Pottery Platters',
|
||||
'Pottery Pitchers',
|
||||
'Pottery Planters',
|
||||
'Pottery Sculptures',
|
||||
'Pottery Wall Art',
|
||||
'Pottery Tiles',
|
||||
'Pottery Dinnerware',
|
||||
'Pottery Serveware',
|
||||
'Pottery Bakeware',
|
||||
'Pottery Home Decor',
|
||||
'Pottery Jewelry',
|
||||
'Pottery Kiln',
|
||||
'Ceramic Sculpture',
|
||||
'Ceramic Figurines',
|
||||
'Ceramic Mugs',
|
||||
'Ceramic Bowls',
|
||||
'Ceramic Plates',
|
||||
'Ceramic Vases',
|
||||
'Ceramic Teapots',
|
||||
'Ceramic Platters',
|
||||
'Ceramic Pitchers',
|
||||
'Ceramic Planters',
|
||||
'Ceramic Sculptures',
|
||||
'Ceramic Wall Art',
|
||||
'Ceramic Dinnerware',
|
||||
'Ceramic Serveware',
|
||||
'Ceramic Bakeware',
|
||||
'Ceramic Home Decor',
|
||||
'Ceramic Jewelry',
|
||||
'Ceramic Kiln',
|
||||
'Ceramic Wheel',
|
||||
'Pottery Glazes',
|
||||
'Pottery Wheels',
|
||||
'Modeling Clay'
|
||||
];
|
||||
prods.forEach(product => trie.add(product));
|
||||
expect(trie.getWords('air')).toEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Trie operations', () => {
|
||||
let trie: Trie;
|
||||
|
||||
beforeEach(() => {
|
||||
trie = new Trie();
|
||||
});
|
||||
|
||||
test('Add and Find Words', () => {
|
||||
trie.add('apple');
|
||||
trie.add('banana');
|
||||
expect(trie.has('apple')).toBe(true);
|
||||
expect(trie.has('banana')).toBe(true);
|
||||
expect(trie.has('cherry')).toBe(false);
|
||||
});
|
||||
|
||||
test('Remove Words', () => {
|
||||
trie.add('apple');
|
||||
trie.add('banana');
|
||||
expect(trie.remove('apple')).toBe(true);
|
||||
expect(trie.has('apple')).toBe(false);
|
||||
expect(trie.remove('cherry')).toBe(false);
|
||||
});
|
||||
|
||||
test('Case Sensitivity', () => {
|
||||
const caseInsensitiveTrie = new Trie(['apple', 'Banana'], false);
|
||||
expect(caseInsensitiveTrie.has('APPLE')).toBe(true);
|
||||
expect(caseInsensitiveTrie.has('banana')).toBe(true);
|
||||
expect(caseInsensitiveTrie.has('Cherry')).toBe(false);
|
||||
});
|
||||
|
||||
test('Pure Prefix Check', () => {
|
||||
trie.add('apple');
|
||||
expect(trie.hasPurePrefix('appl')).toBe(true);
|
||||
expect(trie.hasPurePrefix('apple')).toBe(false);
|
||||
});
|
||||
|
||||
test('Prefix Check', () => {
|
||||
trie.add('apple');
|
||||
expect(trie.hasPrefix('app')).toBe(true);
|
||||
expect(trie.hasPrefix('ban')).toBe(false);
|
||||
});
|
||||
|
||||
test('Common Prefix Check', () => {
|
||||
trie.add('apple');
|
||||
trie.add('appetizer');
|
||||
expect(trie.hasCommonPrefix('app')).toBe(true);
|
||||
expect(trie.hasCommonPrefix('apple')).toBe(false);
|
||||
});
|
||||
|
||||
test('Longest Common Prefix', () => {
|
||||
trie.add('apple');
|
||||
trie.add('appetizer');
|
||||
expect(trie.getLongestCommonPrefix()).toBe('app');
|
||||
});
|
||||
|
||||
test('Get Words by Prefix', () => {
|
||||
trie.add('apple');
|
||||
trie.add('appetizer');
|
||||
trie.add('banana');
|
||||
const words = trie.getWords('app', 2); // Get at most 2 words with the prefix 'app'
|
||||
expect(words).toEqual(['apple', 'appetizer']);
|
||||
});
|
||||
|
||||
test('Tree Height', () => {
|
||||
trie.add('apple');
|
||||
trie.add('banana');
|
||||
expect(trie.getHeight()).toBe(6); // Assuming 'apple' and 'banana' are the longest words.
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES6",
|
||||
"module": "ES6",
|
||||
"outDir": "./lib",
|
||||
"declaration": true,
|
||||
"module": "ES6",
|
||||
"target": "ES6",
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
|
@ -12,6 +12,7 @@
|
|||
"moduleResolution": "node",
|
||||
"skipLibCheck": true,
|
||||
"downlevelIteration": true,
|
||||
"removeComments": false,
|
||||
"experimentalDecorators": true,
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES5",
|
||||
"target": "ES6",
|
||||
"module": "CommonJS",
|
||||
"outDir": "./dist",
|
||||
"sourceMap": true,
|
||||
"declaration": true,
|
||||
"lib": [
|
||||
"ESNext"
|
||||
],
|
||||
"sourceMap": true,
|
||||
"strict": true,
|
||||
"downlevelIteration": true,
|
||||
"removeComments": true,
|
||||
"removeComments": false,
|
||||
"typeRoots": [
|
||||
"node_modules/@types"
|
||||
]
|
||||
|
|
Loading…
Reference in a new issue