数学建模有关DNA序列k-mer index的问题

原问题是这样的:

给定一个DNA序列,这个系列只含有4个字母ATCG,如 S =“CTGTACTGTAT”。给定一个整数值k,从S的第一个位置开始,取一连续k个字母的短串,称之为k-mer(如k= 5,则此短串为CTGTA), 然后从S的第二个位置, 取另一k-mer(如k= 5,则此短串为TGTAC),这样直至S的末端,就得一个集合,包含全部k-mer 。 如对序列S来说,所有5-mer为{CTGTA,TGTAC,GTACT,TACTG,ACTGT,TGTAT}。

通常这些k-mer需一种数据索引方法,可被后面的操作快速访问。例如,对5-mer来说,当查询CTGTA,通过这种数据索引方法,可返回其在DNA序列S中的位置为{1,6}。

现在以文件形式给定 100万个 DNA序列,序列编号为1-1000000,每个基因序列长度为100 。

(1)要求对给定k, 给出并实现一种数据索引方法,可返回任意一个k-mer所在的DNA序列编号和相应序列中出现的位置。每次建立索引,只需支持一个k值即可,不需要支持全部k值。

(2)要求索引一旦建立,查询速度尽量快,所用内存尽量小。

(3)给出建立索引所用的计算复杂度,和空间复杂度分析。

(4)给出使用索引查询的计算复杂度,和空间复杂度分析。

(5)假设内存限制为8G,分析所设计索引方法所能支持的最大k值和相应数据查询效率。

(6)按重要性由高到低排列,将依据以下几点,来评价索引方法性能 

l 索引查询速度

l 索引内存使用

l 8G内存下,所能支持的k值范围

l 建立索引时间

本题主要是有关DNA序列的k-mer index查找问题,可将其转化为字符串的查找匹配模型问题,在处理字符串查找问题上,现在得到广泛认可的算法有适合处理字符串单模匹配的KMP算法,BM算法,以及适合处理字符串多模匹配的AC算法,WM算法等等。我们队以hash算法为基础,并作了几点优化和改进,使算法的内存占用有了一定程度的降低,查找效率也有很大提高。

本文中的算法和其它大多数算法一样,在建立索引时采用了hash算法,不同的是,我们利用一个hash函数(将DNA序列中的ATCG分别用二进制位的00,01,10,11来表示),这样做不但把DNA序列映射为一个整数,便于存储与查找,而且可以减少内存的使用,在k值取值较大时减耗尤其明显。在解决hash函数的地址冲突时,我们采用了拉链法,并且采用多级链表的形式,这样在确保查询效率较高的情况下,同样也可以减少内存的使用。

由于我们将DNA序列的ATCG分别表示为00,01,10,11,则我们可以将任意一个k-mer串映射为一个十进制整数。

假如我们的k-mer串长度为5,DNA序列ATCGA,则出于二进制左高位右低位的表示习惯考虑,我们也按照从左到右的顺序表示。则转化后如图所示。


在使用hash算法时,我们不可避免会遇到地址冲突的情况,在该算法中我们采用拉链法解决地址冲突。

 

我们首先以hash 表的数组元素为链表的头结点,然后采用直接插入法插入到有序链表中,假如已经存在一个key值为781的结点,如图所示。



为了进一步提高查找效率,我们将key值相同的元素采用头插法插入到一个新的链表中。

假如我们又插入一个key值为228的结点,如图。

数学建模有关DNA序列k-mer index的问题_第1张图片

好了,废话少说了,现将源码附录如下:

#include 

#include 

#include 

#include 

#include 

#define M 14557

typedef struct seq

{

int value;

int num;

char index;

struct seq *next1;

struct seq *next2;

}*Seq,Sequence;

void initNode(Seq *r,int i)

{

if(*r==NULL)

{

*r=(Seq)malloc(sizeof(Sequence));

(*r)->next1=NULL;

(*r)->next2=NULL;

}

}

void addNode(Seq *r,int v,int n,int i)

