字元RNA--自动机,trie图,可学习算法

wolfkain 2009-07-29 09:34:14
字元RNA链


自动机,tire图,可学习算法--作者:周强

本算法基于自动机理论,类似于trie树,因为tried树空间消耗过大,而改用了本数据结构和算法。
本算法具有以下特点:
1.每个节点都为有效节点,无叶子节点(trie树很多叶子节点占用大量空间)。
2.具有编码和解码能力(trie树不具备解码能力)。
3.在字元最大容量内(suffix最大值),具备节点大小及数量和字元数无关的性质
(trie树是节点大小跟字元数量直接相关的)。
4.编码或串匹配时间复杂度最坏O(sum(study_index(S[i]))),最好O(len(S))
S表示串,S[i]表示串中第i个字元,len()求串长,sum()求和,study_index()字元学习的序。
解码时间复杂度为O(len(S));
5.可具备最近访问最小匹配时间复杂度的能力(可选)。

数据结构:
typedef struct {
unsigned short linker;//指向有相同前缀的下一个节点
unsigned short jumper;//指向由本节点前缀+后缀构成新的前缀的节点,也是本节点的编码,状态函数的转移状态
unsigned short prefix;//本节点的前缀
unsigned char suffix;//本节点的后缀
unsigned char bflags;//节点的标志,使用者可设置
} Base;

typedef struct {
Base *base;//序列
unsigned short allocs;//分配的节点个数
unsigned short limits;//限制数
unsigned short header;//字元个数
unsigned short nexter;//可学习节点的index
unsigned short jumper[ELEMENTS];//串首字元,第一次出现的节点偏移
} MRNA;

每个Base节点由五个成员,每个节点是一个状态转移函数F(prefix,suffix) = jumper,
同时节点的linker指向和本节点具有相同前缀prefix的下一个节点。图示如下:
|-----------------------------------------------+
V |
jumper -> linker -----------------------> ...... -------->linker
prefix |----------------+ prefix
suffix V | suffix
jumper -> linker ->......-> linker jumper
prefix prefix
suffix suffix
jumper jumper
bflags成员是个标志,用来设置编码分类或其他用途,由使用者定义。
套用生物学概念,Base节点代表一个碱基,对应的MRNA就是一个由很多碱基依次排列构成的大分子信使RNA。
MRNA结构中base是存放base节点的指针,allocs用来记录分配的节点数,limits限制最大节点数
,这两个在本文示例中未做使用,header字元的个数,nexter下一个可学习的节点偏移,jumper是串中第一个字元首次出现对应的跳转--在base中的偏移。

学习原理(编码):
当F(prefix,suffix)转移状态还未定义时,获取一个当前可学习节点,并设置该节点的相关参数,返回该节点的偏移作为状态函数的转移状态,可学习节点后移。
如果已经定义,检查prefix和suffix是否和该节点的相等,相等则返回该节点的jumper
否则,如果prefix相等说明在相同prefix的链中插入过或还没建立这个节点,需要转入linker链中查找,不存在则学习。
否则,具有相同prefix的链在下一层中,转入该节点的jumper,然后在jumper到的节点的linker中搜索,不存在则学习。

解码原理:
给出一个编码,由于编码和对应节点的偏移是线性关系,所以可直接定位其对应的节点,节点中包含上一个状态prefix和对应的后缀suffix,所以向前回溯能得到串的所有后缀,于是可得到串。


