fix: Fix the bug in the getCycles method. refactor: Rename some variables.

This commit is contained in:
Revone 2023-12-19 12:15:44 +08:00
parent 6ceaf21fba
commit bbfa64fc64
11 changed files with 301 additions and 165 deletions

View file

@ -156,10 +156,10 @@ export abstract class AbstractGraph<
addVertex(keyOrVertex: VertexKey | VO, value?: V): boolean {
if (keyOrVertex instanceof AbstractVertex) {
return this._addVertexOnly(keyOrVertex);
return this._addVertex(keyOrVertex);
} else {
const newVertex = this.createVertex(keyOrVertex, value);
return this._addVertexOnly(newVertex);
return this._addVertex(newVertex);
}
}
@ -242,14 +242,14 @@ export abstract class AbstractGraph<
addEdge(srcOrEdge: VO | VertexKey | EO, dest?: VO | VertexKey, weight?: number, value?: E): boolean {
if (srcOrEdge instanceof AbstractEdge) {
return this._addEdgeOnly(srcOrEdge);
return this._addEdge(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.key;
if (dest instanceof AbstractVertex) dest = dest.key;
const newEdge = this.createEdge(srcOrEdge, dest, weight, value);
return this._addEdgeOnly(newEdge);
return this._addEdge(newEdge);
} else {
throw new Error('dest must be a Vertex or vertex key while srcOrEdge is an Edge');
}
@ -1147,14 +1147,6 @@ export abstract class AbstractGraph<
return this.tarjan(false, false, false, false).lowMap;
}
/**
* The function `getCycles` returns a map of cycles found using the Tarjan algorithm.
* @returns The function `getCycles()` is returning a `Map<number, VO[]>`.
*/
getCycles(): Map<number, VO[]> {
return this.tarjan(false, false, false, true).cycles;
}
/**
* The function "getCutVertexes" returns an array of cut vertexes using the Tarjan algorithm.
* @returns an array of VO objects, specifically the cut vertexes.
@ -1180,6 +1172,55 @@ export abstract class AbstractGraph<
return this.tarjan(false, true, false, false).bridges;
}
/**
* O(V+E+C)
* O(V+C)
*/
getCycles(isInclude2Cycle: boolean = false): VertexKey[][] {
const cycles: VertexKey[][] = [];
const visited: Set<VO> = new Set();
const dfs = (vertex: VO, currentPath: VertexKey[], visited: Set<VO>) => {
if (visited.has(vertex)) {
if ((!isInclude2Cycle && currentPath.length > 2 || isInclude2Cycle && currentPath.length >= 2) && currentPath[0] === vertex.key) {
cycles.push([...currentPath]);
}
return;
}
visited.add(vertex);
currentPath.push(vertex.key);
for (const neighbor of this.getNeighbors(vertex)) {
neighbor && dfs(neighbor, currentPath, visited);
}
visited.delete(vertex);
currentPath.pop();
};
for (const vertex of this.vertexMap.values()) {
dfs(vertex, [], visited);
}
// Use a set to eliminate duplicate cycles
const uniqueCycles = new Map<string, VertexKey[]>();
for (const cycle of cycles) {
const sorted = [...cycle].sort().toString()
if (uniqueCycles.has(sorted)) continue
else {
uniqueCycles.set(sorted, cycle)
}
}
// Convert the unique cycles back to an array
return [...uniqueCycles].map(cycleString =>
cycleString[1]
);
}
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
@ -1247,9 +1288,9 @@ export abstract class AbstractGraph<
}
}
protected abstract _addEdgeOnly(edge: EO): boolean;
protected abstract _addEdge(edge: EO): boolean;
protected _addVertexOnly(newVertex: VO): boolean {
protected _addVertex(newVertex: VO): boolean {
if (this.hasVertex(newVertex)) {
return false;
// throw (new Error('Duplicated vertex key is not allowed'));

View file

@ -596,6 +596,7 @@ export class DirectedGraph<
}
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
@ -605,13 +606,13 @@ export class DirectedGraph<
* Time Complexity: O(1)
* Space Complexity: O(1)
*
* The function `_addEdgeOnly` adds an edge to a graph if the source and destination vertexMap exist.
* The function `_addEdge` adds an edge to a graph if the source and destination vertexMap exist.
* @param {EO} edge - The parameter `edge` is of type `EO`, which represents an edge in a graph. It is the edge that
* needs to be added to the graph.
* @returns a boolean value. It returns true if the edge was successfully added to the graph, and false if either the
* source or destination vertex does not exist in the graph.
*/
protected _addEdgeOnly(edge: EO): boolean {
protected _addEdge(edge: EO): boolean {
if (!(this.hasVertex(edge.src) && this.hasVertex(edge.dest))) {
return false;
}

View file

@ -381,7 +381,7 @@ export class UndirectedGraph<
* @param {EO} edge - The parameter "edge" is of type EO, which represents an edge in a graph.
* @returns a boolean value.
*/
protected _addEdgeOnly(edge: EO): boolean {
protected _addEdge(edge: EO): boolean {
for (const end of edge.vertexMap) {
const endVertex = this._getVertex(end);
if (endVertex === undefined) return false;

View file

@ -70,6 +70,38 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
* Space Complexity: O(n)
*/
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*
* The `get first` function returns the first node in a doubly linked list, or undefined if the list is empty.
* @returns The method `get first()` returns the first node of the doubly linked list, or `undefined` if the list is empty.
*/
get first(): E | undefined {
return this.head?.value;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*
* The `get last` function returns the last node in a doubly linked list, or undefined if the list is empty.
* @returns The method `get last()` returns the last node of the doubly linked list, or `undefined` if the list is empty.
*/
get last(): E | undefined {
return this.tail?.value;
}
/**
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n), where n is the size of the input array.
* Space Complexity: O(n)
@ -141,7 +173,7 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(1)
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
@ -168,7 +200,7 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(1)
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
@ -399,11 +431,6 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
return false;
}
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
@ -434,11 +461,6 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
return true;
}
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
@ -475,6 +497,11 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
return false;
}
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
/**
* The function checks if a variable has a size greater than zero and returns a boolean value.
* @returns A boolean value is being returned.
@ -483,6 +510,11 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
return this.size === 0;
}
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
/**
* The `clear` function resets the linked list by setting the head, tail, and size to undefined and 0 respectively.
*/
@ -548,7 +580,7 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
* Space Complexity: O(n)
*/
/**
@ -575,7 +607,7 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
* Space Complexity: O(n)
*/
/**
@ -596,7 +628,7 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Time Complexity: O(n)
* Space Complexity: O(n)
*/
@ -640,8 +672,8 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(n)
* Space Complexity: O(n)
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
@ -674,8 +706,8 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(n)
* Time Complexity: O(1)
* Space Complexity: O(1)
*/
/**
@ -740,7 +772,7 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(1)
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
@ -757,7 +789,7 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(1)
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
@ -773,38 +805,6 @@ export class DoublyLinkedList<E = any> extends IterableElementBase<E> {
this.unshift(value);
}
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*
* The `get first` function returns the first node in a doubly linked list, or undefined if the list is empty.
* @returns The method `get first()` returns the first node of the doubly linked list, or `undefined` if the list is empty.
*/
get first(): E | undefined {
return this.head?.value;
}
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*/
/**
* Time Complexity: O(n), where n is the number of elements in the linked list.
* Space Complexity: O(1)
*
* The `get last` function returns the last node in a doubly linked list, or undefined if the list is empty.
* @returns The method `get last()` returns the last node of the doubly linked list, or `undefined` if the list is empty.
*/
get last(): E | undefined {
return this.tail?.value;
}
/**
* The function returns an iterator that iterates over the values of a linked list.
*/

View file

@ -348,7 +348,7 @@ export class SinglyLinkedList<E = any> extends IterableElementBase<E> {
* @returns The `delete` method returns a boolean value. It returns `true` if the value or node is found and
* successfully deleted from the linked list, and `false` if the value or node is not found in the linked list.
*/
delete(valueOrNode: E | SinglyLinkedListNode<E> | undefined ): boolean {
delete(valueOrNode: E | SinglyLinkedListNode<E> | undefined): boolean {
if (!valueOrNode) return false;
let value: E;
if (valueOrNode instanceof SinglyLinkedListNode) {

View file

@ -57,6 +57,45 @@ export class SkipList<K, V> {
return this._probability;
}
/**
* Time Complexity: O(log n) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*/
/**
* Time Complexity: O(1) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*
* Get the value of the first element (the smallest element) in the Skip List.
* @returns The value of the first element, or undefined if the Skip List is empty.
*/
get first(): V | undefined {
const firstNode = this.head.forward[0];
return firstNode ? firstNode.value : undefined;
}
/**
* Time Complexity: O(log n) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*/
/**
* Time Complexity: O(log n) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*
* Get the value of the last element (the largest element) in the Skip List.
* @returns The value of the last element, or undefined if the Skip List is empty.
*/
get last(): V | undefined {
let current = this.head;
for (let i = this.level - 1; i >= 0; i--) {
while (current.forward[i]) {
current = current.forward[i];
}
}
return current.value;
}
/**
* Time Complexity: O(log n) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
@ -125,7 +164,7 @@ export class SkipList<K, V> {
}
/**
* Time Complexity: O(log n) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Time Complexity: O(1) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*/
@ -181,45 +220,6 @@ export class SkipList<K, V> {
return false;
}
/**
* Time Complexity: O(1) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*/
/**
* Time Complexity: O(1) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*
* Get the value of the first element (the smallest element) in the Skip List.
* @returns The value of the first element, or undefined if the Skip List is empty.
*/
get first(): V | undefined {
const firstNode = this.head.forward[0];
return firstNode ? firstNode.value : undefined;
}
/**
* Time Complexity: O(log n) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*/
/**
* Time Complexity: O(log n) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.
*
* Get the value of the last element (the largest element) in the Skip List.
* @returns The value of the last element, or undefined if the Skip List is empty.
*/
get last(): V | undefined {
let current = this.head;
for (let i = this.level - 1; i >= 0; i--) {
while (current.forward[i]) {
current = current.forward[i];
}
}
return current.value;
}
/**
* Time Complexity: O(log n) - where n is the number of elements in the SkipList, as it traverses the levels of the SkipList.
* Space Complexity: O(1) - constant space, as it uses a fixed amount of space regardless of the size of the SkipList.

View file

@ -49,6 +49,40 @@ export class Queue<E = any> extends IterableElementBase<E> {
return this.nodes.length - this.offset;
}
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*
* The `first` function returns the first element of the array `_nodes` if it exists, otherwise it returns `undefined`.
* @returns The `get first()` method returns the first element of the data structure, represented by the `_nodes` array at
* the `_offset` index. If the data structure is empty (size is 0), it returns `undefined`.
*/
get first(): E | undefined {
return this.size > 0 ? this.nodes[this.offset] : undefined;
}
/**
* Time Complexity: O(1) - constant time as it adds an element to the end of the array.
* Space Complexity: O(1) - no additional space is used.
*/
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*
* The `last` function returns the last element in an array-like data structure, or undefined if the structure is empty.
* @returns The method `get last()` returns the last element of the `_nodes` array if the array is not empty. If the
* array is empty, it returns `undefined`.
*/
get last(): E | undefined {
return this.size > 0 ? this.nodes[this.nodes.length - 1] : undefined;
}
/**
* Time Complexity: O(n) - where n is the number of elements in the queue. In the worst case, it may need to shift all elements to update the offset.
* Space Complexity: O(1) - no additional space is used.
*/
/**
* The function "fromArray" creates a new Queue object from an array of elements.Creates a queue from an existing array.
* @public
@ -62,7 +96,7 @@ export class Queue<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(1) - constant time as it adds an element to the end of the array.
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*/
@ -80,7 +114,7 @@ export class Queue<E = any> extends IterableElementBase<E> {
}
/**
* Time Complexity: O(n) - where n is the number of elements in the queue. In the worst case, it may need to shift all elements to update the offset.
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*/
@ -107,23 +141,6 @@ export class Queue<E = any> extends IterableElementBase<E> {
return first;
}
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*/
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*
* The `first` function returns the first element of the array `_nodes` if it exists, otherwise it returns `undefined`.
* @returns The `get first()` method returns the first element of the data structure, represented by the `_nodes` array at
* the `_offset` index. If the data structure is empty (size is 0), it returns `undefined`.
*/
get first(): E | undefined {
return this.size > 0 ? this.nodes[this.offset] : undefined;
}
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
@ -141,23 +158,6 @@ export class Queue<E = any> extends IterableElementBase<E> {
return this.first;
}
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*/
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
*
* The `last` function returns the last element in an array-like data structure, or undefined if the structure is empty.
* @returns The method `get last()` returns the last element of the `_nodes` array if the array is not empty. If the
* array is empty, it returns `undefined`.
*/
get last(): E | undefined {
return this.size > 0 ? this.nodes[this.nodes.length - 1] : undefined;
}
/**
* Time Complexity: O(1) - constant time as it retrieves the value at the current offset.
* Space Complexity: O(1) - no additional space is used.
@ -358,12 +358,20 @@ export class Queue<E = any> extends IterableElementBase<E> {
* 4. Frequent Enqueuing and Dequeuing Operations: If your application involves frequent enqueuing and dequeuing operations and is less concerned with random access, then LinkedListQueue is a good choice.
*/
export class LinkedListQueue<E = any> extends SinglyLinkedList<E> {
/**
* The `get first` function returns the value of the head node in a linked list, or `undefined` if the list is empty.
* @returns The `get first()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`.
*/
get first(): E | undefined {
return this.head?.value;
}
/**
* The enqueue function adds a value to the end of an array.
* @param {E} value - The value parameter represents the value that you want to add to the queue.
*/
enqueue(value: E): boolean {
return this.push(value);
return this.push(value);
}
/**
@ -374,14 +382,6 @@ export class LinkedListQueue<E = any> extends SinglyLinkedList<E> {
return this.shift();
}
/**
* The `get first` function returns the value of the head node in a linked list, or `undefined` if the list is empty.
* @returns The `get first()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`.
*/
get first(): E | undefined {
return this.head?.value;
}
/**
* The `peek` function returns the value of the head node in a linked list, or `undefined` if the list is empty.
* @returns The `peek()` method is returning the value of the `head` node if it exists, otherwise it returns `undefined`.

View file

@ -66,7 +66,7 @@ class MyGraph<
return edge ? undefined : undefined;
}
protected _addEdgeOnly(edge: EO): boolean {
protected _addEdge(edge: EO): boolean {
return edge ? true : true;
}
}

View file

@ -588,7 +588,7 @@ describe('cycles, strongly connected components, bridges, articular points in Di
const cutVertexes = graph.getCutVertexes();
const dfnMap = graph.getDFNMap();
const lowMap = graph.getLowMap();
expect(cycles.size).toBe(2);
expect(cycles.length).toBe(2);
expect(scCs.size).toBe(5);
expect(bridges.length).toBe(4);
expect(cutVertexes.length).toBe(4);
@ -688,8 +688,53 @@ describe('DirectedGraph getCycles', () => {
graph.addEdge('D', 'E');
graph.addEdge('E', 'B');
const cycles = graph.getCycles();
expect(cycles.size).toBe(1);
expect(cycles.get(2)).toEqual( [{ "key": "B", "value": undefined }, { "key": "D", "value": undefined }, { "key": "E", "value": undefined }]);
expect(cycles.length).toBe(1);
expect(cycles[0]).toEqual(["B", "D", "E"]);
})
test('should simple cycles graph getCycles return correct result', () => {
const graph = new DirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addEdge('A', 'B');
graph.addEdge('B', 'C');
graph.addEdge('C', 'A');
graph.addEdge('A', 'D');
graph.addEdge('D', 'C');
const cycles = graph.getCycles();
expect(cycles.length).toBe(2)
expect(cycles).toEqual([["A", "B", "C"], ["A", "D", "C"]])
});
test('should 3 cycles graph getCycles return correct result', () => {
const graph = new DirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addVertex('E');
graph.addVertex('F');
graph.addVertex('G');
graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('B', 'D');
graph.addEdge('C', 'D');
graph.addEdge('D', 'E');
graph.addEdge('E', 'B');
graph.addEdge('B', 'F');
graph.addEdge('F', 'E');
graph.addEdge('C', 'G');
graph.addEdge('G', 'A');
const cycles = graph.getCycles();
expect(cycles.length).toBe(3)
expect(cycles).toEqual([["A", "C", "G"], ["B", "D", "E"], ["B", "F", "E"]]);
});
})

View file

@ -237,7 +237,7 @@ describe('cycles, strongly connected components, bridges, articular points in Un
const cutVertexes = graph.getCutVertexes();
const dfnMap = graph.getDFNMap();
const lowMap = graph.getLowMap();
expect(cycles.size).toBe(2);
expect(cycles.length).toBe(3);
expect(scCs.size).toBe(5);
expect(bridges.length).toBe(4);
expect(cutVertexes.length).toBe(4);
@ -277,8 +277,52 @@ describe('UndirectedGraph getCycles', () => {
graph.addEdge('D', 'E');
graph.addEdge('E', 'B');
const cycles = graph.getCycles();
expect(cycles.size).toBe(2);
expect(cycles.get(1)).toEqual([{ "key": "A", "value": "A" }, { "key": "B", "value": "B" }, { "key": "D", "value": "D" }, { "key": "C", "value": "C" }]);
expect(cycles.get(2)).toEqual([{ "key": "B", "value": "B" }, { "key": "D", "value": "D" }, { "key": "E", "value": "E" }]);
expect(cycles.length).toBe(3);
expect(cycles).toEqual([["A", "B", "D", "C"], ["A", "B", "E", "D", "C"], ["B", "D", "E"]]);
})
test('should simple cycles graph getCycles return correct result', () => {
const graph = new UndirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addEdge('A', 'B');
graph.addEdge('B', 'C');
graph.addEdge('C', 'A');
graph.addEdge('A', 'D');
graph.addEdge('D', 'C');
const cycles = graph.getCycles();
expect(cycles.length).toBe(3)
expect(cycles).toEqual([["A", "B", "C"], ["A", "B", "C", "D"], ["A", "C", "D"]])
});
test('should 3 cycles graph getCycles return correct result', () => {
const graph = new UndirectedGraph();
graph.addVertex('A');
graph.addVertex('B');
graph.addVertex('C');
graph.addVertex('D');
graph.addVertex('E');
graph.addVertex('F');
graph.addVertex('G');
graph.addEdge('A', 'B');
graph.addEdge('A', 'C');
graph.addEdge('B', 'D');
graph.addEdge('C', 'D');
graph.addEdge('D', 'E');
graph.addEdge('E', 'B');
graph.addEdge('B', 'F');
graph.addEdge('F', 'E');
graph.addEdge('C', 'G');
graph.addEdge('G', 'A');
const cycles = graph.getCycles();
expect(cycles.length).toBe(10)
expect(cycles).toEqual([["A", "B", "D", "C"], ["A", "B", "D", "C", "G"], ["A", "B", "E", "D", "C"], ["A", "B", "E", "D", "C", "G"], ["A", "B", "F", "E", "D", "C"], ["A", "B", "F", "E", "D", "C", "G"], ["A", "C", "G"], ["B", "D", "E"], ["B", "D", "E", "F"], ["B", "E", "F"]]);
});
})

View file

@ -5,7 +5,12 @@ import { logBigOMetricsWrap } from '../../../utils';
describe('Heap Operation Test', () => {
it('should numeric heap work well', function () {
const minNumHeap = new MinHeap<number>();
minNumHeap.add(1);minNumHeap.add(6);minNumHeap.add(2);minNumHeap.add(0);minNumHeap.add(5);minNumHeap.add(9);
minNumHeap.add(1);
minNumHeap.add(6);
minNumHeap.add(2);
minNumHeap.add(0);
minNumHeap.add(5);
minNumHeap.add(9);
expect(minNumHeap.has(1)).toBe(true);
expect(minNumHeap.has(2)).toBe(true);
expect(minNumHeap.poll()).toBe(0);