-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTreeNode.ts
158 lines (140 loc) · 4.02 KB
/
TreeNode.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/**
* Represents a node in a tree structure.
*/
export class TreeNode<T> {
/**
* The value of the node.
*/
value: T
/**
* The children of the node.
*/
children: TreeNode<T>[]
/**
* The parent of the node.
*/
parent: TreeNode<T> | null
/**
* Creates a new TreeNode instance.
* @param value The value of the node.
* @param parent The parent of the node.
*/
constructor(value: T, parent: TreeNode<T> | null = null) {
this.value = value
this.children = []
this.parent = parent
}
/**
* Adds a child node to the current node.
* @param value The value of the child node.
* @returns The new child node.
*/
addChild(value: T): TreeNode<T> {
const newNode = new TreeNode(value, this)
this.children.push(newNode)
return newNode
}
/**
* Gets all nodes in the tree below the current node.
* @returns An array of TreeNode instances.
*/
all(): TreeNode<T>[] {
const nodes: TreeNode<T>[] = []
for (const value of this.children) {
nodes.push(value)
value.children && nodes.push(...value.all())
}
return nodes
}
/**
* Gets the path from the root node to the current node.
* @returns An array of TreeNode instances.
*/
getPath(): TreeNode<T>[] {
const path: TreeNode<T>[] = []
// eslint-disable-next-line @typescript-eslint/no-this-alias
let currentNode: TreeNode<T> | null = this
while (currentNode !== null) {
path.push(currentNode)
currentNode = currentNode.parent
}
return path.reverse()
}
/**
* Checks if the current node has any child nodes.
* @returns `true` if the node has children, `false` otherwise.
*/
hasChildren(): boolean {
return this.children.length > 0
}
/**
* Checks if the current node has any siblings.
* @returns `true` if the node has siblings, `false` otherwise.
*/
hasSiblings(): boolean {
return this.parent !== null && this.parent.children.length > 1
}
/**
* Checks if the current node is the root node.
* @returns `true` if the node is the root node, `false` otherwise.
*/
isRoot(): boolean {
return this.parent === null || this.parent === undefined
}
/**
* Removes the current node from the tree.
* @returns The new current node after removing the current node.
*/
remove(): TreeNode<T> | null {
if (this.parent) {
const parent = this.parent
const index = parent.children.indexOf(this)
if (index >= 0)
parent.children.splice(index, 1)
this.parent = null
return parent
}
else {
return null
}
}
/**
* Traverses the tree starting from the current node.
* @param callback A function to be called for each visited node.
* @param traversal `true` to traverse the tree in depth-first order, `false` for breadth-first order.
*/
traverse(callback: (node: TreeNode<T>) => void, traversal: 'breadthFirst' | 'depthFirst' | 'preOrder' | 'postOrder') {
if (!this)
return
if (traversal === 'preOrder') {
// Pre-order traversal: visit the current node, then traverse the left subtree, then traverse the right subtree
callback(this)
this.children.forEach(child => child.traverse(callback, traversal))
return
}
if (traversal === 'postOrder') {
// Post-order traversal: traverse the left subtree, then traverse the right subtree, then visit the current node
this.children.forEach(child => child.traverse(callback, traversal))
callback(this)
return
}
const collection: TreeNode<T>[] = []
collection.push(this)
while (collection.length > 0) {
let current: TreeNode<T>
if (traversal === 'depthFirst')
current = collection.pop()!
else
current = collection.shift()!
callback(current)
if (traversal === 'depthFirst') {
for (let i = current.children.length - 1; i >= 0; i--)
collection.push(current.children[i])
}
else {
for (const child of current.children)
collection.push(child)
}
}
}
}