1.KMP查找算法
1.1 用途
- 給定一個主串,一個查找串,需要找到查找串在主串中第一次出現的位置(下標)。
1.2 方法
- 要求主串不回頭(就是隻想主串的指針不向後移動),查找串(匹配串)回頭跳轉。
- 這是一種以空間換時間的方法。
1.3 串的前綴與後綴
- 1.字符串的前綴是指字符串的任意首部,比如字符串“abbc”的前綴有 a ab abb ;
- 2.字符串的後綴是指字符串的任意尾部,比如字符串“abbc”的後綴有 c bc bbc ;
1.4 KMP算法就是找兩個串中的最大相等的前綴和後綴。
1.5 KMP算法的核心就是計算 Next 數組。
1.6 求 “aababaaabbcabbaa” 的 Next 數組
- 1.即使用一個和字符串等長的數組來存儲當前字符串前綴與後綴最大的相等長度。
- 2.Next 數組爲 [0101012230010012] ;
1.7 使用 Next 數組進行匹配
1.8 KMP算法步驟
int* GetNext(char* match)
{
int* p_next = NULL;
p_next = (int*)malloc(sizeof(int)*strlen(match));
p_next[0] = 0;
int i = 1;
int j = i - 1;
while(i < strlen(match))
{
if(match[i] == match[p_next[j]])
{
p_next[i] = p_next[j] + 1;
i++;
j = i - 1;
}
else if(p_next[j] == 0)
{
p_next[i] = 0;
i++;
j = i - 1;
}
else
{
j = p_next[j] - 1;
}
}
return p_next;
}
int KMP(char* str, char* match)
{
if(str == NULL || match == NULL)return -1;
int* p_next = NULL;
p_next = GetNext(match);
int i = 0;
int j = 0;
while(i < strlen(str) && j < strlen(match))
{
if(str[i] == match[j])
{
i++;
j++;
}
else
{
if(j == 0)
{
i++;
}
else
{
j = p_next[j-1];
}
}
}
if(j == strlen(match))
{
return i - j;
}
else
{
return -1;
}
}
2.Sunday算法
2.1 使用一個256維的數組來存儲從右到左match的字母第一次出現的位置。
2.2 實現算法
int Sunday(char* str, char* match)
{
if(str == NULL || match == NULL)return -1;
int* p_next = NULL;
p_next = (int*)malloc(sizeof(int)*256);
memset(p_next, -1, sizeof(int)*256);
int i;
for(i=0; i<strlen(match); i++)
{
p_next[match[i]] = i;
}
int j;
int k;
i = 0;
j = 0;
while(i < strlen(str) && j < strlen(match))
{
k = i;
while(str[i] == match[j] && i < strlen(str) && j < strlen(match))
{
i++;
j++;
}
if(j == strlen(match))
{
return i - j;
}
if(k+strlen(match) < strlen(str))
{
k = k + strlen(match) - p_next[str[k+strlen(match)]];
i = k;
j = 0;
}
else
{
return -1;
}
}
}
3.字典樹
3.1 功能
3.2 查找樹沒有空樹的概念
3.3 每個節點不是字母,而是代表字母
3.4 實現
typedef struct trie
{
int n_count;
char* str;
struct trie* p_character[26];
}TrieTree;
TrieTree* GetNode()
{
TrieTree* p_node = NULL;
p_node = (TrieTree*)malloc(sizeof(TrieTree));
memset(p_node, 0, sizeof(TrieTree));
return p_node;
}
void AddWord(TrieTree* p_tree, char* str)
{
int i = 0;
TrieTree* p_temp = NULL;
while(i < strlen(str))
{
if(p_tree->p_character[str[i]-97] == NULL)
{
p_tree->p_character[str[i]-97] = GetNode();
}
p_tree = p_tree->p_character[str[i]-97];
i++;
}
p_tree->str = str;
p_tree->n_count++;
}
TrieTree* CreateTrie(char* str[], int len)
{
if(str == NULL || len <= 0)return NULL;
TrieTree* p_tree = NULL;
p_tree = GetNode();
int i;
for(i=0; i<len; i++)
{
AddWord(p_tree, str[i]);
}
return p_tree;
}
void Search(TrieTree* p_tree, char* str)
{
if(p_tree == NULL || str == NULL)return;
int i = 0;
while(i < strlen(str))
{
if(p_tree->p_character[str[i]-97] == NULL)
{
printf("TAT failed.\n");
return;
}
p_tree = p_tree->p_character[str[i]-97];
i++;
}
if(p_tree->n_count != 0)
{
printf("%s\n", p_tree->str);
return;
}
else
{
printf("QAQ failed.\n");
return;
}
}
void Traversal(TrieTree* p_tree)
{
if(p_tree == NULL)return;
if(p_tree->n_count != 0)
printf("%s\n", p_tree->str);
int i;
for(i=0; i<26; i++)
Traversal(p_tree->p_character[i]);
}