{

Seq s=(*r)->next1;

Seq p=*r;

if(s)

{

while(s&&v>s->value)

{

p=s;

s=s->next1;

}

if(s&&v==s->value)

{

Seq qsub=(Seq)malloc(sizeof(Sequence));

qsub->value=v;

qsub->index=(char)i;

qsub->num=n;

qsub->next1=NULL;

qsub->next2=s->next2;

s->next2=qsub;

}

else

{

Seq q=(Seq)malloc(sizeof(Sequence));

q->next1=s;

q->value=v;

q->index=(char)i;

q->num=n;

q->next2=NULL;

p->next1=q;

}

}

else

{

Seq q=(Seq)malloc(sizeof(Sequence));

q->next1=s;

q->value=v;

q->index=(char)i;

q->num=n;

q->next2=NULL;

(*r)->next1=q;

}

}

void consultNode(Seq s,int v,int *count)

{

Seq r;

if(s)

r=s->next1;

while(r&&v>=r->value)

{

if(v==r->value)

{

(*count)++;

printf("%d,%d\n",r->num,r->index);

Seq q=r->next2;

while(q)

{

(*count)++;

printf("%d,%d\n",q->num,q->index);

q=q->next2;

}

}

r=r->next1;

}

 

}

int main(){

int k,j,i;

int num,n;

int m=0;

int pos=1;

char s[200];

Seq seqarray[M]={NULL};

printf("请输入k值:\n");

scanf("%d",&k);

FILE *fp;

if((fp=fopen("h.fa","r"))==NULL)

{

printf("File open error!\n");

exit(1);

}

long int start=clock();

while(!feof(fp))

{

fscanf(fp,"%*s%s%d%d",s,&num,&j);

fgetc(fp);

fgetc(fp);

j=0;

m=0;

pos=1;

for(i=0;i

{

//建立索引的时间与k值有关,当k值较大时,当hash选择的p值为合适的质数时,建立索引的时间明显缩短

switch(fgetc(fp))

{

case 'A':

j+=2;

break;

case 'T':

m+=(int)pow(2,j);

j+=2;

break;

case 'C':

j++;

m+=(int)pow(2,j);

j++;

break;

case 'G':

m+=(int)pow(2,j);

j++;

m+=(int)pow(2,j);

j++;

break;

default:

break;

}

}

n=m%M;

initNode(&seqarray[n],n);

addNode(&seqarray[n],m,num,pos);

pos++;

while(pos<=100-k)

{

j-=2;

m>>=2;

switch(fgetc(fp))

{

case 'A':

j+=2;

break;

case 'T':

m+=(int)pow(2,j);

j+=2;

break;

case 'C':

j++;

m+=(int)pow(2,j);

j++;

break;

case 'G':

m+=(int)pow(2,j);

j++;

m+=(int)pow(2,j);

j++;

break;

default:

break;

}

n=m%M;

initNode(&seqarray[n],n);

addNode(&seqarray[n],m,num,pos);

pos++;

}

fgets(s,50,fp);

}

/////////////////////////////////////////////////////

getchar();

long int end=clock();

printf("*************建立索引%ldms*************\n",end-start); //计算建立索引时间

printf("请输入要查询的K\n");

gets(s);

m=0;

j=0;

for(i=0;i

switch(s[i])

{

case 'A':

j+=2;

break;

case 'T':

m+=(int)pow(2,j);

j+=2;

break;

case 'C':

j++;

m+=(int)pow(2,j);

j++;

break;

case 'G':

m+=(int)pow(2,j);

j++;

m+=(int)pow(2,j);

j++;

break;

default:

break;

}

n=m%M;

int count=0;

long int start1=clock();

consultNode(seqarray[n],m,&count);

printf("*****查询到记录%d*****\n",count);

long int end1=clock();

printf("*************查询时间%ldms*************\n",end1-start1); //计算查询时间

fclose(fp);

/////////////////////////////////////////////////////////

for(j=0;j释放内存从前往后

if(seqarray[j])

{

Seq p=seqarray[j]->next1;

Seq q;

Seq q1,q2;

while(p)

{

q=p->next1;

q1=p->next2;

while(q1)

{

q2=q1->next2;

free(q1);

q1=q2;

}

free(p);

p=q;

}

free(seqarray[j]);

 

}

return 0;

}




你可能感兴趣的:(数学建模)