如何确定中文字符串的相似度
作者:admin 日期:2007-12-21
摘要
在数据挖掘的研究中,我们往往需要判断文章是否雷同,对类似文章或短句进行归类处理等,这其中就会遇到这样的问题:如何确定两个字符串之间的相似程度。
本文综合作者的实际工作经验和数据挖掘理论,结合中文字符串特性介绍一套相对完整的方法,以解决上述问题.。
分析
最简单的问题求解
字符串由一组不同含义的单词组成,它不同于数值型变量,可以用一个特定的数值来确定它的大小或位置,所以用何种方式来描述两个字符串之间的距离,成为了一个值得探讨的问题。
通常情况下,用于分析的数据类型有如下几种:区间标度遍历、二元变量、标称型变量、序数型变量、比例标度型变量、混合类型变量等。
综合这些变量类型,本文认为字符串变量更适合于归类于二元变量,我们可以利用分词技术将字符串分成若干个单词,每个独立的单词作为二元变量的一个属性。我们把所有单词设定为一个二元变量属性集合R,字符串1和字符串2的单词包含于这个集合R。设q是字符串1和字符串2中都存在的单词的总数,s是字符串1中存在,字符串2中不存在的单词总数,r是字符串2中存在,字符串1中不存在的单词总数,t是字符串1和字符串2中都不存在的单词总数。我们称 q,r,s,t为字符串比较中的4个状态分量。 如图1所示:
由于两个字符串都不存在的单词对两个字符串的比较没有任何作用,所以忽略t,于是我们采用非恒定的相似度评价系数(Jaccard系数)来描述两个字符串见的相异度表示公式为
相异度 = r+s / (q+r+s),不难推断,他们的形似度公式为
相似度=q/(q+r+s) 公式1
字符串相似度的比较问题
作者:admin 日期:2007-12-21
字符串相似度的比较问题
{
int subLen;
int Router;
};
{
//Get table
int len1 = strlen(str1);
int len2 = strlen(str2);
Node ** table;
table = new Node * [len1 + 1];
for (int i = 0;i <= len1;i++)
table[i] = new Node[len2 + 1];
for (int i = 0;i <= len1;i++)
table[i][0].subLen = 0;
for (int i = 0;i <= len2;i++)
table[0][i].subLen = 0;
for (int i = 1;i <= len1;i++)
for (int j = 1;j <= len2;j++)
{
if (str1[i - 1] == str2[j - 1])
{
table[i][j].subLen = table[i- 1][j - 1].subLen + 1;
table[i][j].Router = THIS;
}
else if (table[i][j - 1].subLen < table[i - 1][j].subLen)
{
table[i][j].subLen = table[i - 1][j].subLen;
table[i][j].Router = UP;
}
else
{
table[i][j].subLen = table[i][j - 1].subLen;
table[i][j].Router = LEFT;
}
}
int minIncream = 50;
int IncreamTime = 0;
char *str = new char[minIncream];
for (int i = 0;i < minIncream;i++)
str[i] = '\0';
int k = len1,j = len2,pos = 0;
while (k >= 1 && j >= 1)
{
if (table[k][j].Router == THIS)
{
if (strlen(str) + 1 == (IncreamTime + 1) * minIncream)
{
IncreamTime++;
char *t = new char[minIncream * (IncreamTime + 1)];
for (int s = 0;s < minIncream * IncreamTime;s++)
t[s] = str[s];
for (int s = minIncream * IncreamTime;s < minIncream * (IncreamTime + 1);s++)
t[s] = '\0';
delete[] str;
str = t;
}
str[pos++] = str1[k - 1];
k--;
j--;
}
else if (table[k][j].Router == LEFT)
j--;
else
k--;
}
char *similarStr = new char[strlen(str) + 1];
for (int i = strlen(str) - 1,j = 0;i >= 0;i--,j++)
similarStr[j] = str[i];
similarStr[strlen(str)] = '\0';
for (int i = 0;i <= len1;i++)
delete[] table[i];
delete[] table;
delete[] str;
return similarStr;
}
{
int pos1;
int pos2;
int len;
Node *next;
};
{
Node *front;
Node *rear;
int maxLen;
};
void InsertQueue(Queue &q,int len,int pos1,int pos2);
void DeleteQueue(Queue &q);
void orderQueue(Queue &q);
void EmptyQueue(Queue &q);
{
q.front = q.rear = 0;
q.maxLen = -1;
}
{
Node *node = new Node;
node->pos1 = pos1;
node->pos2 = pos2;
node->len = len;
node->next = 0;
if (len > q.maxLen)
q.maxLen = len;
if (q.front == 0)
q.front = node;
else
q.rear->next = node;
q.rear = node;
}
{
if (q.front)
{
Node *temp = q.front;
q.front = q.front->next;
if (temp == q.rear)
q.rear = 0;
delete temp;
}
}
{
Node *node = q.front;
Node *preNode = 0;
while (node)
{
if (node->len > q.maxLen)
q.maxLen = node->len;
node = node->next;
}
while (node)
if (node->len < q.maxLen)
{
if (preNode == 0)
{
DeleteQueue(q);
node = q.front;
}
else
{
preNode->next = node->next;
if (node == q.rear)
q.rear = preNode;
Node *temp = node;
node = node->next;
delete temp;
}
}
else
{
preNode = node;
node = node->next;
}
}
{
while (q.front)
DeleteQueue(q);
}
{
int len1 = strlen(str1);
int len2 = strlen(str2);
Queue q;
InitQueue(q);
for (int i = 0;i < len1;i++)
for (int j = 0;j < len2;j++)
if (str1[i] == str2[j])
InsertQueue(q,0,i,j);
int curLen;
do
{
curLen = q.maxLen;
Node *node = q.front;
while (node)
{
if (node->pos1 + node->len + 1 < len1 && node->pos2 + node->len + 1 < len2 && str1[node->pos1 + node->len + 1] == str2[node->pos2 + node->len + 1])
node->len++;
node = node->next;
}
OrderQueue(q);
}while (curLen < q.maxLen);
char *returnValue = 0;
if (q.front)
{
returnValue = new char[q.maxLen + 2];
strncpy(returnValue,&str1[q.front->pos1],q.front->len + 1);
returnValue[q.front->len + 1] = '\0';
}
EmptyQueue(q);
return returnValue;
}
VC中编写COM供ASP使用时的注意问题...
作者:admin 日期:2007-12-20
Request...
作者:admin 日期:2007-09-22
DDE数据交换
作者:admin 日期:2007-09-16
DDE(Dynamic data exchange)的工作原理是:
甲方申请一块全局内存,然后把内存指针postmessage到乙方,
乙方根据收到的指针访问那块全局内存。
Win32程序模型
作者:admin 日期:2007-09-08
在WinMain()函数中,程序所进行的最重要工作是注册窗口类,从而把自定义的窗口过程提供给Windows。然后程序调用Windows创建和显示窗口,由此启动同用户的交互过程。在消息循环中,程序不断取得消息,但并不进行处理,而是将其发回Windows,由Windows将消息发给相应的窗口过程。消息循环的作用在于控制生命期,如果没有消息循环,进程将立即结束。
在较高层次上来看,一个可扩展的系统会给模块提供资源和自由,而模块应当配合系统的整体结构。程序执行时,Windows会为其创建进程,分配资源,并调用WinMain()。WinMain()是进程入口,也是进程出口,在此期间进程可以做任何事情,但是为了使用Windows提供的各种便利,它必须符合Windows程序模型,将自己的运行结合到Windows环境中。作为进程出口, WinMain()决定着程序生命期。一个提供窗口过程而等待Windows调用的程序如何维持和结束自己的生命期呢,应该由消息来决定。当进程没有要处理的消息时,它应该等待,所以WinMain()必须知道有没有消息,Windows发给窗口过程的消息不能绕过WinMain();当进程收到特定的消息时,它结束生命期,所以WinMain()还应该了解消息的内容。这正是GetMessage()所做的,如果取不到消息就阻塞,如果取到 WM_QUIT消息就返回0,结束消息循环。那么如果取到普通的消息呢,由WinMain()直接调用窗口过程不可以吗?这种做法有悖于程序由 Windows调用的基本思想,而实际上也会出现问题。一个窗口程序可能有很多窗口类,一些窗口类及其窗口过程是程序自定义的,另一些则是在 Windows内部定义的,程序看不到其窗口过程,比如各种控件窗口。窗口程序运行起来以后,这些窗口类互相配合,它们通信的方式就是消息。由于消息指向的窗口过程可能是自定义的,也可能是Windows内部的,只有Windows才能把它们都送到目的地,并保持发送方式的一致性。所以WinMain() 取到消息后,通过DispatchMessage()将其发回Windows,由Windows为其调用适当的窗口过程,直到窗口过程调用后返回 Windows,DispatchMessage()才返回。(Windows调用窗口过程之后控制首先返回Windows,由WinMain()调用窗口过程之后控制保持在程序中,这种区别是否也有作用?不过经我试验,在一个Win32 SDK的Hello程序中改由WinMain()调用窗口过程,没有发现什么问题)
MVC模式和MFC文档/视图结构
作者:admin 日期:2007-09-08
从MVC的形成过程来看,最初只有模型和视图两个元素。模型封装了数据并提供操作接口,视图用来表现数据和接收用户请求。模型是独立的,而视图依赖于模型:从模型获取数据进行显示;向模型发送用户请求,并根据返回结果刷新自己。
需要用多个视图表现同一模型时,情况发生了变化:一个视图修改数据以后,不但本身要刷新,其他所有视图也要刷新。如果由该视图通知其他视图,它就需要知道其他所有视图,由于每个视图都可能发出修改,每个视图都要知道其他所有视图,这种关联过于复杂,不但难以维护,而且不便于增加新的视图。如果让模型通知所有视图更新,可能会影响模型的独立性。用观察者(Observer)模式可以解决上述矛盾,从而实现:由模型通知视图,而模型不依赖于具体的视图,具体视图之间相互独立。
Form窗体的KeyPreview属性的妙用
作者:admin 日期:2007-08-31
GDI+图像处理初级系列—灰度图像处理
作者:admin 日期:2007-08-29
如果要将彩色图像转换为灰度图像,只要将图像中的每个像素取出来,然后取像素的R、G、B颜色分量,利用如下公式计算灰度值:
int gray = r*0.3 + g*0.59 + b*0.11;