一下为26个字母的示例代码:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
unsigned short jumper;
unsigned short linker;
unsigned short prefix;
unsigned char suffix;
unsigned char bflags;
} BASE;
typedef struct
{
BASE *base;
unsigned short allocs;
unsigned short limits;
unsigned short nexter;
unsigned short header;
unsigned short jumper[26];
} MRNA;
#define RNA_Study(R,prefix,suffix) \
do { \
R->base[R->nexter].prefix = prefix; \
R->base[R->nexter].suffix = suffix; \
R->base[R->nexter].linker = R->nexter; \
R->base[R->nexter].jumper = R->nexter; \
return R->header + R->nexter++; \
} while(0)
int RNA_Prefix(MRNA *h,int prefix,int suffix,int study)
{
int linker = prefix;
unsigned short *jumper = NULL;
if(linker < h->header)
{
if(h->jumper[linker] == 0xFFFF)
{
if(study)
{
h->jumper[linker] = h->nexter;
RNA_Study(h,prefix,suffix);
}
return -1;
}
else
{
linker = h->jumper[linker];
}
}
else
{
linker -= h->header;
}
while(linker < h->nexter)
{
if(h->base[linker].suffix == suffix &&
h->base[linker].prefix == prefix )
{
return h->header + linker;
}
if(h->base[linker].prefix == prefix)
{
if(h->base[linker].linker == linker)
{
if(study)
{
h->base[linker].linker = h->nexter;
RNA_Study(h,prefix,suffix);
}
return -1;
}
linker = h->base[linker].linker;
}
else
{
if(h->base[linker].jumper == linker)
{
if(study)
{
h->base[linker].jumper = h->nexter;
RNA_Study(h,prefix,suffix);
}
return -1;
}
linker = h->base[linker].jumper;
}
}
return -1;
}
int RNA_Prefix_(MRNA *h,int prefix,int suffix)
{
int linker = prefix;
int jumper = linker;
if(linker < h->header)
{
if(h->jumper[linker] == 0xFFFF)
{
h->jumper[linker] = h->nexter;
h->base[h->nexter].prefix = prefix;
h->base[h->nexter].suffix = suffix;
h->base[h->nexter].linker = h->nexter;
h->base[h->nexter].jumper = h->nexter;
return h->header + h->nexter++;
}
else
{
linker = h->jumper[linker];
}
}
else
{
linker -= h->header;
}
jumper = linker;
while(linker < h->nexter)
{
if(h->base[linker].suffix == suffix &&
h->base[linker].prefix == prefix )
{
if(prefix < h->header)
h->jumper[prefix] = linker;
else
h->base[jumper].jumper = linker;
return h->header + linker;
}
if(h->base[linker].prefix == prefix)
{
if(h->base[linker].linker == jumper)
{
h->base[linker].linker = h->nexter;

h->base[h->nexter].prefix = prefix;
h->base[h->nexter].suffix = suffix;
h->base[h->nexter].linker = jumper;
h->base[h->nexter].jumper = h->nexter;
if(prefix < h->header)
h->jumper[prefix] = h->nexter;
else
h->base[jumper].jumper = h->nexter;
return h->header + h->nexter++;
}
linker = h->base[linker].linker;
}
else
{
if(h->base[linker].jumper == linker)
{
h->base[linker].jumper = h->nexter;

h->base[h->nexter].prefix = prefix;
h->base[h->nexter].suffix = suffix;
h->base[h->nexter].linker = h->nexter;
h->base[h->nexter].jumper = h->nexter;
return h->header + h->nexter++;
}
jumper = linker = h->base[linker].jumper;
}
}
printf("bug:this branch can't be reached\n");
return -1;
}
int RNA_Suffix(MRNA *h,int prefix)
{
while(prefix >= h->header)
{
prefix -= h->header;
printf("%c",h->base[prefix].suffix + 'A');
prefix = h->base[prefix].prefix;
}
printf("%c",prefix + 'A');
return 0;
}
int main(int argc,char *argv[])
{
MRNA mRNA;
int suffix;
int prefix = -1;
mRNA.nexter = 0;
mRNA.header = 26;
mRNA.limits = 4096;
mRNA.allocs = 4096;
memset(mRNA.jumper,0xFF,mRNA.header * 2);
mRNA.base = malloc(mRNA.allocs * sizeof(BASE));
while(suffix = getchar())
{
if(isalpha(suffix))
{
suffix = toupper(suffix) - 'A';
if(prefix != -1)
{
printf("f(%d,%d)",prefix,suffix);
prefix = RNA_Prefix_(&mRNA,prefix,suffix);
printf("=%d\n",prefix);
}
else
{
prefix = suffix;
}
}
else
{
if(prefix != -1)
{
RNA_Suffix(&mRNA,prefix);
printf("<==>%d\n",prefix);
prefix = -1;
}
if(suffix == '#') break;
}
}
printf("Bases = %d\n",mRNA.nexter);
free(mRNA.base);
return 0;
}

RNA_Prefix为工作函数,学习和匹配都是这个函数负则,study = 0是就禁止了学习
RNA_Prefix_是为使最近访问过的串匹配时间复杂度最小而做过改进的工作函数。
RNA_Suffix是解码函数,给出对应编码的串的倒序。
RNA_Study是个宏,用于学习,也就是添加新节点。

注意:示例程序分配了4096个节点,但未做溢出检查,示例数据量过大可能溢出,造成程序段错误。


--------------------------------------------------------------------------------


本算法属原创,转载请注明算法发明人:周强
...全文
216 13 打赏 收藏 转发到动态 举报
写回复
用AI写文章
13 条回复
切换为时间正序
请发表友善的回复…
发表回复
jkaic98 2009-08-05
  • 打赏
  • 举报
回复
收藏一下。
ToBeTough 2009-08-04
  • 打赏
  • 举报
回复
怎么看呢?
wolfkain 2009-08-01
  • 打赏
  • 举报
回复
好少人看啊,失望
wolfkain 2009-07-30
  • 打赏
  • 举报
