前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >序列比对(18)重复匹配问题的补充说明

序列比对(18)重复匹配问题的补充说明

作者头像
一只羊
发布2019-09-24 17:26:12
6850
发布2019-09-24 17:26:12
举报
文章被收录于专栏:生信了生信了

前文介绍了重复匹配问题的动态规划算法,但是遗留了重复结果输出的问题。本文对该问题进行了补充说明。

前文《序列匹配(五)——重复匹配问题的动态规划算法》介绍了重复匹配问题的动态规划算法。

但是这个公式在回溯时会出现重复结果输出的问题,比如:

校正公式和代码

这样的公式目前还没有出现重复结果输出的问题:

相应的代码放在了文末。

对比对总长度的估计

实现代码

代码语言:javascript
复制
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#define MAXSEQ 1000
#define GAP_CHAR '-'
#define UNALIGN_CHAR '.'
#define max2(a, b) ((a) > (b) ? (a) : (b))

// 对空位的罚分是线性的
struct FUnit {
    int W0;   // X{i-1}不参与联配
    int* Wj;      // 跳转到A(i - 1, j)
    int nj;       // Wj数组的大小
    float M;      // F(i,0)的值
};
typedef struct FUnit* pFUnit;

// 00000001  F(i, 0) + s(i, j)
// 00000010  是否往左回溯一格
// 00000100  是否往左上回溯一格
// 00001000  是否往上回溯一格
struct AUnit {
    int Wi;      // 不同的bit代表不同的回溯方式
    float M;
};
typedef struct AUnit* pAUnit;

float gap = -2.5;     // 对空位的罚分
float match = 5;
float unmatch = -4;

void strUpper(char *s);
float maxArray(float *a, int n);
float getFScore(char a, char b);
void printFAlign(pFUnit* f, pAUnit** a, const int i, char* s, char* r, char* saln, char* raln, int n, int flag);
void printAAlign(pFUnit* f, pAUnit** a, const int i, const int j, char* s, char* r, char* saln, char* raln, int n);
void align(char *s, char *r, float t);

int main() {
    char s[MAXSEQ];
    char r[MAXSEQ];
    float t;
    printf("The 1st seq: ");
    scanf("%s", s);
    printf("The 2nd seq: ");
    scanf("%s", r);
    printf("T (threshold): ");
    scanf("%f", &t);
    align(s, r, t);
    return 0;
}

void strUpper(char *s) {
    while (*s != '\0') {
        if (*s >= 'a' && *s <= 'z') {
            *s -= 32;
        }
        s++;
    }
}

float maxArray(float *a, int n) {
    float max = a[0];
    int i;
    for (i = 1; i < n; i++) {
        if (a[i] > max)
            max = a[i];
    }
    return max;
}

// 替换矩阵:match分值为5,mismatch分值为-4
// 数组下标是两个字符的ascii码减去65之后的和
float FMatrix[] = {
    5, 0, -4, 0, 5, 0, -4, 0, -4, 0,
    0, 0, 5, 0, 0, 0, 0, 0, 0, -4,
    0, -4, 0, 0, 0, -4, 0, 0, 0, 0,
    0, 0, 0, 0, 0, 0, 0, 0, 5
};

float getFScore(char a, char b) {
    return FMatrix[a + b - 'A' - 'A'];
}

void printFAlign(pFUnit* f, pAUnit** a, const int i, char* s, char* r, char* saln, char* raln, int n, int flag) {
    // flag: 是否是从F(i+1,0)跳转过来,而不是从F(i, 0) + s(i, j)跳转过来
    int k;
    pFUnit p = f[i];
    //printf("i=%d, n=%d, flag=%d\n", i, n, flag);
    if (! i) {  // 保证序列s的每个字符都比对上
        for (k = n - 1; k >= 0; k--)
            printf("%c", saln[k]);
        printf("\n");
        for (k = n - 1; k >= 0; k--)
            printf("%c", raln[k]);
        printf("\n\n");
        return;
    }
    if (flag) {
        saln[n] = s[i - 1];
        raln[n] = UNALIGN_CHAR;
    }
    if (p->W0) 
        printFAlign(f, a, i - 1, s, r, saln, raln, n + flag, 1);
    for (k = 0; k < p->nj; k++)
        if (p->Wj[k])
            printAAlign(f, a, i - 1, k + 1, s, r, saln, raln, n + flag);
}

