By constraining the necessity to implement the _createNode method, we ensure that the node types are correct within the subclass. The current design of the Graph needs further optimization.

This commit is contained in:
Revone 2023-08-22 08:58:42 +08:00
parent c1b5969c51
commit 1b441f1d47
39 changed files with 294 additions and 146 deletions

View file

@ -7,22 +7,17 @@
*/
import {BST, BSTNode} from './bst';
import type {AVLTreeDeleted, BinaryTreeNodeId} from '../types';
import {IBinaryTreeNode} from '../interfaces';
export class AVLTreeNode<T> extends BSTNode<T> {
/**
* The function overrides the clone method of the AVLTreeNode class to create a new AVLTreeNode object with the same
* id, value, and count.
* @returns The method is returning a new instance of the AVLTreeNode class with the same id, val, and count values as
* the current instance.
*/
override clone(): AVLTreeNode<T> {
return new AVLTreeNode<T>(this.id, this.val, this.count);
export class AVLTreeNode<T> extends BSTNode<T> implements IBinaryTreeNode<T> {
override _createNode(id: BinaryTreeNodeId, val: T | null, count?: number): AVLTreeNode<T> | null {
return val !== null ? new AVLTreeNode<T>(id, val, count) : null;
}
}
export class AVLTree<T> extends BST<T> {
override createNode(id: BinaryTreeNodeId, val: T, count?: number): AVLTreeNode<T> {
override _createNode(id: BinaryTreeNodeId, val: T, count?: number): AVLTreeNode<T> {
return new AVLTreeNode<T>(id, val, count);
}

View file

@ -16,6 +16,7 @@ import type {
ResultByProperty,
ResultsByProperty
} from '../types';
import {IBinaryTree, IBinaryTreeNode} from '../interfaces';
/* 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, left, right}
@ -28,7 +29,7 @@ export enum FamilyPosition {root, left, right}
*/
export enum LoopType { iterative = 1, recursive = 2}
export class BinaryTreeNode<T> {
export class BinaryTreeNode<T> implements IBinaryTreeNode<T> {
constructor(id: BinaryTreeNodeId, val: T, count?: number) {
this._id = id;
@ -47,6 +48,7 @@ export class BinaryTreeNode<T> {
}
private _val: T;
get val(): T {
return this._val;
}
@ -123,31 +125,37 @@ export class BinaryTreeNode<T> {
this._height = v;
}
_createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BinaryTreeNode<T> | null {
return val !== null ? new BinaryTreeNode<T>(id, val, count) : null;
}
swapLocation(swapNode: BinaryTreeNode<T>): BinaryTreeNode<T> {
const {val, count, height} = swapNode;
const tempNode = new BinaryTreeNode<T>(swapNode.id, val);
tempNode.val = val;
tempNode.count = count;
tempNode.height = height;
const tempNode = this._createNode(swapNode.id, val);
if (tempNode instanceof BinaryTreeNode) {
tempNode.val = val;
tempNode.count = count;
tempNode.height = height;
swapNode.id = this.id;
swapNode.val = this.val;
swapNode.count = this.count;
swapNode.height = this.height;
swapNode.id = this.id;
swapNode.val = this.val;
swapNode.count = this.count;
swapNode.height = this.height;
this.id = tempNode.id;
this.val = tempNode.val;
this.count = tempNode.count;
this.height = tempNode.height;
this.id = tempNode.id;
this.val = tempNode.val;
this.count = tempNode.count;
this.height = tempNode.height;
}
return swapNode;
}
clone(): BinaryTreeNode<T> {
return new BinaryTreeNode<T>(this.id, this.val, this.count);
clone(): BinaryTreeNode<T> | null {
return this._createNode(this.id, this.val, this.count);
}
}
export class BinaryTree<T> {
export class BinaryTree<T> implements IBinaryTree<T> {
/**
* The constructor function accepts an optional options object and sets the values of loopType, autoIncrementId, and
@ -243,19 +251,18 @@ export class BinaryTree<T> {
}
/**
* The function creates a new binary tree node with the given id, value, and count, or returns null if the value is
* null.
* The function creates a new binary tree node with the given id, value, and count if the value is not null, otherwise
* it returns null.
* @param {BinaryTreeNodeId} id - The `id` parameter is the identifier for the binary tree node. It is of type
* `BinaryTreeNodeId`, which could be a string or a number, depending on how you want to identify your nodes.
* @param {T | null} val - The `val` parameter represents the value to be stored in the binary tree node. It can be of
* any type `T` or `null`.
* @param {number} [count] - The count parameter is an optional parameter that represents the number of occurrences of
* the value in the binary tree node. It is of type number.
* @returns The function `createNode` returns a `BinaryTreeNode<T>` object if the `val` parameter is not null.
* Otherwise, it returns null.
* `BinaryTreeNodeId`.
* @param {T | null} val - The `val` parameter represents the value of the node. It can be of type `T` (generic type)
* or `null`.
* @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 tree node. If not provided, the default value is `undefined`.
* @returns a BinaryTreeNode object if the value is not null, otherwise it returns null.
*/
createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BinaryTreeNode<T> | null {
return val !== null ? new BinaryTreeNode(id, val, count) : null;
_createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BinaryTreeNode<T> | null {
return val !== null ? new BinaryTreeNode<T>(id, val, count) : null;
}
/**
@ -305,7 +312,7 @@ export class BinaryTree<T> {
};
let inserted: BinaryTreeNode<T> | null | undefined;
const needInsert = val !== null ? new BinaryTreeNode<T>(id, val, count) : null;
const needInsert = val !== null ? this._createNode(id, val, count) : null;
const existNode = val !== null ? this.get(id, 'id') : null;
if (this.root) {
if (existNode) {
@ -319,7 +326,7 @@ export class BinaryTree<T> {
inserted = _bfs(this.root, needInsert);
}
} else {
this._setRoot(val !== null ? new BinaryTreeNode<T>(id, val, count) : null);
this._setRoot(val !== null ? this._createNode(id, val, count) : null);
if (needInsert !== null) {
this._setSize(1);
this._setCount(count);

View file

@ -7,16 +7,17 @@
*/
import type {BinaryTreeNodeId, BinaryTreeNodePropertyName, BSTComparator, BSTDeletedResult} from '../types';
import {BinaryTree, BinaryTreeNode, FamilyPosition, LoopType,} from './binary-tree';
import {IBinaryTree, IBinaryTreeNode} from '../interfaces';
export enum CP {lt = -1, eq = 0, gt = 1}
export class BSTNode<T> extends BinaryTreeNode<T> {
override clone(): BSTNode<T> {
return new BSTNode<T>(this.id, this.val, this.count);
export class BSTNode<T> extends BinaryTreeNode<T> implements IBinaryTreeNode<T> {
override _createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BSTNode<T> | null {
return val !== null ? new BSTNode<T>(id, val, count) : null;
}
}
export class BST<T> extends BinaryTree<T> {
export class BST<T> extends BinaryTree<T> implements IBinaryTree<T> {
/**
* The constructor function accepts an optional options object and sets the comparator property if provided.
* @param [options] - An optional object that can contain the following properties:
@ -34,7 +35,7 @@ export class BST<T> extends BinaryTree<T> {
}
}
override createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BSTNode<T> | null {
override _createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BSTNode<T> | null {
return val !== null ? new BSTNode<T>(id, val, count) : null;
}
@ -52,7 +53,7 @@ export class BST<T> extends BinaryTree<T> {
*/
override add(id: BinaryTreeNodeId, val: T | null, count: number = 1): BSTNode<T> | null {
let inserted: BSTNode<T> | null = null;
const newNode = this.createNode(id, val, count);
const newNode = this._createNode(id, val, count);
if (this.root === null) {
this._setRoot(newNode);
this._setSize(this.size + 1);

View file

@ -1,3 +1,110 @@
export class RBTree {
import {BinaryTree, BinaryTreeNode, LoopType} from './binary-tree';
import {IBinaryTree, IBinaryTreeNode} from '../interfaces';
enum RBColor { Red, Black }
class RBNode<T> extends BinaryTreeNode<T> implements IBinaryTreeNode<T> {
// override createNode(id: BinaryTreeNodeId, val: T | null, count?: number): RBNode<T> | null {
// return val !== null ? new RBNode<T>(id, val, count) : null;
// }
constructor(id: number, val: T, count?: number) {
super(id, val, count);
}
private _color: RBColor = RBColor.Red;
get color(): RBColor {
return this._color;
}
set color(value: RBColor) {
this._color = value;
}
// private override _parent: RBNode<T> | null;
// override set parent(v: RBNode<T> | null) {
// this._parent = v;
// }
// override get parent(): RBNode<T> | null {
// return this._parent;
// }
// private override _left?: RBNode<T> | null;
//
// override get left(): RBNode<T> | null | undefined {
// return this._left;
// }
//
// override set left(v: RBNode<T> | null | undefined) {
// if (v) {
// v.parent = this;
// v.familyPosition = FamilyPosition.left;
// }
// this._left = v;
// }
//
// private override _right?: RBNode<T> | null;
//
// override get right(): RBNode<T> | null | undefined {
// return this._right;
// }
//
// override set right(v: RBNode<T> | null | undefined) {
// if (v) {
// v.parent = this;
// v.familyPosition = FamilyPosition.right;
// }
// this._right = v;
// }
}
class RBTree<T> extends BinaryTree<T> implements IBinaryTree<T> {
constructor(options?: {
loopType?: LoopType,
autoIncrementId?: boolean,
isDuplicatedVal?: boolean
}) {
super(options);
}
// override _createNode(id: BinaryTreeNodeId, val: T | null, count?: number): RBNode<T> | null {
// return val !== null ? new RBNode<T>(id, val, count) : null;
// }
// private override _root: BinaryTreeNode<T> | null = null;
//
// override get root(): BinaryTreeNode<T> | null {
// return this._root;
// }
insert(id: number, val: T | null) {
}
private leftRotate(node: RBNode<T>) {
}
private rightRotate(node: RBNode<T>) {
}
private insertFixup(node: RBNode<T>) {
}
private deleteFixup(node: RBNode<T>) {
}
private transplant(u: RBNode<T>, v: RBNode<T>) {
}
// override remove(id: BinaryTreeNodeId, ignoreCount?: boolean): BinaryTreeDeleted<T>[] {
//
// return [{deleted: new RBNode<T>(0, 0), needBalanced: null}];
// }
}

View file

@ -7,8 +7,9 @@
*/
import {BST, BSTNode} from './bst';
import type {BinaryTreeNodeId, TreeMultiSetDeletedResult} from '../types';
import {IBinaryTree} from '../interfaces';
export class TreeMultiSet<T> extends BST<T> {
export class TreeMultiSet<T> extends BST<T> implements IBinaryTree<T> {
/**
* 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
@ -18,7 +19,7 @@ export class TreeMultiSet<T> extends BST<T> {
* 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).
*/
override createNode(id: BinaryTreeNodeId, val: T, count?: number): BSTNode<T> {
override _createNode(id: BinaryTreeNodeId, val: T, count?: number): BSTNode<T> {
return new BSTNode<T>(id, val, count);
}

View file

@ -7,7 +7,8 @@
*/
import {arrayRemove, uuidV4} from '../../utils';
import {PriorityQueue} from '../priority-queue';
import type {DijkstraResult, IGraph, VertexId} from '../types';
import type {DijkstraResult, VertexId} from '../types';
import {IGraph} from '../interfaces';
export class AbstractVertex {
constructor(id: VertexId) {
@ -389,7 +390,7 @@ export abstract class AbstractGraph<V extends AbstractVertex, E extends Abstract
* @returns The function `dijkstraWithoutHeap` returns an object of type `DijkstraResult<V>`.
*/
dijkstraWithoutHeap(src: V | VertexId, dest?: V | VertexId | null, getMinDist?: boolean, genPaths?: boolean): DijkstraResult<V> {
if (getMinDist === undefined) getMinDist = false ;
if (getMinDist === undefined) getMinDist = false;
if (genPaths === undefined) genPaths = false;
if (dest === undefined) dest = null;

View file

@ -7,7 +7,8 @@
*/
import {arrayRemove} from '../../utils';
import {AbstractEdge, AbstractGraph, AbstractVertex} from './abstract-graph';
import type {IDirectedGraph, TopologicalStatus, VertexId} from '../types';
import type {TopologicalStatus, VertexId} from '../types';
import {IDirectedGraph} from '../interfaces';
export class DirectedVertex extends AbstractVertex {
/**

View file

@ -5,7 +5,7 @@
* @copyright Copyright (c) 2022 Tyler Zeng <zrwusa@gmail.com>
* @license MIT License
*/
export class CoordinateSet extends Set {
export class CoordinateSet extends Set<any> {
constructor(joint?: string) {
super();
if (joint !== undefined) this._joint = joint;

View file

@ -9,6 +9,7 @@ export * from './heap';
export * from './priority-queue';
export * from './matrix';
export * from './trie';
export * from './interfaces';
export * from './types';

View file

@ -0,0 +1,40 @@
import {VertexId} from '../types';
export interface IGraph<V, E> {
hasVertex(vertexOrId: V | VertexId): boolean;
getVertex(vertexOrId: VertexId | V): V | null;
getVertexId(vertexOrId: V | VertexId): VertexId;
vertexSet(): Map<VertexId, V>;
addVertex(v: 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(edge: E): boolean;
removeEdgeBetween(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
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[];
}

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1,10 @@
import {BinaryTreeNodeId} from '../types';
import {BinaryTreeNode} from '../binary-tree';
export interface IBinaryTreeNode<T> {
_createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BinaryTreeNode<T> | null
}
export interface IBinaryTree<T> {
_createNode(id: BinaryTreeNodeId, val: T | null, count?: number): BinaryTreeNode<T> | null
}

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1,15 @@
import {VertexId} from '../types';
export interface IDirectedGraph<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;
}

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1,13 @@
export * from './binary-tree';
export * from './bst';
export * from './avl-tree';
export * from './segment-tree';
export * from './tree-multiset';
export * from './abstract-graph';
export * from './directed-graph';
export * from './undirected-graph';
export * from './priority-queue';
export * from './heap';
export * from './singly-linked-list';
export * from './doubly-linked-list';
export * from './navigator';

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1 @@
export {}

View file

@ -0,0 +1,3 @@
export interface IUNDirectedGraph<V, E> {
}

View file

@ -49,7 +49,7 @@ export class DoublyLinkedListNode<T = number> {
}
}
export class DoublyLinkedList<T> {
export class DoublyLinkedList<T = number> {
/**
* The constructor initializes the linked list with an empty head, tail, and length.

View file

@ -38,7 +38,7 @@ export class SinglyLinkedListNode<T = number> {
}
}
export class SinglyLinkedList<T> {
export class SinglyLinkedList<T = number> {
/**
* The constructor initializes the linked list with an empty head, tail, and length.

View file

@ -6,7 +6,8 @@
* @license MIT License
*/
import {PriorityQueue} from './priority-queue';
import type {PriorityQueueOptions, SpecifyOptional} from '../types';
import type {PriorityQueueOptions} from '../types';
import {SpecifyOptional} from '../../utils';
export class MaxPriorityQueue<T = number> extends PriorityQueue<T> {
constructor(options?: Omit<PriorityQueueOptions<number>, 'comparator'>)

View file

@ -6,7 +6,8 @@
* @license MIT License
*/
import {PriorityQueue} from './priority-queue';
import type {PriorityQueueOptions, SpecifyOptional} from '../types';
import type {PriorityQueueOptions} from '../types';
import {SpecifyOptional} from '../../utils';
export class MinPriorityQueue<T = number> extends PriorityQueue<T> {
constructor(options?: Omit<PriorityQueueOptions<number>, 'comparator'>)

View file

@ -30,10 +30,6 @@ export class PriorityQueue<T = number> {
return this._nodes;
}
protected set nodes(value: T[]) {
this._nodes = value;
}
get size(): number {
return this.nodes.length;
}
@ -137,7 +133,7 @@ export class PriorityQueue<T = number> {
* The clear function clears the nodes array.
*/
clear() {
this.nodes = [];
this._setNodes([]);
}
/**
@ -231,6 +227,10 @@ export class PriorityQueue<T = number> {
return visitedNode;
}
protected _setNodes(value: T[]) {
this._nodes = value;
}
protected readonly _comparator: PriorityQueueComparator<T> = (a: T, b: T) => {
const aKey = a as unknown as number, bKey = b as unknown as number;
return aKey - bKey;

View file

@ -16,7 +16,7 @@ export class Deque<T> extends DoublyLinkedList<T> {
// O(1) time complexity of obtaining the value
// O(n) time complexity of adding at the beginning and the end
// todo tested slowest one
export class ObjectDeque<T> {
export class ObjectDeque<T = number> {
constructor(capacity?: number) {
if (capacity !== undefined) this._capacity = capacity;
}
@ -27,10 +27,6 @@ export class ObjectDeque<T> {
return this._nodes;
}
protected set nodes(value: { [p: number]: T }) {
this._nodes = value;
}
private _capacity = Number.MAX_SAFE_INTEGER;
get capacity(): number {
@ -67,10 +63,6 @@ export class ObjectDeque<T> {
return this._size;
}
protected set size(value: number) {
this._size = value;
}
addFirst(value: T) {
if (this._size === 0) {
const mid = Math.floor(this._capacity / 2);
@ -129,6 +121,14 @@ export class ObjectDeque<T> {
isEmpty() {
return this._size <= 0;
}
protected _seNodes(value: { [p: number]: T }) {
this._nodes = value;
}
protected _setSize(value: number) {
this._size = value;
}
}
// O(1) time complexity of obtaining the value

View file

@ -3,7 +3,7 @@
* @copyright Tyler Zeng <zrwusa@gmail.com>
* @class
*/
export class Queue<T> {
export class Queue<T = number> {
protected _nodes: T[];
protected _offset: number;

View file

@ -3,7 +3,7 @@
* @copyright Tyler Zeng <zrwusa@gmail.com>
* @class
*/
export class Stack<T> {
export class Stack<T = number> {
protected _elements: T[];
/**

View file

@ -2,50 +2,3 @@ export type VertexId = string | number;
export type DijkstraResult<V> =
{ distMap: Map<V, number>, preMap: Map<V, V | null>, seen: Set<V>, paths: V[][], minDist: number, minPath: V[] }
| null;
export interface IGraph<V, E> {
hasVertex(vertexOrId: V | VertexId): boolean;
getVertex(vertexOrId: VertexId | V): V | null;
getVertexId(vertexOrId: V | VertexId): VertexId;
vertexSet(): Map<VertexId, V>;
addVertex(v: 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;
// hasEdge(e: E): boolean;
getEdge(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
// getAllEdges(src: V, dest: V): E[];
edgeSet(): E[];
addEdge(edge: E): boolean;
removeEdgeBetween(srcOrId: V | VertexId, destOrId: V | VertexId): E | null;
removeEdge(edge: E): E | null;
// removeAllEdges(v1: VertexId | V, v2: VertexId | V): (E | null)[];
// removeAllEdges(edges: E[] | [VertexId, VertexId]): boolean;
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[];
}

View file

@ -1,6 +1,6 @@
import {AVLTreeNode} from '../binary-tree';
export interface AVLTreeDeleted<T> {
export type AVLTreeDeleted<T> = {
deleted: AVLTreeNode<T> | null;
needBalanced: AVLTreeNode<T> | null;
}

View file

@ -1,18 +1,8 @@
import {VertexId} from './abstract-graph';
export interface IDirectedGraph<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;
}
// 0 means unknown, 1 means visiting, 2 means visited;
export type TopologicalStatus = 0 | 1 | 2;
export type TopologicalStatus = 0 | 1 | 2;
export enum TopologicalProperty {
VAL = 'VAL',
NODE = 'NODE',
ID = 'ID',
}

View file

@ -1,4 +1,4 @@
export interface HeapOptions<T> {
export type HeapOptions<T> = {
priority?: (element: T) => number;
// TODO there is an idea that support chaining which is for conveniently using the data structure
// isChaining? : boolean

View file

@ -9,5 +9,4 @@ export * from './priority-queue';
export * from './heap';
export * from './singly-linked-list';
export * from './doubly-linked-list';
export * from './navigator';
export * from '../../utils/types/utils';
export * from './navigator';

View file

@ -1,7 +1,7 @@
export type Direction = 'up' | 'right' | 'down' | 'left';
export type Turning = { [key in Direction]: Direction };
export interface NavigatorParams<T> {
export type NavigatorParams<T> = {
matrix: T[][],
turning: Turning,
onMove: (cur: [number, number]) => void

View file

@ -1,6 +1,6 @@
export type PriorityQueueComparator<T> = (a: T, b: T) => number;
export interface PriorityQueueOptions<T> {
export type PriorityQueueOptions<T> = {
nodes?: T[];
isFix?: boolean;
comparator: PriorityQueueComparator<T>;

View file

@ -59,7 +59,7 @@ describe('DirectedGraph Operation Test', () => {
graph.addEdge(edgeBC);
const topologicalOrder = graph.topologicalSort();
if (topologicalOrder) expect(topologicalOrder.map(v => v.id)).toEqual(['A', 'B', 'C']);
if (topologicalOrder) expect(topologicalOrder.map(v => v instanceof DirectedVertex ? v.id: '')).toEqual(['A', 'B', 'C']);
});
});
@ -168,9 +168,9 @@ describe('DirectedGraph Test2 operations', () => {
expect(sorted).toBeInstanceOf(Array);
if (sorted && sorted.length > 0) {
expect(sorted.length).toBe(9);
expect(sorted[0].data).toBe('data9');
expect(sorted[3].data).toBe('data6');
expect(sorted[8].id).toBe(1);
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);
}
});