回复
顶,
qq675927952 2009-07-30
  • 打赏
  • 举报
回复
友情up
  • 打赏
  • 举报
回复
嗯,有道理。
[Quote=引用 3 楼 fire_woods 的回复:]
关于代码一点疑问
#define RNA_Study(R,prefix,suffix) \
do { \
R->base[R->nexter].prefix = prefix; \
R->base[R->nexter].suffix = suffix; \
R->base[R->nexter].linker = R->nexter; \
R->base[R->nexter].jumper = R->nexter; \
return R->header + R->nexter++; \
} while(0)

这个不是铁定执行一次吗?为什么要这么写呢.

关于算法, 算法将TRIE树的每个节点的指向孩子的指针数组换成了多个链表的数组集合[/Quote]
wolfkain 2009-07-29
  • 打赏
  • 举报
回复
这个宏是这样的,为了看起来像个函数
效率确实没tire树高,
4.编码或串匹配时间复杂度最坏O(sum(study_index(S[i]))),最好O(len(S))
S表示串,S[i]表示串中第i个字元,len()求串长,sum()求和,study_index()字元学习的序。
解码时间复杂度为O(len(S));
但具有其他很多TIRE树不具备的东西。如编码,解码,比如说我个以对串编码,然后让别人使用这个编码,解码时间复杂度和TIRE树是一样的。
fire_woods 2009-07-29
  • 打赏
  • 举报
回复
关于代码一点疑问
#define RNA_Study(R,prefix,suffix) \
do { \
R->base[R->nexter].prefix = prefix; \
R->base[R->nexter].suffix = suffix; \
R->base[R->nexter].linker = R->nexter; \
R->base[R->nexter].jumper = R->nexter; \
return R->header + R->nexter++; \
} while(0)

这个不是铁定执行一次吗?为什么要这么写呢.

关于算法, 根据我的理解, 算法将TRIE树的每个节点的指向孩子的指针数组换成了多个链表的数组集合.
不知道理解是否有误, 这样的话,每个节点的存储空间可能变小了,但是搜索速度会变慢.

另外TRIE树最终的子节点是指向数据的指针,其他的看的不是很懂,请指教.
dhb008 2009-07-29
  • 打赏
  • 举报
回复
帮顶
wolfkain 2009-07-29
  • 打赏
  • 举报
回复
自己顶,呵呵
fire_woods 2009-07-29
  • 打赏
  • 举报
回复
哦,原来如此,没有看过linux的源代码,多谢指点.
medie2005 2009-07-29
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 fire_woods 的回复:]
关于代码一点疑问
#define RNA_Study(R,prefix,suffix) \
do { \
R->base[R->nexter].prefix = prefix; \
R->base[R->nexter].suffix = suffix; \
R->base[R->nexter].linker = R->nexter; \
R->base[R->nexter].jumper = R->nexter; \
return R->header + R->nexter++; \
} while(0)

这个不是铁定执行一次吗?为什么要这么写呢.

关于算法, 根据我的理解, 算法将TRIE树的每个节点的指向孩子的指针数组换成了多个链表…
[/Quote]
fire_woods看来没看过linux源码,这是linux源码内的一个技巧,以保证多语句宏可在各种情况下都适用。
pb生成二维码源代码 二维码是QR 二维码 QR码是二维条码的一种,QR 来自英文 “Quick Response” 的缩写,即快速反应的意思,源自发明者希望 QR 码可让其内容快速被解码。QR码比普通条码可储存更多资料,亦无需像普通条码般在扫描时需直线对准扫描器。 QR 码呈正方形,只有黑白两色。在4个角落的其中3个,印有较小,像“回”字的的正方案。这 3 个是帮助解码软件定位的案,使用者不需要对准,无论以任何角度扫描,资料仍可正确被读取。 QR码最常见于日本,并为目前日本最流行的二维空间条码。QR码比普通条码可储存更多资料。 QR码呈正方形,只有黑白两色。在4个角落的其中3个,印有较小,像“回”字的的正方案。这3个是帮助解码软件定位的案,使用者不需要对准,无论以任何角度扫描,资料仍可正确被读取。 日本QR码的标准JIS X 0510在1999年1月发布,而其对应的ISO国际标准ISO/IEC18004,则在2000年6月获得批准。根据Denso Wave公司的网站资料,QR码是属于开放式的标准,QR码的规格公开,而由Denso Wave公司持有的专利权益,则不会被执行。 除了标准的QR码之外,也存在一种称为“微型QR码”的格式,是QR码标准的缩小版本,主要是为了无法处理较大型扫描的应用而设计。微型QR码同样有多种标准,最高可储存35个字元

33,008

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