Skip to content

Commit

Permalink
added breadth-first search and depth-first-search
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-jonathan committed Mar 24, 2024
1 parent 0a3767b commit f18aed2
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 19 deletions.
64 changes: 61 additions & 3 deletions __tests__/structures/Tree.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
} from 'vitest'

import {
logger,
guard,
} from '@cosmicmind/foundationjs'

Expand All @@ -53,7 +54,8 @@ import {
treeIsFirstChild,
treeIsLastChild,
treeIsOnlyChild,
treeIterator,
depthFirstIterator,
breadthFirstIterator,
treeQuery,
treeInsertChildBefore,
treeInsertChildAfter,
Expand Down Expand Up @@ -268,7 +270,7 @@ describe('Tree', () => {
expect(treeDepth(n7)).toBe(2)
})

it('treeIterator', () => {
it('depthFirstIterator', () => {
const n1 = createTreeEntry(1, 'a')
const n2 = createTreeEntry(2, 'b')
const n3 = createTreeEntry(3, 'c')
Expand All @@ -286,13 +288,69 @@ describe('Tree', () => {

const result: Tree[] = []

for (const n of treeIterator(n1)) {
for (const n of depthFirstIterator(n1)) {
result.push(n)
}

expect(result).toStrictEqual([ n1, n2, n6, n7, n3, n4, n5 ])
})

it('breadthFirstIterator', () => {
const n1 = createTreeEntry(1, 'a')
const n2 = createTreeEntry(2, 'b')
const n3 = createTreeEntry(3, 'c')
const n4 = createTreeEntry(4, 'd')
const n5 = createTreeEntry(5, 'e')
const n6 = createTreeEntry(6, 'f')
const n7 = createTreeEntry(7, 'g')
const n8 = createTreeEntry(8, 'h')
const n9 = createTreeEntry(9, 'i')
const n10 = createTreeEntry(10, 'j')
const n11 = createTreeEntry(11, 'k')
const n12 = createTreeEntry(12, 'l')
const n13 = createTreeEntry(13, 'm')
const n14 = createTreeEntry(14, 'n')
const n15 = createTreeEntry(15, 'o')
const n16 = createTreeEntry(16, 'p')
const n17 = createTreeEntry(17, 'q')
const n18 = createTreeEntry(18, 'r')
const n19 = createTreeEntry(19, 'j')

treeAppendChild(n1, n2)
treeAppendChild(n1, n3)
treeAppendChild(n1, n4)
treeAppendChild(n1, n5)

treeAppendChild(n2, n6)
treeAppendChild(n2, n7)

treeAppendChild(n3, n8)
treeAppendChild(n3, n9)
treeAppendChild(n3, n10)

treeAppendChild(n4, n11)
treeAppendChild(n4, n12)
treeAppendChild(n4, n13)

treeAppendChild(n5, n14)
treeAppendChild(n5, n15)

treeAppendChild(n10, n16)
treeAppendChild(n10, n17)

treeAppendChild(n11, n18)
treeAppendChild(n11, n19)


const result = []

for (const n of breadthFirstIterator(n1)) {
result.push(n.key)
}

expect(result).toStrictEqual([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 ])
})

it('treeQuery', () => {
const n1 = createTreeEntry(1, 'a')
const n2 = createTreeEntry(2, 'b')
Expand Down
50 changes: 34 additions & 16 deletions src/structures/Tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ import {
listRemove,
listInsertBefore,
listInsertAfter,
listIterateFromFirst,
listIterateFromFirst, listRemoveFirst,
} from '@/structures'

import {
Expand Down Expand Up @@ -128,8 +128,8 @@ export function treeRemove<T extends Tree>(node: T, compare = TreeCompareFn<T>):
/**
* @performance O(n)
*/
export const treeDepth = <T extends Tree>(node: T): ReturnType<typeof stackDepth> =>
stackDepth(node)
export const treeDepth = <T extends Tree>(root: T): ReturnType<typeof stackDepth> =>
stackDepth(root)

/**
* @performance O(1)
Expand Down Expand Up @@ -190,46 +190,64 @@ export function treeIsChildDeep<T extends Tree>(parent: T, node: T, compare = Tr
/**
* @performance O(n)
*/
export function treeIncreaseSize<T extends Tree>(node: T, size: number): void {
export function treeIncreaseSize<T extends Tree>(root: T, size: number): void {
assert(0 < size, 'size must be greater than 0')
for (const n of stackIterateFrom(node)) {
n.size += size
for (const node of stackIterateFrom(root)) {
node.size += size
}
}

/**
* @performance O(n)
*/
export function treeDecreaseSize<T extends Tree>(node: T, size: number): void {
export function treeDecreaseSize<T extends Tree>(root: T, size: number): void {
assert(0 < size, 'size must be greater than 0')
for (const n of stackIterateFrom(node)) {
for (const n of stackIterateFrom(root)) {
n.size -= size
}
}

/**
* @performance O(n)
*/
export function *treeIterator<T extends Tree>(node: T): IterableIterator<T> {
yield node
for (const n of listIterateFromFirst(node.children as List<T>)) {
yield *treeIterator(n)
export function *depthFirstIterator<T extends Tree>(root: T): IterableIterator<T> {
yield root
for (const n of listIterateFromFirst(root.children as List<T>)) {
yield *depthFirstIterator(n)
}
}

/**
* @performance O(n)
*/
export function treeQuery<T extends Tree>(node: T, ...fn: ((node: T) => boolean)[]): Set<T> {
export function *breadthFirstIterator<T extends Tree>(root: T): IterableIterator<T> {
const queue = listCreate<T>()
listAppend(queue, { ...root })

while (0 < queue.count) {
const node = listRemoveFirst(queue) as T

yield node

for (const q of listIterateFromFirst(node.children as List<T>)) {
listAppend(queue, { ...q })
}
}
}

/**
* @performance O(n)
*/
export function treeQuery<T extends Tree>(root: T, ...fn: ((node: T) => boolean)[]): Set<T> {
const r = new Set<T>()
loop: for (const n of treeIterator(node)) {
loop: for (const node of depthFirstIterator(root)) {
for (const f of fn) {
if (f(n)) {
if (f(node)) {
continue
}
continue loop
}
r.add(n)
r.add(node)
}
return r
}

0 comments on commit f18aed2

Please sign in to comment.