Skip to content

Commit e5585b9

Browse files
committed
added quick sort
1 parent bbf4a5a commit e5585b9

File tree

6 files changed

+138
-38
lines changed

6 files changed

+138
-38
lines changed

src/dim_red/dim_red.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,4 +104,13 @@ export abstract class DimRed<P extends DimRedParams> {
104104
get seed() {
105105
return this._params.seed
106106
}
107+
108+
/**
109+
* Gets the parameters used for the algorithm.
110+
*/
111+
get parameters() {
112+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
113+
const { metric, seed, dimensionality, ...rest } = this._params
114+
return rest
115+
}
107116
}

src/dim_red/tsne.ts

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export class TSNE extends DimRed<TSNEParams> {
1818
epsilon: 10,
1919
dimensionality: 2,
2020
metric: euclideanSquared,
21+
seed: 1212,
2122
...params
2223
})
2324
this._result = new Matrix(this._data.rows, this.dimensionality, () => this._randomizer.randomGauss() * 1e-4)
@@ -51,7 +52,7 @@ export class TSNE extends DimRed<TSNEParams> {
5152
const P = new Matrix(n, n, 0)
5253

5354
// search for fitting sigma
54-
const targetH = Math.log(this.perplexity)
55+
const targetH = Math.log(this._params.perplexity)
5556
for (let i = 0; i < n; ++i) {
5657
const nDist = delta.getRow(i)
5758
const pRow = P.getRow(i)
@@ -186,20 +187,4 @@ export class TSNE extends DimRed<TSNEParams> {
186187

187188
return this._result
188189
}
189-
190-
/**
191-
* Returns the perplexity value used in t-SNE algorithm.
192-
* @returns The value of the perplexity parameter.
193-
*/
194-
get perplexity() {
195-
return this._params.perplexity
196-
}
197-
198-
/**
199-
* Returns the epsilon value used in t-SNE algorithm.
200-
* @returns The value of the epsilon parameter.
201-
*/
202-
get epsilon() {
203-
return this._params.epsilon
204-
}
205190
}

src/sortings/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1-
// 2023-10-10 13:12:20
1+
// 2023-10-25 12:32:42
22

33
export * from './merge';
4+
export * from './quick';

src/sortings/merge.ts

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,41 @@
1-
import { isRightArray } from "../utils"
1+
import { getLCP } from "../utils"
22

33
/**
4-
* Sorts an array of numbers or strings using the merge sort algorithm.
4+
* Sorts an array of numbers using the merge sort algorithm.
55
* @param array The array to be sorted.
66
* @returns The sorted array.
77
*/
8-
export function mergeSort(array: number[]): number[]
9-
export function mergeSort(array: string[]): string[]
10-
export function mergeSort(array: number[] | string[]) {
8+
export function mergeSortNum(array: number[]) {
119
if (array.length <= 1) return array
1210

1311
const middle = Math.floor(array.length / 2)
1412

15-
let left = array.slice(0, middle) as never
16-
let right = array.slice(middle) as never
13+
let left = array.slice(0, middle)
14+
let right = array.slice(middle)
1715

18-
left = mergeSort(left) as never
19-
right = mergeSort(right) as never
16+
left = mergeSortNum(left)
17+
right = mergeSortNum(right)
2018

21-
let result: number[] | string[] = []
19+
return mergeNumbers(left, right)
20+
}
2221

23-
if (isRightArray<string>(array)) result = mergeStrings(left, right)
24-
else if (isRightArray<number>(array)) result = mergeNumbers(left, right)
22+
/**
23+
* Sorts an array of strings using the merge sort algorithm.
24+
* @param array The array to be sorted.
25+
* @returns The sorted array.
26+
*/
27+
export function mergeSortStr(array: string[]) {
28+
if (array.length <= 1) return array
2529

26-
return result
30+
const middle = Math.floor(array.length / 2)
31+
32+
let left = array.slice(0, middle)
33+
let right = array.slice(middle)
34+
35+
left = mergeSortStr(left)
36+
right = mergeSortStr(right)
37+
38+
return mergeStrings(left, right)
2739
}
2840

2941
function mergeNumbers(left: number[], right: number[]) {
@@ -48,7 +60,7 @@ function mergeStrings(left: string[], right: string[]) {
4860
let result: string[] = []
4961

5062
while (left.length > 0 && right.length > 0) {
51-
if (compareLCP(left[0], right[0]) <= 0) {
63+
if (getLCP(left[0], right[0]) <= 0) {
5264
result.push(left[0])
5365
left.shift()
5466
} else {
@@ -60,10 +72,4 @@ function mergeStrings(left: string[], right: string[]) {
6072
result = [...result, ...left, ...right]
6173

6274
return result
63-
}
64-
65-
function compareLCP(str1: string, str2: string) {
66-
let lcp = 0
67-
while (lcp < Math.min(str1.length, str2.length) && str1[lcp] === str2[lcp]) lcp++
68-
return lcp
6975
}

src/sortings/quick.ts

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import { getLCP } from "../utils"
2+
3+
/**
4+
* Sorts an array of numbers using the quick sort algorithm.
5+
* @param array The array to be sorted.
6+
* @returns The sorted array.
7+
*/
8+
export function quickSortNum(array: number[]) {
9+
if (array.length <= 1) return array
10+
11+
const result = [...array]
12+
13+
const qs = (arr: number[], low: number, high: number) => {
14+
if (low < high) {
15+
const pi = partitionNumbers(arr, low, high)
16+
17+
qs(arr, low, pi - 1)
18+
qs(arr, pi + 1, high)
19+
}
20+
}
21+
22+
qs(result, 0, result.length - 1)
23+
24+
return result
25+
}
26+
27+
/**
28+
* Sorts an array of strings using the quick sort algorithm.
29+
* @param array The array to be sorted.
30+
* @returns The sorted array.
31+
*/
32+
export function quickSortStr(array: string[]) {
33+
if (array.length <= 1) return array
34+
35+
const result = [...array]
36+
37+
const qs = (arr: string[], low: number, high: number) => {
38+
if (low < high) {
39+
const pi = partitionStrings(arr, low, high)
40+
41+
qs(arr, low, pi - 1)
42+
qs(arr, pi + 1, high)
43+
}
44+
}
45+
46+
qs(result, 0, result.length - 1)
47+
48+
return result
49+
}
50+
51+
function partitionNumbers(arr: number[], low: number, high: number) {
52+
const pivot = arr[high]
53+
let i = low - 1
54+
55+
for (let j = low; j <= high - 1; j++) {
56+
if (arr[j] < pivot) {
57+
i++;
58+
[arr[i], arr[j]] = [arr[j], arr[i]];
59+
}
60+
}
61+
62+
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
63+
64+
return i + 1
65+
}
66+
67+
function partitionStrings(arr: string[], low: number, high: number) {
68+
const pivot = arr[high]
69+
let i = low - 1
70+
71+
for (let j = low; j <= high - 1; j++) {
72+
const lcp = getLCP(arr[j], pivot)
73+
if (lcp < 0) {
74+
i++;
75+
[arr[i], arr[j]] = [arr[j], arr[i]];
76+
} else if (arr[j] === pivot) {
77+
if (lcp === arr[j].length || lcp === pivot.length || arr[j][lcp] < pivot[lcp]) {
78+
i++;
79+
[arr[i], arr[j]] = [arr[j], arr[i]];
80+
}
81+
}
82+
}
83+
84+
[arr[i + 1], arr[high]] = [arr[high], arr[i + 1]];
85+
86+
return i + 1
87+
}

src/utils/helpers.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,18 @@ export function isArray2D<T>(array: unknown[][]): array is T[][] {
2828
return isRightArray(array) && array?.every(item => isRightArray(item))
2929
}
3030

31+
/**
32+
* Returns the length of the longest common prefix between two strings.
33+
* @param str1 - The first string to compare.
34+
* @param str2 - The second string to compare.
35+
* @returns The length of the longest common prefix between the two strings.
36+
*/
37+
export function getLCP(str1: string, str2: string) {
38+
let lcp = 0
39+
while (lcp < Math.min(str1.length, str2.length) && str1[lcp] === str2[lcp]) lcp++
40+
return lcp
41+
}
42+
3143
/**
3244
* Measures the time it takes for a function to execute.
3345
* @param func - The function to measure the execution time of.

0 commit comments

Comments
 (0)