{"id":17001396,"url":"https://github.com/alexaegis/avl","last_synced_at":"2026-04-09T02:32:09.120Z","repository":{"id":34199410,"uuid":"171386356","full_name":"AlexAegis/avl","owner":"AlexAegis","description":"Flexible AVL Tree for TypeScript","archived":false,"fork":false,"pushed_at":"2023-10-19T03:56:33.000Z","size":653,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-01-27T09:09:19.888Z","etag":null,"topics":["avl","avl-tree","data-structures","javascript","node","npm","npm-package","tree","typescript"],"latest_commit_sha":null,"homepage":"https://alexaegis.github.io/avl/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/AlexAegis.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":".github/contributing.md","funding":null,"license":null,"code_of_conduct":".github/code_of_conduct.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-02-19T01:55:34.000Z","updated_at":"2023-05-19T22:29:43.000Z","dependencies_parsed_at":"2024-11-28T18:32:36.488Z","dependency_job_id":"91bf676e-1767-47b6-bf44-f448c4d463e7","html_url":"https://github.com/AlexAegis/avl","commit_stats":{"total_commits":110,"total_committers":3,"mean_commits":"36.666666666666664","dds":0.09090909090909094,"last_synced_commit":"1dfca37b94a8309e8736b555c2bf62a070be2be1"},"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexAegis%2Favl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexAegis%2Favl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexAegis%2Favl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/AlexAegis%2Favl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/AlexAegis","download_url":"https://codeload.github.com/AlexAegis/avl/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":244931587,"owners_count":20534010,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["avl","avl-tree","data-structures","javascript","node","npm","npm-package","tree","typescript"],"created_at":"2024-10-14T04:24:50.438Z","updated_at":"2025-12-30T23:50:01.370Z","avatar_url":"https://github.com/AlexAegis.png","language":"TypeScript","readme":"# [AVL Tree](https://en.wikipedia.org/wiki/AVL_tree)\n\n[![Build Status](https://travis-ci.com/AlexAegis/avl.svg?branch=master)](https://travis-ci.com/AlexAegis/avl) [![npm (scoped)](https://img.shields.io/npm/v/@alexaegis/avl.svg?style=popout)](https://www.npmjs.com/package/@alexaegis/avl) [![Codacy Badge](https://api.codacy.com/project/badge/Grade/35d7fb5b31c9407094abf49fc445cc48)](https://www.codacy.com/app/AlexAegis/avl?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=AlexAegis/avl\u0026utm_campaign=Badge_Grade) [![Maintainability](https://api.codeclimate.com/v1/badges/35161dd7d57e3759381a/maintainability)](https://codeclimate.com/github/AlexAegis/avl/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/35161dd7d57e3759381a/test_coverage)](https://codeclimate.com/github/AlexAegis/avl/test_coverage) [![Known Vulnerabilities](https://snyk.io/test/github/AlexAegis/avl/badge.svg?targetFile=package.json)](https://snyk.io/test/github/AlexAegis/avl?targetFile=package.json) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier) [![Greenkeeper badge](https://badges.greenkeeper.io/AlexAegis/avl.svg)](https://greenkeeper.io/)\n\nFlexible [AVL Tree](./src/main/tree.class.ts) for TypeScript and JavaScript\n\n### Install with NPM\n\n```bash\nnpm i @alexaegis/avl\n```\n\n### Import and Create\n\n```TypeScript\nimport { Tree } from '@alexaegis/avl';\n\nconst tree = new Tree\u003cKey, Value\u003e(); // Create\ntree.set(key, value); // Set\nconst result: Value = tree.get(key) // Get\n```\n\n## Usage\n\nAlthough the typing does not enforce the key to have a `compareTo` method (to allow using any type of object as keys, not just what you created and have control over) The tree will throw runtime errors if it can't order the keys.\n\n\u003e The most basic case is that the key is a string or a number, then the value itself can be directly converted to a string or a number (Implicit or explicit, either having a `convertTo(): K` method on the objects prototyle or supply a converter function to the Tree object), and then if the key is an object it has to be comparable (Implicit or explicit, either having a `comparable(a: K, b: K): number` method on the objects prototype or supply a converter function to the Tree object)\n\n\u003e These functions you supply will al have their this value bound to the object the are getting applied on. For this reason if you want to use `this` in you `comparator` and/or `converter` methods use regular functions instead of lambdas.\n\n## Implicit keys - Comparable, Comparator\n\nif the object you are using as a key contains a compareTo(T) method then it will work just fine\n\n```TypeScript\nclass Key {\n\tconstructor(public key: number) {}\n}\nconst tree = new Tree\u003cKey, Value\u003e();\ntree.set(new Key(2), new Value(4)); // Cannot compare error\n```\n\n### Using a Comparable\n\n```TypeScript\nclass Key implements Comparable\u003cKey\u003e {\n\tconstructor(public key: number) {}\n\tcompareTo(other: Key): number {\n\t\treturn this.key - other.key;\n\t}\n}\nconst tree = new Tree\u003cKey, Value\u003e();\ntree.set(new Key(2), new Value(4)); // 👌 the key will be valid\n```\n\n### Using a Comparator\n\nVery important, if using a lambda as a comparator you cant use the `this` keyword in it (as usual),\nand the only type of comparator you can write is the 'two argumen' one as seen below.\nBut you can use this if you use a regular anonym function. This will act the same as the one you\nwould write while implementing the interface. There is an optional second argument here too, that's gonna be the same as a. But you don't need to use it.\n\n```TypeScript\nclass Key {\n\tconstructor(public key: number) {}\n}\n\nlet tree = new Tree\u003cKey, Value\u003e((a: Key, b: Key) =\u003e a.key - b.key); // Using Lambdas\n// Because of the fancy inner binding, you can even write this. It's basically the same\ntree = new Tree\u003cKey, Value\u003e(function (b: Key) { return this.key - b.key; });\n\ntree.set(new Key(2), new Value(4)); // 👌 the key will be valid\n```\n\n## Explicit keys - Convertable, Converter\n\n### Using a Convertable\n\n\u003e Only using Converters/Convertables allows the usage of the push method! You can even convert to a comparable!\n\n```TypeScript\nconst tree = new Tree\u003cValue\u003e();\ntree.push(new Value(4)); // Cannot convert error\n```\n\n```TypeScript\nexport class Value implements Convertable {\n    constructor(public n: number) {}\n\tconvertTo(): number | string {\n\t\treturn this.n;\n\t}\n}\n\nconst tree = new Tree\u003cValue\u003e();\ntree.push(new Value(4)); // 👌 the key will be 4\n\n```\n\n### Using a Converter\n\nAlternatively you can supply a function to act as the converter\n\n```TypeScript\nexport class Value {\n    constructor(public n: number) {}\n}\nexport class AnotherValue {\n    constructor(public n: number) {}\n}\n\nconst tree = new Tree\u003cnumber, Value\u003e(undefined, (val: Value) =\u003e val.n);\ntree.push(new Value(4));\ntree.push(new AnotherValue(1)); // You can do messy things like this without implementing a single interface\n\n```\n\n### Using a Convertable that converts to a Comparable\n\nThis is great when you have a bunch of objects you want to quickly access by keys that are encapsulated within the object.\n\n```TypeScript\nexport class Coord implements Comparable\u003cCoord\u003e {\n\tconstructor(public x: number = 0, public y: number = 0) {}\n\tcompareTo(other: Coord): number {\n\t\treturn this.y === other.y ? this.x - other.x : this.y - other.y;\n\t}\n}\n\nexport class BasicConvertableToComparable implements Convertable\u003cCoord\u003e {\n\tconstructor(private coord: Coord) {}\n\tconvertTo(): Coord {\n\t\treturn this.coord;\n\t}\n}\n\nconst tree: Tree\u003cCoord, BasicConvertableToComparable\u003e;\ntree.push(new BasicConvertableToComparable(new Coord(1, 1)));\ntree.get(new Coord(1, 1)); // The BasicConvertableToComparable object you pushed in\n\n```\n\n### Searching nearest values for missing keys\n\nYou can search for either nearest on left and nearest on right values if the one you search for might be missing.\n\n```typescript\nconst tree = new Tree\u003cnumber, number\u003e();\ntree.set(1, 1);\ntree.set(2, 2);\ntree.set(4, 4);\ntree.set(8, 8);\ntree.set(7, 7);\ntree.set(10, 10);\ntree.set(14, 14);\ntree.set(12, 12);\n\nconst last = tree.lastBefore(13.66); // 12\nconst first = tree.firstFrom(13.66); // 14\nconst enclosing = tree.enclosing(13.66); // {last: 12, first: 14}\n\n// When you might need the keys too\nconst lastNode = tree.lastNodeBefore(13.66); // Node {h: 1, k: 12, v: 12}\nconst firstNode = tree.firstNodeFrom(13.66); // Node {h: 2, k: 14, v: 14, …}\nconst enclosingNodes = tree.enclosingNodes(13.66); // Object {last: Node {h: 1, k: 12, v: 12}, first: Node {h: 2, k: 14, v: 14, …}}\n```\n\nFor more examples check the [mocha tests](./src/test/)\n\n---\n\n## Technologies\n\n### [Node 10](https://nodejs.org/en/)\n\n\u003e **JavaScript** runtime\n\n### [NPM](https://www.npmjs.com/)\n\n\u003e **Package manager** for Node\n\n### [TypeScript](https://www.typescriptlang.org/)\n\n\u003e **Typed superset** of JavaScript\n\n### [TSLint](https://palantir.github.io/tslint/)\n\n\u003e **Linting** tool\n\n### [Mocha](https://mochajs.org/)\n\n\u003e **Behaviour driven testing** framework\n\n### [Chai](https://www.chaijs.com/)\n\n\u003e **Assertion** library\n\n### [Istanbul](https://istanbul.js.org/)\n\n\u003e **Code coverage** tool\n\n## Recommendations\n\n### [Visual Studio Code](https://code.visualstudio.com/)\n\n\u003e **IDE** for everything. [Settings](./.vscode/)\n\n### [Fira Code](https://github.com/tonsky/FiraCode)\n\n\u003e **Font** with ligatures\n\n## Services\n\n### [Travis CI](https://travis-ci.com/)\n\n\u003e **Continuous Integration** solution\n\n### [Codacy](https://codacy.com/)\n\n\u003e **Code Quality** monitoring\n\n### [Code Climate](https://codeclimate.com/)\n\n\u003e **Maintainability and Coverage** reports\n\n### [Snyk](https://snyk.io/)\n\n\u003e **Vulnerability** detection\n\n### [Shields.io](https://shields.io/#/)\n\n\u003e **Badges** to look cool\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexaegis%2Favl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Falexaegis%2Favl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Falexaegis%2Favl/lists"}