@no-k/hermes 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +15 -0
- package/README.md +88 -0
- package/bin/hermes.mjs +159 -0
- package/catalog.json +1084 -0
- package/lib/catalog.mjs +51 -0
- package/package.json +28 -0
- package/templates/algorithm/geometry/ccw/ccw.ts +25 -0
- package/templates/algorithm/geometry/ccw/index.ts +1 -0
- package/templates/algorithm/geometry/convex-hull/convex-hull.ts +43 -0
- package/templates/algorithm/geometry/convex-hull/index.ts +1 -0
- package/templates/algorithm/geometry/polygon-area/index.ts +1 -0
- package/templates/algorithm/geometry/polygon-area/polygon-area.ts +13 -0
- package/templates/algorithm/graph/bellman-ford/bellman-ford.ts +46 -0
- package/templates/algorithm/graph/bellman-ford/index.ts +1 -0
- package/templates/algorithm/graph/bfs/bfs.ts +21 -0
- package/templates/algorithm/graph/bfs/index.ts +1 -0
- package/templates/algorithm/graph/dfs/dfs.ts +22 -0
- package/templates/algorithm/graph/dfs/index.ts +1 -0
- package/templates/algorithm/graph/dijkstra/dijkstra.ts +37 -0
- package/templates/algorithm/graph/dijkstra/index.ts +1 -0
- package/templates/algorithm/graph/floyd-warshall/floyd-warshall.ts +17 -0
- package/templates/algorithm/graph/floyd-warshall/index.ts +1 -0
- package/templates/algorithm/graph/kruskal/index.ts +1 -0
- package/templates/algorithm/graph/kruskal/kruskal.ts +29 -0
- package/templates/algorithm/graph/prim/index.ts +1 -0
- package/templates/algorithm/graph/prim/prim.ts +44 -0
- package/templates/algorithm/graph/topology-sort/index.ts +1 -0
- package/templates/algorithm/graph/topology-sort/topology-sort.ts +31 -0
- package/templates/algorithm/search/binary-search/binary-search.ts +74 -0
- package/templates/algorithm/search/binary-search/index.ts +1 -0
- package/templates/algorithm/string/kmp/index.ts +1 -0
- package/templates/algorithm/string/kmp/kmp.ts +46 -0
- package/templates/algorithm/string/z-algorithm/index.ts +1 -0
- package/templates/algorithm/string/z-algorithm/z-algorithm.ts +41 -0
- package/templates/algorithm/tree/avl-tree/avl-tree.ts +197 -0
- package/templates/algorithm/tree/avl-tree/index.ts +1 -0
- package/templates/algorithm/tree/binary-search-tree/binary-search-tree.ts +144 -0
- package/templates/algorithm/tree/binary-search-tree/index.ts +1 -0
- package/templates/algorithm/tree/lca/index.ts +1 -0
- package/templates/algorithm/tree/lca/lca.ts +119 -0
- package/templates/array/chunk/chunk.ts +13 -0
- package/templates/array/chunk/index.ts +1 -0
- package/templates/array/compact/compact.ts +8 -0
- package/templates/array/compact/index.ts +1 -0
- package/templates/array/count-by/count-by.ts +12 -0
- package/templates/array/count-by/index.ts +1 -0
- package/templates/array/difference/difference.ts +6 -0
- package/templates/array/difference/index.ts +1 -0
- package/templates/array/drop/drop.ts +7 -0
- package/templates/array/drop/index.ts +1 -0
- package/templates/array/group-by/group-by.ts +18 -0
- package/templates/array/group-by/index.ts +1 -0
- package/templates/array/intersection/index.ts +1 -0
- package/templates/array/intersection/intersection.ts +15 -0
- package/templates/array/key-by/index.ts +1 -0
- package/templates/array/key-by/key-by.ts +11 -0
- package/templates/array/max-by/index.ts +1 -0
- package/templates/array/max-by/max-by.ts +20 -0
- package/templates/array/min-by/index.ts +1 -0
- package/templates/array/min-by/min-by.ts +20 -0
- package/templates/array/partition/index.ts +1 -0
- package/templates/array/partition/partition.ts +16 -0
- package/templates/array/range/index.ts +1 -0
- package/templates/array/range/range.ts +22 -0
- package/templates/array/sample/index.ts +1 -0
- package/templates/array/sample/sample.ts +10 -0
- package/templates/array/shuffle/index.ts +1 -0
- package/templates/array/shuffle/shuffle.ts +15 -0
- package/templates/array/sort-by/index.ts +1 -0
- package/templates/array/sort-by/sort-by.ts +32 -0
- package/templates/array/sum-by/index.ts +1 -0
- package/templates/array/sum-by/sum-by.ts +9 -0
- package/templates/array/take/index.ts +1 -0
- package/templates/array/take/take.ts +7 -0
- package/templates/array/union/index.ts +1 -0
- package/templates/array/union/union.ts +5 -0
- package/templates/array/unique/index.ts +1 -0
- package/templates/array/unique/unique.ts +5 -0
- package/templates/array/unique-by/index.ts +1 -0
- package/templates/array/unique-by/unique-by.ts +19 -0
- package/templates/array/windowed/index.ts +1 -0
- package/templates/array/windowed/windowed.ts +15 -0
- package/templates/array/zip/index.ts +1 -0
- package/templates/array/zip/zip.ts +11 -0
- package/templates/boolean/parse-boolean/index.ts +1 -0
- package/templates/boolean/parse-boolean/parse-boolean.ts +17 -0
- package/templates/boolean/toggle/index.ts +1 -0
- package/templates/boolean/toggle/toggle.ts +2 -0
- package/templates/boolean/xor/index.ts +1 -0
- package/templates/boolean/xor/xor.ts +2 -0
- package/templates/data-structure/deque/deque.ts +79 -0
- package/templates/data-structure/deque/index.ts +1 -0
- package/templates/data-structure/fenwick-tree/fenwick-tree.ts +76 -0
- package/templates/data-structure/fenwick-tree/index.ts +1 -0
- package/templates/data-structure/heap/heap.ts +88 -0
- package/templates/data-structure/heap/index.ts +3 -0
- package/templates/data-structure/heap/max-heap.ts +7 -0
- package/templates/data-structure/heap/min-heap.ts +7 -0
- package/templates/data-structure/priority-queue/index.ts +1 -0
- package/templates/data-structure/priority-queue/priority-queue.ts +44 -0
- package/templates/data-structure/queue/index.ts +1 -0
- package/templates/data-structure/queue/queue.ts +66 -0
- package/templates/data-structure/segment-tree/index.ts +1 -0
- package/templates/data-structure/segment-tree/segment-tree.ts +79 -0
- package/templates/data-structure/trie/index.ts +1 -0
- package/templates/data-structure/trie/trie.ts +104 -0
- package/templates/data-structure/union-find/index.ts +1 -0
- package/templates/data-structure/union-find/union-find.ts +79 -0
- package/templates/dom/attribute/attribute.ts +24 -0
- package/templates/dom/attribute/index.ts +1 -0
- package/templates/dom/class-name/class-name.ts +48 -0
- package/templates/dom/class-name/index.ts +1 -0
- package/templates/dom/is-element/index.ts +1 -0
- package/templates/dom/is-element/is-element.ts +20 -0
- package/templates/dom/query/index.ts +1 -0
- package/templates/dom/query/query.ts +7 -0
- package/templates/http/content-type/content-type.ts +130 -0
- package/templates/http/content-type/index.ts +1 -0
- package/templates/http/header/header.ts +56 -0
- package/templates/http/header/index.ts +1 -0
- package/templates/http/method/index.ts +1 -0
- package/templates/http/method/method.ts +25 -0
- package/templates/http/status/index.ts +1 -0
- package/templates/http/status/status.ts +191 -0
- package/templates/number/clamp/clamp.ts +11 -0
- package/templates/number/clamp/index.ts +1 -0
- package/templates/number/factorial/factorial.ts +15 -0
- package/templates/number/factorial/index.ts +1 -0
- package/templates/number/format-thousands/format-thousands.ts +24 -0
- package/templates/number/format-thousands/index.ts +1 -0
- package/templates/number/gcd/gcd.ts +13 -0
- package/templates/number/gcd/index.ts +1 -0
- package/templates/number/in-range/in-range.ts +3 -0
- package/templates/number/in-range/index.ts +1 -0
- package/templates/number/is-even/index.ts +1 -0
- package/templates/number/is-even/is-even.ts +5 -0
- package/templates/number/is-odd/index.ts +1 -0
- package/templates/number/is-odd/is-odd.ts +7 -0
- package/templates/number/lcm/index.ts +1 -0
- package/templates/number/lcm/lcm.ts +12 -0
- package/templates/number/lerp/index.ts +1 -0
- package/templates/number/lerp/lerp.ts +3 -0
- package/templates/number/percentage/index.ts +1 -0
- package/templates/number/percentage/percentage.ts +7 -0
- package/templates/number/random/index.ts +1 -0
- package/templates/number/random/random.ts +9 -0
- package/templates/number/random-int/index.ts +1 -0
- package/templates/number/random-int/random-int.ts +9 -0
- package/templates/number/round/index.ts +1 -0
- package/templates/number/round/round.ts +22 -0
- package/templates/number/safe-parse-number/index.ts +1 -0
- package/templates/number/safe-parse-number/safe-parse-number.ts +29 -0
- package/templates/number/to-ordinal/index.ts +1 -0
- package/templates/number/to-ordinal/to-ordinal.ts +28 -0
- package/templates/object/deep-clone/deep-clone.ts +47 -0
- package/templates/object/deep-clone/index.ts +1 -0
- package/templates/object/deep-equal/deep-equal.ts +66 -0
- package/templates/object/deep-equal/index.ts +1 -0
- package/templates/object/deep-merge/deep-merge.ts +49 -0
- package/templates/object/deep-merge/index.ts +1 -0
- package/templates/object/defaults/defaults.ts +14 -0
- package/templates/object/defaults/index.ts +1 -0
- package/templates/object/filter-object/filter-object.ts +11 -0
- package/templates/object/filter-object/index.ts +1 -0
- package/templates/object/get/get.ts +75 -0
- package/templates/object/get/index.ts +1 -0
- package/templates/object/has/has.ts +60 -0
- package/templates/object/has/index.ts +1 -0
- package/templates/object/invert/index.ts +1 -0
- package/templates/object/invert/invert.ts +13 -0
- package/templates/object/map-keys/index.ts +1 -0
- package/templates/object/map-keys/map-keys.ts +16 -0
- package/templates/object/map-values/index.ts +1 -0
- package/templates/object/map-values/map-values.ts +14 -0
- package/templates/object/omit/index.ts +1 -0
- package/templates/object/omit/omit.ts +15 -0
- package/templates/object/omit-by/index.ts +1 -0
- package/templates/object/omit-by/omit-by.ts +19 -0
- package/templates/object/pick/index.ts +1 -0
- package/templates/object/pick/pick.ts +15 -0
- package/templates/object/pick-by/index.ts +1 -0
- package/templates/object/pick-by/pick-by.ts +19 -0
- package/templates/object/set/index.ts +1 -0
- package/templates/object/set/set.ts +118 -0
- package/templates/string/capitalize/capitalize.ts +4 -0
- package/templates/string/capitalize/index.ts +1 -0
- package/templates/string/change-case/change-case.ts +98 -0
- package/templates/string/change-case/index.ts +1 -0
- package/templates/string/char/char.ts +14 -0
- package/templates/string/char/index.ts +1 -0
- package/templates/string/count-occurrences/count-occurrences.ts +20 -0
- package/templates/string/count-occurrences/index.ts +1 -0
- package/templates/string/escape-html/escape-html.ts +16 -0
- package/templates/string/escape-html/index.ts +1 -0
- package/templates/string/get-decorated-string/get-decorated-string.ts +7 -0
- package/templates/string/get-decorated-string/index.ts +1 -0
- package/templates/string/is-blank/index.ts +1 -0
- package/templates/string/is-blank/is-blank.ts +6 -0
- package/templates/string/mask/index.ts +1 -0
- package/templates/string/mask/mask.ts +30 -0
- package/templates/string/pad/index.ts +1 -0
- package/templates/string/pad/pad.ts +17 -0
- package/templates/string/random-string/index.ts +1 -0
- package/templates/string/random-string/random-string.ts +20 -0
- package/templates/string/reverse/index.ts +1 -0
- package/templates/string/reverse/reverse.ts +6 -0
- package/templates/string/slugify/index.ts +1 -0
- package/templates/string/slugify/slugify.ts +11 -0
- package/templates/string/strip-tags/index.ts +1 -0
- package/templates/string/strip-tags/strip-tags.ts +8 -0
- package/templates/string/template/index.ts +1 -0
- package/templates/string/template/template.ts +14 -0
- package/templates/string/truncate/index.ts +1 -0
- package/templates/string/truncate/truncate.ts +17 -0
- package/templates/string/truncate-middle/index.ts +1 -0
- package/templates/string/truncate-middle/truncate-middle.ts +25 -0
- package/templates/string/uuid/index.ts +1 -0
- package/templates/string/uuid/uuid.ts +9 -0
- package/templates/tailwindcss/class-variant/class-variant.ts +35 -0
- package/templates/tailwindcss/class-variant/index.ts +1 -0
- package/templates/tailwindcss/cn/cn.ts +29 -0
- package/templates/tailwindcss/cn/index.ts +1 -0
- package/templates/tailwindcss/create-tailwind-css/create-tailwind-css.ts +16 -0
- package/templates/tailwindcss/create-tailwind-css/index.ts +1 -0
- package/templates/tailwindcss/tw-merge-config/index.ts +1 -0
- package/templates/tailwindcss/tw-merge-config/tw-merge-config.ts +14 -0
- package/templates/type/get-type/get-type.ts +27 -0
- package/templates/type/get-type/index.ts +1 -0
- package/templates/type/is-type-of/index.ts +1 -0
- package/templates/type/is-type-of/is-type-of.ts +26 -0
- package/templates/util/mutex/index.ts +1 -0
- package/templates/util/mutex/mutex.ts +109 -0
- package/templates/util/url-parser/index.ts +1 -0
- package/templates/util/url-parser/url-parser.ts +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./sample";
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// 배열에서 무작위로 원소 하나를 골라 반환한다. 빈 배열이면 null을 반환한다.
|
|
2
|
+
// 각 원소가 균등 확률로 뽑힌다. 난수는 런타임의 Math.random을 사용한다.
|
|
3
|
+
export const sample = <T>(array: T[]): T | null => {
|
|
4
|
+
if (array.length === 0) {
|
|
5
|
+
return null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
const index = Math.floor(Math.random() * array.length);
|
|
9
|
+
return array[index];
|
|
10
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./shuffle";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Fisher-Yates 셔플로 무작위 순서의 새 배열을 반환한다. 입력 배열은 변형하지
|
|
2
|
+
// 않는다. 뒤에서 앞으로 훑으며 각 위치를 [0, index] 구간의 임의 위치와 교환하므로
|
|
3
|
+
// 모든 순열이 균등 확률로 나온다. 난수는 런타임의 Math.random을 사용한다.
|
|
4
|
+
export const shuffle = <T>(array: T[]): T[] => {
|
|
5
|
+
const result = array.slice();
|
|
6
|
+
|
|
7
|
+
for (let index = result.length - 1; index > 0; index -= 1) {
|
|
8
|
+
const swap = Math.floor(Math.random() * (index + 1));
|
|
9
|
+
const temp = result[index];
|
|
10
|
+
result[index] = result[swap];
|
|
11
|
+
result[swap] = temp;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./sort-by";
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// keyFn이 돌려준 키를 기준으로 오름차순 안정 정렬한 새 배열을 반환한다.
|
|
2
|
+
// 입력 배열은 변형하지 않는다. 키가 같은 항목들은 원래 순서를 유지한다(안정).
|
|
3
|
+
//
|
|
4
|
+
// 키 타입은 number | string로 한정한다. 두 키를 빼거나 직접 비교하는 대신
|
|
5
|
+
// compareKey 하나로 처리해, number는 차이로 string은 사전식으로 비교한다.
|
|
6
|
+
// string 비교에 localeCompare를 쓰지 않는 이유는 로케일에 따라 결과가 달라져
|
|
7
|
+
// 코드 단위 비교(`<`/`>`)가 더 결정적이기 때문이다.
|
|
8
|
+
const compareKey = (a: number | string, b: number | string): number => {
|
|
9
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
10
|
+
return a - b;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const left = String(a);
|
|
14
|
+
const right = String(b);
|
|
15
|
+
if (left < right) {
|
|
16
|
+
return -1;
|
|
17
|
+
}
|
|
18
|
+
if (left > right) {
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
return 0;
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export const sortBy = <T>(array: T[], keyFn: (item: T) => number | string): T[] => {
|
|
25
|
+
// 키를 항목당 한 번만 계산해 두고(슈워츠 변환) 비교에서 재호출하지 않는다.
|
|
26
|
+
// index를 함께 들고 가 동점일 때 원래 순서로 풀어 안정성을 보장한다.
|
|
27
|
+
// (Array.prototype.sort 자체도 ES2019부터 안정이지만, 키 캐싱을 위해 래핑한다.)
|
|
28
|
+
return array
|
|
29
|
+
.map((item, index) => ({ item, index, key: keyFn(item) }))
|
|
30
|
+
.sort((a, b) => compareKey(a.key, b.key) || a.index - b.index)
|
|
31
|
+
.map((entry) => entry.item);
|
|
32
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./sum-by";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./take";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// 배열 앞에서 n개를 잘라 새 배열로 반환한다. 입력 배열은 변형하지 않는다.
|
|
2
|
+
// n이 0 이하면 빈 배열, n이 길이보다 크면 전체 복사본을 돌려준다.
|
|
3
|
+
// slice의 음수 인덱스 해석을 피하려고 n을 [0, length]로 먼저 클램프한다.
|
|
4
|
+
export const take = <T>(array: readonly T[], n: number): T[] => {
|
|
5
|
+
const count = Math.min(Math.max(n, 0), array.length);
|
|
6
|
+
return array.slice(0, count);
|
|
7
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./union";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./unique";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./unique-by";
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// keyFn이 돌려준 키를 기준으로 중복을 제거한다. 같은 키가 처음 나온 항목만
|
|
2
|
+
// 남기고 첫 등장 순서를 보존한다. 입력 배열은 변형하지 않는다.
|
|
3
|
+
// 키 비교는 Set의 SameValueZero 동등성을 따른다.
|
|
4
|
+
export const uniqueBy = <T, K>(array: readonly T[], keyFn: (item: T) => K): T[] => {
|
|
5
|
+
const seen = new Set<K>();
|
|
6
|
+
const result: T[] = [];
|
|
7
|
+
|
|
8
|
+
for (const item of array) {
|
|
9
|
+
const key = keyFn(item);
|
|
10
|
+
if (seen.has(key)) {
|
|
11
|
+
continue;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
seen.add(key);
|
|
15
|
+
result.push(item);
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
return result;
|
|
19
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./windowed";
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export const windowed = <T>(array: T[], size: number, step = 1): T[][] => {
|
|
2
|
+
if (size <= 0 || step <= 0) {
|
|
3
|
+
return [];
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
const result: T[][] = [];
|
|
7
|
+
|
|
8
|
+
// 마지막 시작 인덱스는 size만큼 꽉 찬 윈도우가 나오는 지점까지다.
|
|
9
|
+
// array.length < size면 루프가 한 번도 돌지 않아 빈 배열이 된다.
|
|
10
|
+
for (let index = 0; index + size <= array.length; index += step) {
|
|
11
|
+
result.push(array.slice(index, index + size));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return result;
|
|
15
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./zip";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export const zip = <A, B>(a: A[], b: B[]): [A, B][] => {
|
|
2
|
+
// 길이가 다르면 짧은 쪽에서 멈춘다. 남는 원소는 짝이 없으므로 버린다.
|
|
3
|
+
const length = Math.min(a.length, b.length);
|
|
4
|
+
const result: [A, B][] = [];
|
|
5
|
+
|
|
6
|
+
for (let index = 0; index < length; index += 1) {
|
|
7
|
+
result.push([a[index], b[index]]);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return result;
|
|
11
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./parse-boolean";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// 다양한 입력을 boolean으로 해석한다.
|
|
2
|
+
// true/"true"/"1"/"yes"/"y"/"on"(대소문자·앞뒤 공백 무시)과 0이 아닌 숫자는 true,
|
|
3
|
+
// 그 외(false/0/null/undefined/빈 문자열 등)는 false.
|
|
4
|
+
const TRUTHY = new Set(["true", "1", "yes", "y", "on"]);
|
|
5
|
+
|
|
6
|
+
export const parseBoolean = (value: unknown): boolean => {
|
|
7
|
+
if (typeof value === "boolean") {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
if (typeof value === "number") {
|
|
11
|
+
return value !== 0;
|
|
12
|
+
}
|
|
13
|
+
if (typeof value === "string") {
|
|
14
|
+
return TRUTHY.has(value.trim().toLowerCase());
|
|
15
|
+
}
|
|
16
|
+
return false;
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./toggle";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./xor";
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
export class Deque<T> {
|
|
2
|
+
private items = new Map<number, T>();
|
|
3
|
+
private head = 0;
|
|
4
|
+
private tail = 0;
|
|
5
|
+
|
|
6
|
+
size() {
|
|
7
|
+
return this.tail - this.head;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
isEmpty() {
|
|
11
|
+
return this.size() === 0;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
pushFront(value: T) {
|
|
15
|
+
this.head -= 1;
|
|
16
|
+
this.items.set(this.head, value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
pushBack(value: T) {
|
|
20
|
+
this.items.set(this.tail, value);
|
|
21
|
+
this.tail += 1;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
popFront(): T | null {
|
|
25
|
+
if (this.isEmpty()) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const value = this.items.get(this.head) as T;
|
|
30
|
+
this.items.delete(this.head);
|
|
31
|
+
this.head += 1;
|
|
32
|
+
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
popBack(): T | null {
|
|
37
|
+
if (this.isEmpty()) {
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.tail -= 1;
|
|
42
|
+
const value = this.items.get(this.tail) as T;
|
|
43
|
+
this.items.delete(this.tail);
|
|
44
|
+
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
front(): T | null {
|
|
49
|
+
if (this.isEmpty()) {
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return this.items.get(this.head) as T;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
back(): T | null {
|
|
57
|
+
if (this.isEmpty()) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return this.items.get(this.tail - 1) as T;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
clear() {
|
|
65
|
+
this.items.clear();
|
|
66
|
+
this.head = 0;
|
|
67
|
+
this.tail = 0;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
toArray() {
|
|
71
|
+
const result: T[] = [];
|
|
72
|
+
|
|
73
|
+
for (let index = this.head; index < this.tail; index += 1) {
|
|
74
|
+
result.push(this.items.get(index) as T);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./deque";
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
export class FenwickTree {
|
|
2
|
+
private tree: number[];
|
|
3
|
+
private values: number[];
|
|
4
|
+
|
|
5
|
+
constructor(sizeOrValues: number | number[]) {
|
|
6
|
+
const size = Array.isArray(sizeOrValues) ? sizeOrValues.length : sizeOrValues;
|
|
7
|
+
this.tree = Array(size + 1).fill(0);
|
|
8
|
+
this.values = Array(size).fill(0);
|
|
9
|
+
|
|
10
|
+
if (Array.isArray(sizeOrValues)) {
|
|
11
|
+
sizeOrValues.forEach((value, index) => {
|
|
12
|
+
this.set(index, value);
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
size() {
|
|
18
|
+
return this.values.length;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
update(index: number, delta: number) {
|
|
22
|
+
this.assertIndex(index);
|
|
23
|
+
|
|
24
|
+
this.values[index] += delta;
|
|
25
|
+
|
|
26
|
+
for (let current = index + 1; current < this.tree.length; current += current & -current) {
|
|
27
|
+
this.tree[current] += delta;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
set(index: number, value: number) {
|
|
32
|
+
this.assertIndex(index);
|
|
33
|
+
this.update(index, value - this.values[index]);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
get(index: number) {
|
|
37
|
+
this.assertIndex(index);
|
|
38
|
+
|
|
39
|
+
return this.values[index];
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
prefixSum(index: number) {
|
|
43
|
+
if (index < 0) {
|
|
44
|
+
return 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (index >= this.size()) {
|
|
48
|
+
throw new RangeError("index is out of range");
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
let result = 0;
|
|
52
|
+
|
|
53
|
+
for (let current = index + 1; current > 0; current -= current & -current) {
|
|
54
|
+
result += this.tree[current];
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return result;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
rangeSum(left: number, right: number) {
|
|
61
|
+
if (left > right) {
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
this.assertIndex(left);
|
|
66
|
+
this.assertIndex(right);
|
|
67
|
+
|
|
68
|
+
return this.prefixSum(right) - this.prefixSum(left - 1);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
private assertIndex(index: number) {
|
|
72
|
+
if (!Number.isInteger(index) || index < 0 || index >= this.size()) {
|
|
73
|
+
throw new RangeError("index is out of range");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./fenwick-tree";
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export abstract class Heap<T> {
|
|
2
|
+
items: T[];
|
|
3
|
+
compareBy: (item: T) => number;
|
|
4
|
+
|
|
5
|
+
constructor(options: { compareBy: Heap<T>["compareBy"] }) {
|
|
6
|
+
this.items = [];
|
|
7
|
+
this.compareBy = options.compareBy;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
size() {
|
|
11
|
+
return this.items.length;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
peek(): T | null {
|
|
15
|
+
if (!this.size()) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return this.items[0];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
push(value: T) {
|
|
23
|
+
this.items.push(value);
|
|
24
|
+
this.bubbleUp();
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
pop(): T | null {
|
|
28
|
+
if (!this.size()) {
|
|
29
|
+
return null;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const top = this.items[0];
|
|
33
|
+
const last = this.items[this.size() - 1];
|
|
34
|
+
this.items.pop();
|
|
35
|
+
|
|
36
|
+
if (this.size()) {
|
|
37
|
+
this.items[0] = last;
|
|
38
|
+
this.bubbleDown();
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return top;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
swap(a: number, b: number) {
|
|
45
|
+
[this.items[a], this.items[b]] = [this.items[b], this.items[a]];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* 루트에 더 가까워야 하는(우선순위가 높은) 쪽을 음수로 반환합니다.
|
|
50
|
+
* MinHeap은 값이 작을수록, MaxHeap은 값이 클수록 우선순위가 높습니다.
|
|
51
|
+
*/
|
|
52
|
+
abstract compare(aIndex: number, bIndex: number): number;
|
|
53
|
+
|
|
54
|
+
bubbleUp() {
|
|
55
|
+
let index = this.size() - 1;
|
|
56
|
+
|
|
57
|
+
while (index > 0) {
|
|
58
|
+
const parentIndex = Math.floor((index - 1) / 2);
|
|
59
|
+
|
|
60
|
+
if (this.compare(parentIndex, index) <= 0) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
this.swap(index, parentIndex);
|
|
65
|
+
index = parentIndex;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
bubbleDown() {
|
|
70
|
+
let index = 0;
|
|
71
|
+
|
|
72
|
+
while (index * 2 + 1 < this.size()) {
|
|
73
|
+
const leftIndex = index * 2 + 1;
|
|
74
|
+
const rightIndex = index * 2 + 2;
|
|
75
|
+
|
|
76
|
+
const isRightHigherPriority = rightIndex < this.size() && this.compare(rightIndex, leftIndex) < 0;
|
|
77
|
+
|
|
78
|
+
const targetIndex = isRightHigherPriority ? rightIndex : leftIndex;
|
|
79
|
+
|
|
80
|
+
if (this.compare(index, targetIndex) <= 0) {
|
|
81
|
+
break;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
this.swap(index, targetIndex);
|
|
85
|
+
index = targetIndex;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./priority-queue";
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { Heap } from "../heap/heap";
|
|
2
|
+
|
|
3
|
+
type Compare<T> = (a: T, b: T) => number;
|
|
4
|
+
|
|
5
|
+
const defaultCompare = <T>(a: T, b: T) => {
|
|
6
|
+
if (a < b) {
|
|
7
|
+
return -1;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
if (a > b) {
|
|
11
|
+
return 1;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
return 0;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
export class PriorityQueue<T> extends Heap<T> {
|
|
18
|
+
private compareItems: Compare<T>;
|
|
19
|
+
|
|
20
|
+
constructor(options: { compare?: Compare<T> } = {}) {
|
|
21
|
+
super({ compareBy: () => 0 });
|
|
22
|
+
this.compareItems = options.compare ?? defaultCompare;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
compare(aIndex: number, bIndex: number): number {
|
|
26
|
+
return this.compareItems(this.items[aIndex], this.items[bIndex]);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
enqueue(value: T) {
|
|
30
|
+
this.push(value);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
dequeue(): T | null {
|
|
34
|
+
return this.pop();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
isEmpty() {
|
|
38
|
+
return this.size() === 0;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
clear() {
|
|
42
|
+
this.items = [];
|
|
43
|
+
}
|
|
44
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./queue";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
class Node<T> {
|
|
2
|
+
value: T;
|
|
3
|
+
next: Node<T> | null;
|
|
4
|
+
|
|
5
|
+
constructor(value: T) {
|
|
6
|
+
this.value = value;
|
|
7
|
+
this.next = null;
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class Queue<T> {
|
|
12
|
+
_size: number;
|
|
13
|
+
_head: Node<T> | null;
|
|
14
|
+
_tail: Node<T> | null;
|
|
15
|
+
|
|
16
|
+
constructor() {
|
|
17
|
+
this._size = 0;
|
|
18
|
+
this._head = null;
|
|
19
|
+
this._tail = null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
enqueue(newValue: T) {
|
|
23
|
+
const newNode = new Node(newValue);
|
|
24
|
+
|
|
25
|
+
if (this._head === null) {
|
|
26
|
+
this._head = this._tail = newNode;
|
|
27
|
+
this._size += 1;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (this._tail) {
|
|
32
|
+
this._tail.next = newNode;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
this._tail = newNode;
|
|
36
|
+
this._size += 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
dequeue(): T | null {
|
|
40
|
+
if (this._head) {
|
|
41
|
+
const value = this._head.value;
|
|
42
|
+
this._head = this._head.next;
|
|
43
|
+
this._size -= 1;
|
|
44
|
+
|
|
45
|
+
return value;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
peek() {
|
|
52
|
+
if (this._head) {
|
|
53
|
+
return this._head;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
size() {
|
|
60
|
+
return this._size;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
isEmpty() {
|
|
64
|
+
return this._size === 0;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from "./segment-tree";
|