Skip to content

Commit

Permalink
Adding RabinKarp to algs4
Browse files Browse the repository at this point in the history
  • Loading branch information
mina-asham committed May 17, 2015
1 parent 9617905 commit 6500dc4
Show file tree
Hide file tree
Showing 2 changed files with 178 additions and 0 deletions.
2 changes: 2 additions & 0 deletions algs4/algs4.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<Reference Include="System" />
<Reference Include="System.Core" />
<Reference Include="System.Drawing" />
<Reference Include="System.Numerics" />
<Reference Include="System.Windows.Forms" />
</ItemGroup>
<ItemGroup>
Expand Down Expand Up @@ -142,6 +143,7 @@
<Compile Include="algs4\Quick.cs" />
<Compile Include="algs4\QuickUnionUF.cs" />
<Compile Include="algs4\QuickX.cs" />
<Compile Include="algs4\RabinKarp.cs" />
<Compile Include="algs4\RandomSeq.cs" />
<Compile Include="algs4\RedBlackBST.cs" />
<Compile Include="algs4\ResizingArrayBag.cs" />
Expand Down
176 changes: 176 additions & 0 deletions algs4/algs4/RabinKarp.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
using System.Numerics;
using System.Security.Cryptography;
using algs4.stdlib;

namespace algs4.algs4
{
public class RabinKarp
{
/// <summary>
/// The pattern // needed only for Las Vegas
/// </summary>
private readonly string _pat;

/// <summary>
/// Pattern hash value
/// </summary>
private readonly long _patHash;

/// <summary>
/// Pattern length
/// </summary>
private readonly int _m;

/// <summary>
/// A large prime, small enough to avoid long overflow
/// </summary>
private readonly long _q;

/// <summary>
/// Radix
/// </summary>
private readonly int _r;

/// <summary>
/// R^(M-1) % Q
/// </summary>
private readonly long _rm;

public RabinKarp(string pat)
{
_pat = pat; // save pattern (needed only for Las Vegas)
_r = 256;
_m = pat.Length;
_q = LongRandomPrime();

// precompute R^(M-1) % Q for use in removing leading digit
_rm = 1;
for (int i = 1; i <= _m - 1; i++)
{
_rm = (_r * _rm) % _q;
}
_patHash = Hash(pat, _m);
}

/// <summary>
/// Compute hash for key[0..M-1].
/// </summary>
/// <param name="key"></param>
/// <param name="m"></param>
/// <returns></returns>
private long Hash(string key, int m)
{
long h = 0;
for (int j = 0; j < m; j++)
{
h = (_r * h + key[j]) % _q;
}
return h;
}

/// <summary>
/// Las Vegas version: does pat[] match txt[i..i-M+1] ?
/// </summary>
/// <param name="txt"></param>
/// <param name="i"></param>
/// <returns></returns>
private bool Check(string txt, int i)
{
for (int j = 0; j < _m; j++)
{
if (_pat[j] != txt[i + j])
{
return false;
}
}
return true;
}

/// <summary>
/// Check for exact match
/// </summary>
/// <param name="txt"></param>
/// <returns></returns>
public int Search(string txt)
{
int n = txt.Length;
if (n < _m)
{
return n;
}
long txtHash = Hash(txt, _m);

// Check for match at offset 0
if ((_patHash == txtHash) && Check(txt, 0))
{
return 0;
}

// Check for hash match; if hash match, Check for exact match
for (int i = _m; i < n; i++)
{
// Remove leading digit, add trailing digit, Check for match.
txtHash = (txtHash + _q - _rm * txt[i - _m] % _q) % _q;
txtHash = (txtHash * _r + txt[i]) % _q;

// match
int offset = i - _m + 1;
if ((_patHash == txtHash) && Check(txt, offset))
{
return offset;
}
}

// no match
return n;
}

/// <summary>
/// A random 31-bit prime
/// </summary>
/// <returns></returns>
private static long LongRandomPrime()
{
BigInteger prime = RandomBigInteger(31);
return (long)prime;
}

/// <summary>
/// Replacement for Java's BigInteger.probablePrime
/// </summary>
/// <param name="bits"></param>
/// <returns></returns>
private static BigInteger RandomBigInteger(int bits)
{
RNGCryptoServiceProvider rng = new RNGCryptoServiceProvider();
byte[] bytes = new byte[bits / 8];
rng.GetBytes(bytes);

return new BigInteger(bytes);
}

/// <summary>
/// Test client
/// </summary>
/// <param name="args"></param>
public static void RunMain(string[] args)
{
string pat = args[0];
string txt = args[1];

RabinKarp searcher = new RabinKarp(pat);
int offset = searcher.Search(txt);

// Print results
StdOut.PrintLn("text: " + txt);

// from brute force search method 1
StdOut.Print("pattern: ");
for (int i = 0; i < offset; i++)
{
StdOut.Print(" ");
}
StdOut.PrintLn(pat);
}
}
}

0 comments on commit 6500dc4

Please sign in to comment.