void printAAlign(pFUnit* f, pAUnit** a, const int i, const int j, char* s, char* r, char* saln, char* raln, int n) {
    int k;
    pAUnit p = a[i][j];
    //printf("i=%d, j=%d, n=%d\n");
    if (! i) {  // 保证序列s的每个字符都比对上
        for (k = n - 1; k >= 0; k--)
            printf("%c", saln[k]);
        printf("\n");
        for (k = n - 1; k >= 0; k--)
            printf("%c", raln[k]);
        printf("\n\n");
        return;
    }
    if (! j) {  // F(i, 0) + d
        saln[n] = s[i - 1];
        raln[n] = GAP_CHAR;
        printFAlign(f, a, i, s, r, saln, raln, n + 1, 0);
    } else {
        if (p->Wi & 1) {    // F(i, 0) + s(i, j)
            saln[n] = s[i - 1];
            raln[n] = r[j - 1];
            printFAlign(f, a, i, s, r, saln, raln, n + 1, 0);
        }
        if (p->Wi & 2) {    // 向上回溯一格
            saln[n] = s[i - 1];
            raln[n] = GAP_CHAR;
            printAAlign(f, a, i - 1, j, s, r, saln, raln, n + 1);
        }
        if (p->Wi & 4) {    // 向左上回溯一格
            saln[n] = s[i - 1];
            raln[n] = r[j - 1];
            printAAlign(f, a, i - 1, j - 1, s, r, saln, raln, n + 1);
        }
        if (p->Wi & 8) {    // 向左回溯一格
            saln[n] = GAP_CHAR;
            raln[n] = r[j - 1];
            printAAlign(f, a, i, j - 1, s, r, saln, raln, n + 1);
        }
    }
}

