3.4 马尔科夫链算法具体实现
在这一篇笔记中,我不打算说很多了。因为所有的理论知识都在3.3节中讨论过了。我在这里直接给出代码。另外给个彩蛋,某公司的面试题可就和这道特别类似哦。
在这里,我要说的是:
1.读取文本和代码之间的配合要掌握好
2.时间与空间消耗要掌握好
而对于C语言来说,最强的地方就是给了程序员对实现方式的完全控制,用它写出的程序趋向于快速。但是这也有代价,这就是C程序员必须做更多的工作,包括分配和释放存储,建立散列表和链接表,以及其他许多类似的事项。 C语言像一把飞快的剃刀,使用它,你可以创造优雅和高效的程序,或者弄出些一塌糊涂的东西来。
代码时间:
#include "stdafx.h"
#include "stdlib.h"
#include "string.h"
#include <iostream>
using namespace std;
enum
{
NPREF = 2, /*前缀中词的数量*/
NHASH = 99999, /*哈希表(散列表)大小*/
MAXGEN = 10000, /*录入的最大单词数量*/
MULTIPLIER = 31,
BUFSIZE = 100
};
char NONWORD = '\n';
typedef struct State State;
typedef struct Suffix Suffix;
/*散列表中的元素*/
struct State
{
/*前缀数量是确定的*/
char *pref[NPREF];
/*状态中要可以包含后缀及指向下一个前缀*/
Suffix *suf;
State *next;
};
/*后缀*/
struct Suffix
{
char *word;
/*可以构成多个后缀*/
Suffix *next;
};
/*这个就是散列表*/
State *statetab[NHASH] = { NULL };
unsigned int hash_number(char *s[NPREF]);
State *lookup(char *prefix[NPREF], int create);
void build(char *prefix[NPREF], FILE *f);
void add(char *prefix[NPREF], char *suffix);
void addsuffix(State *sp, char *suffix);
int main()
{
State *begin;
FILE *fp = NULL;
char box[NPREF][256];
fp = fopen("..\\test.txt", "r");
if (fp == NULL)
{
cout << "Error in opening the file" << endl;
exit(0);
}
begin = (State *)malloc(sizeof(State));
begin->next = NULL;
for (int i = 0; i < NPREF; i++)
{
fscanf(fp, "%s", box[i]);
begin->pref[i] = box[i];
//cout << begin->pref[i] << endl;
}
build(begin->pref, fp);
for (int i = 0; i < NHASH; i++)
{
if (statetab[i] != NULL)
{
cout << statetab[i]->pref[0] << " " << statetab[i]->pref[1] << " " << statetab[i]->suf->word << endl;
/*插入的位置同样正确*/
if (statetab[i]->suf->next != NULL)
{
cout << statetab[i]->suf->next->word << endl;
}
}
}
return 0;
}
/*哈希表键值计算函数*/
unsigned int hash_number(char *s[NPREF])
{
unsigned int h;
unsigned char *p;
int i;
h = 0;
for (i = 0; i < NPREF; i++)
{
for (p = (unsigned char *)s[i]; *p != '\0'; p++)
{
h = MULTIPLIER * h + *p;
}
}
/*返回哈希表中的键值*/
return h;
}
State *lookup(char *prefix[NPREF], int create)
{
int i, h;
State *sp = NULL;
h = hash_number(prefix);
for (sp = statetab[h]; sp != NULL; sp = sp->next)
{
for (i = 0; i < NPREF; i++)
{
/*如果输入的prefix和哈希表中对应的sp->pref[i]不相同*/
/*证明不是要找的前缀*/
/*注意前缀中含有两个单词*/
if (strcmp(prefix[i], sp->pref[i]) != 0)
{
break;
}
}
if (i == NPREF)
{
return sp;
}
}
/*在哈希表中没有与输入前缀相对应的部分时*/
if (create)
{
sp = (State *)malloc(sizeof(State));
for (i = 0; i < NPREF; i++)
{
sp->pref[i] = prefix[i];
}
sp->suf = NULL;
/*将新生成的状态(State)加入到散列表中(哈希表)*/
sp->next = statetab[h];
statetab[h] = sp;
}
return sp;
}
/*读取文档并且构建前缀、后缀*/
void build(char *prefix[NPREF], FILE *f)
{
char buf[100], fmt[10];
//sprintf(fmt, "%%%ds", sizeof(buf) - 1);
/*将文本中符合“fmt”定义的单词读取到buf中*/
/*fmt定义为最大99个字符,因为基本所有单词不会超过20个字符*/
while (fscanf(f, "%s", buf) != EOF)
{
/*将符合“fmt”标准的单词复制到buf中*/
/*使用字符串复制函数strdup*/
add(prefix, _strdup(buf));
}
}
/*添加函数,将会把整篇文档都加到散列表中*/
/*遍历文档,文章中所有前缀都能涉及*/
void add(char *prefix[NPREF], char *suffix)
{
/*定位到prefix,并且把后缀suffix加入到prefix对应的sp中*/
State *sp;
sp = lookup(prefix, 1);
addsuffix(sp, suffix);
/*前缀的更新*/
memmove(prefix, prefix + 1, (NPREF - 1) * sizeof(prefix[0]));
prefix[NPREF - 1] = suffix;
}
/*为某一个特定的前缀添加后缀*/
void addsuffix(State *sp, char *suffix)
{
Suffix *suf;
suf = (Suffix *)malloc(sizeof(Suffix));
suf->word = suffix;
suf->next = sp->suf;
sp->suf = suf;
}