Skip to content

Commit

Permalink
Fix KMP algorithm
Browse files Browse the repository at this point in the history
last commit full of bugs...
  • Loading branch information
hutusi committed Aug 9, 2019
1 parent 8fc7a5c commit 3a528b7
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 12 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ make
### String
- [x] BigNum integer [bignum.h](src/bignum.h) [bignum.c](src/bignum.c)
- [ ] BigNum decimal
- [ ] KMP
- [x] KMP string match algorithm [kmp.h](src/kmp.h) [kmp.c](src/kmp.c)
- [ ] Trie Tree

### Sorting
Expand Down
27 changes: 18 additions & 9 deletions src/kmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,38 +12,47 @@
#include <stdlib.h>
#include <string.h>

static void kmp_calculate_next(const char *string, int len, int *next)
#ifdef ALLOC_TESTING
#include "alloc-testing.h"
#endif

int *kmp_calculate_next(const char *string, int len)
{
int *next = (int *)calloc(len, sizeof(int));
next[0] = 0;
int k = 0;
for (int i = 1; i < len; ++i) {
while (k > 0 && next[k] != next[i]) {
while (k > 0 && string[k] != string[i]) {
k = next[k];
}
if (next[k + 1] != next[i]) {
}

if (string[k] == string[i]) {
++k;
}

next[i] = k;
}

return next;
}

int kmp_string_match(const char *text, const char *pattern)
{
int text_len = strlen(text);
int pat_len = strlen(pattern);
int *next = (int *)calloc(pat_len, sizeof(int));
kmp_calculate_next(pattern, pat_len, next);
int *next = kmp_calculate_next(pattern, pat_len);

int index = -1;
int j = 0;
for (int i = 0; i < text_len; ++i) {
if (text[i] == pattern[j]) {
++j;
} else {
j = next[j];
--i;
if (j > 0) {
/** C allowed n[-1] ?? */
j = next[j - 1];
--i;
}
}

if (j >= pat_len) {
Expand Down
2 changes: 1 addition & 1 deletion src/kmp.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@

/**
* @brief KMP algorithm to find the match substring.
*
*
* @param text The text string.
* @param pattern The pattern string.
* @return int The first match index.
Expand Down
65 changes: 64 additions & 1 deletion test/test_kmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,72 @@
#include "test_helper.h"
#include "alloc-testing.h"

void test_kmp()
extern int *kmp_calculate_next(const char *string, int len);

void test_kmp_calculate_next()
{
int *next;

next = kmp_calculate_next("abc", 3);
assert(next[0] == 0);
assert(next[1] == 0);
assert(next[2] == 0);
free(next);

next = kmp_calculate_next("aaa", 3);
assert(next[0] == 0);
assert(next[1] == 1);
assert(next[2] == 2);
free(next);

next = kmp_calculate_next("abababab", 8);
assert(next[0] == 0);
assert(next[1] == 0);
assert(next[2] == 1);
assert(next[3] == 2);
assert(next[4] == 3);
assert(next[5] == 4);
assert(next[6] == 5);
assert(next[7] == 6);
free(next);

next = kmp_calculate_next("abcdabd", 7);
assert(next[0] == 0);
assert(next[1] == 0);
assert(next[2] == 0);
assert(next[3] == 0);
assert(next[4] == 1);
assert(next[5] == 2);
assert(next[6] == 0);
free(next);

next = kmp_calculate_next("abcabaaabcda", 12);
assert(next[0] == 0);
assert(next[1] == 0);
assert(next[2] == 0);
assert(next[3] == 1);
assert(next[4] == 2);
assert(next[5] == 1);
assert(next[6] == 1);
assert(next[7] == 1);
assert(next[8] == 2);
assert(next[9] == 3);
assert(next[10] == 0);
assert(next[11] == 1);
free(next);
}

void test_kmp_string_match()
{
assert(kmp_string_match("abcabc", "abc") == 0);
assert(kmp_string_match("abcabc", "abcd") < 0);
assert(kmp_string_match("abcabcd", "abcd") == 3);
assert(kmp_string_match("bcabaaaa", "aaaa") == 4);
assert(kmp_string_match("bbcabcdababcdabcdabde", "abcdabd") == 13);
}

void test_kmp()
{
test_kmp_calculate_next();
test_kmp_string_match();
}

0 comments on commit 3a528b7

Please sign in to comment.