void align(char *s, char *r, float t) {
    int i, j, k;
    int m = strlen(s);
    int n = strlen(r);
    float tm[4];
    float em;   // F(m + 1, 0)
    pFUnit* fUnit;
    pAUnit** aUnit;
    char* salign;
    char* ralign;
    int alnSize = m + floor(m * abs(match / gap));
    // 初始化
    if ((fUnit = (pFUnit*) malloc(sizeof(pFUnit) * (m + 1))) == NULL || \
        (aUnit = (pAUnit**) malloc(sizeof(pAUnit*) * (m + 1))) == NULL) {
        fputs("Error: Out of space!\n", stderr);
        exit(1);
    }
    for (i = 0; i <= m; i++) {
        if ((fUnit[i] = (pFUnit) malloc(sizeof(struct FUnit))) == NULL) {
            fputs("Error: Out of space!\n", stderr);
            exit(1);            
        }
        fUnit[i]->W0 = 0;
        fUnit[i]->nj = n;
        // 创建F(i, 0)的跳转数组
        if ((fUnit[i]->Wj = (int*) malloc(sizeof(int) * fUnit[i]->nj)) == NULL) {
            fputs("Error: Out of space!\n", stderr);
            exit(1);     
        }
        for (k = 0; k < fUnit[i]->nj; k++) {
            fUnit[i]->Wj[k] = 0;
        }
    }
    for (i = 0; i <= m; i++) {
        if ((aUnit[i] = (pAUnit *) malloc(sizeof(pAUnit) * (n + 1))) == NULL) {
            fputs("Error: Out of space!\n", stderr);
            exit(1);     
        }
        for (j = 0; j <= n; j++) {
            if ((aUnit[i][j] = (pAUnit) malloc(sizeof(struct AUnit))) == NULL) {
                fputs("Error: Out of space!\n", stderr);
                exit(1);     
            }
            aUnit[i][j]->Wi = 0;
        }
    }
    fUnit[0]->M = 0;
    aUnit[0][0]->M = gap;      // 注意这里设置A(0,0) != 0 是很有必要的,否则A(0,0)=F(0,0)会导致重复结果输出
    for (j = 1; j <= n; j++)
        aUnit[0][j]->M = gap;
    // 将字符串都变成大写
    strUpper(s);
    strUpper(r);
    // 动态规划算法计算得分矩阵每个单元的分值
    for (i = 1; i <= m; i++) {
        // 计算F(i, 0) i >= 1
        fUnit[i]->M = fUnit[i - 1]->M;
        for (j = 1; j <= n; j++)
            if (fUnit[i]->M < aUnit[i - 1][j]->M - t)
                fUnit[i]->M = aUnit[i - 1][j]->M - t;
        if (fUnit[i]->M == fUnit[i - 1]->M)
            fUnit[i]->W0 = 1;
        for (j = 1; j <= n; j++)
            if (fUnit[i]->M == aUnit[i - 1][j]->M - t)
                fUnit[i]->Wj[j - 1] = 1;
        // 计算A(i, 0) i >= 1
        aUnit[i][0]->M = fUnit[i]->M + gap;
        aUnit[i][0]->Wi |= 1;
        // 计算A(i, j) i >= 1 and j >= 1
        for (j = 1; j <= n; j++) {
            tm[0] = fUnit[i]->M + getFScore(s[i - 1], r[j - 1]);
            tm[1] = aUnit[i - 1][j]->M + gap;
            tm[2] = aUnit[i - 1][j - 1]->M + getFScore(s[i - 1], r[j - 1]);
            tm[3] = aUnit[i][j - 1]->M + gap;
            aUnit[i][j]->M = maxArray(tm, 4);
            for (k = 0; k < 4; k++)
                if (tm[k] == aUnit[i][j]->M)
                    aUnit[i][j]->Wi |= 1 << k;
        }
    }
    // 计算F(m + 1, 0)
    em = fUnit[m]->M;
    for (j = 1; j <= n; j++)
        if (em < aUnit[m][j]->M - t)
            em = aUnit[m][j]->M - t;
/*
    // 打印得分矩阵
    for (i = 0; i <= m; i++)
        printf("%f ", fUnit[i]->M);
    printf("\n");
    for (i = 0; i <= m; i++) {
        for (j = 0; j <= n; j++)
            printf("%f ", aUnit[i][j]->M);
        printf("\n");
    }
*/
    printf("max score: %f\n", em);
    // 打印最优比对结果,如果有多个,全部打印
    // 递归法
    if (em == 0) {
        fputs("No seq aligned.\n", stdout);
    } else {
        if ((salign = (char*) malloc(sizeof(char) * alnSize)) == NULL) {
            fputs("Error: Out of space!\n", stderr);
            exit(1);
        }
        if ((ralign = (char*) malloc(sizeof(char) * alnSize)) == NULL) {
            fputs("Error: Out of space!\n", stderr);
            exit(1);
        }
        if (em == fUnit[m]->M)
            printFAlign(fUnit, aUnit, m, s, r, salign, ralign, 0, 1);
        for (j = 1; j <= n; j++)
            if (em == aUnit[m][j]->M - t)
                printAAlign(fUnit, aUnit, m, j, s, r, salign, ralign, 0);
        // 释放内存
        free(salign);
        free(ralign);
    }
    for (i = 0; i <= m; i++) {
        for (j = 0; j <= n; j++)
            free(aUnit[i][j]);
        free(aUnit[i]);
    }
    free(aUnit);
    for (i = 0; i <= m; i++) {
        free(fUnit[i]->Wj);
        free(fUnit[i]);
    }
    free(fUnit);
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-09-20,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生信了 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 校正公式和代码
  • 对比对总长度的估计
  • 实现代码
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档