/** * substring.c * A simple implementation of the Rabin-Karp algorithm and some. * related stuff. Needs to be linked with -lm. * * Written by Samuel A. Rebelsky * Released under version 3.0 of the GNU GPL */ // +---------+------------------------------------------------------- // | Headers | // +---------+ #include // For INT_MAX #include // For sqrt #include #include // For strlen, strncmp #include "substring.h" // +---------+------------------------------------------------------- // | Globals | // +---------+ /** * The size of our alphabet. */ const int ALPHA = 131; /** * The largest hash value. It should be about the square root * of INT_MAX. We'll just right shift by half the bits and then * subtract a little so that it's not a power of two. */ const int MAX_HASH = (INT_MAX >> 4*sizeof(int)) - 7; // +---------+------------------------------------------------------- // | Helpers | // +---------+ /** * Compute x^n mod m, inefficiently. */ int expt_mod (int x, int n, int m) { int result = 1; for (int i = 0; i < n; i++) { result = (result * x) % m; } // for return result; } // expt_mod /** * Compute the hash code of the length-n substring of str starting from s */ int hashcode (char *str, int s, int n) { int code = str[s]; for (int i = 1; i < n; i++) { code = (ALPHA*code + str[s+i]) % MAX_HASH; } // for return code; } // hashcode // +--------------------+-------------------------------------------- // | Exported Functions | // +--------------------+ int substring (char *text, char *pattern) { // Compute the lengths of the two strings int textlen = strlen (text); int patlen = strlen (pattern); // Compute the hash codes of the first textlen characters of each string int pathash = hashcode (pattern, 0, patlen); int texthash = hashcode (text, 0, patlen); // Compute alpha^patlen-1, since we need it for updating the text // hash. int multiplier = expt_mod (ALPHA, patlen - 1, MAX_HASH); // Try each position in turn for (int i = 0; i <= textlen - patlen; i++) { // If the hash codes are the same, compare the substrings if (pathash == texthash) // if (pathash == texthash && (0 == strncmp(text+i, pattern, patlen))) { return i; } // Move on texthash = ALPHA * (MAX_HASH + texthash - (multiplier*text[i] % MAX_HASH)) + text[patlen+i]; texthash = texthash % MAX_HASH; } // for // Not found. return -1; } // substring