Skip to content

Commit 523716b

Browse files
Merge pull request #104 from PresenceOP-Coder/rabinkarp
feat: implemented rabin karp
2 parents 8c0baef + 579d93b commit 523716b

File tree

4 files changed

+481
-8
lines changed

4 files changed

+481
-8
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
export function getRabinKarpSteps(text, pattern) {
2+
const steps = [];
3+
const n = text.length;
4+
const m = pattern.length;
5+
6+
if (m === 0 || n < m) {
7+
return { steps, found: false };
8+
}
9+
10+
const d = 256;
11+
const q = 101;
12+
let h = 1;
13+
let pHash = 0;
14+
let tHash = 0;
15+
let found = false;
16+
17+
for (let i = 0; i < m - 1; i++) {
18+
h = (h * d) % q;
19+
}
20+
21+
steps.push({
22+
windowStart: 0,
23+
compareIndex: -1,
24+
status: 'calculating',
25+
pHash: 0,
26+
tHash: 0,
27+
message: `Starting. Pattern length=${m}, Text length=${n}. Prime q=${q}. Multiplier h=${h}.`
28+
});
29+
30+
for (let i = 0; i < m; i++) {
31+
pHash = (d * pHash + pattern.charCodeAt(i)) % q;
32+
tHash = (d * tHash + text.charCodeAt(i)) % q;
33+
34+
steps.push({
35+
windowStart: 0,
36+
compareIndex: i,
37+
status: 'calculating',
38+
pHash,
39+
tHash,
40+
message: `Calculating initial hashes. Index ${i}. Pattern Hash = ${pHash}, Window Hash = ${tHash}.`
41+
});
42+
}
43+
44+
for (let i = 0; i <= n - m; i++) {
45+
steps.push({
46+
windowStart: i,
47+
compareIndex: -1,
48+
status: 'sliding',
49+
pHash,
50+
tHash,
51+
message: `Sliding window to index ${i}. Pattern Hash = ${pHash}, Window Hash = ${tHash}.`
52+
});
53+
54+
if (pHash === tHash) {
55+
steps.push({
56+
windowStart: i,
57+
compareIndex: 0,
58+
status: 'hash_match',
59+
pHash,
60+
tHash,
61+
message: `Hash Match Found! Verifying character by character...`
62+
});
63+
64+
let j = 0;
65+
for (j = 0; j < m; j++) {
66+
steps.push({
67+
windowStart: i,
68+
compareIndex: i + j,
69+
patternCompareIndex: j,
70+
status: 'verifying',
71+
pHash,
72+
tHash,
73+
message: `Verifying: text[${i + j}] ('${text[i + j]}') === pattern[${j}] ('${pattern[j]}')?`
74+
});
75+
76+
if (text[i + j] !== pattern[j]) {
77+
steps.push({
78+
windowStart: i,
79+
compareIndex: i + j,
80+
patternCompareIndex: j,
81+
status: 'spurious_hit',
82+
pHash,
83+
tHash,
84+
message: `Spurious Hit! Mismatch found. Resuming search.`
85+
});
86+
break;
87+
}
88+
}
89+
90+
if (j === m) {
91+
found = true;
92+
steps.push({
93+
windowStart: i,
94+
compareIndex: -1,
95+
status: 'found',
96+
pHash,
97+
tHash,
98+
message: `Pattern Found at index ${i}!`
99+
});
100+
}
101+
}
102+
103+
if (i < n - m) {
104+
const oldHash = tHash;
105+
const charToRemove = text.charCodeAt(i);
106+
const charToAdd = text.charCodeAt(i + m);
107+
108+
tHash = (d * (tHash - charToRemove * h) + charToAdd) % q;
109+
if (tHash < 0) {
110+
tHash += q;
111+
}
112+
113+
steps.push({
114+
windowStart: i,
115+
compareIndex: -1,
116+
status: 'rolling',
117+
removeIndex: i,
118+
addIndex: i + m,
119+
pHash,
120+
tHash: oldHash,
121+
message: `Rolling hash... Removing '${text[i]}' (val ${charToRemove}).`
122+
});
123+
124+
steps.push({
125+
windowStart: i + 1,
126+
compareIndex: -1,
127+
status: 'rolling',
128+
removeIndex: i,
129+
addIndex: i + m,
130+
pHash,
131+
tHash,
132+
message: `Rolling hash... Adding '${text[i + m]}' (val ${charToAdd}). New Window Hash = ${tHash}.`
133+
});
134+
}
135+
}
136+
137+
steps.push({
138+
windowStart: -1,
139+
compareIndex: -1,
140+
status: found ? 'finished_found' : 'finished_not_found',
141+
pHash,
142+
tHash,
143+
message: found ? "Search complete. Pattern was found." : "Search complete. Pattern was not found."
144+
});
145+
146+
return { steps, found };
147+
}

0 commit comments

Comments
 (0)