c语言模拟实现DTW(动态时间规整算法)

关于DTW算法的原理这篇博客写的很好https://blog.csdn.net/aa8568849/article/details/53841189?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.nonecase
作者对原文的c程序进行注释和改进如下:


#include "stdio.h"
#include "windows.h" 

struct pointOritation//保存当前节点方向,用来回溯每个W点
{
    int frontI,frontJ;
};


/*求最小累计距离的二维数组g,
传入参数p为标准模板和测试模板各元素之间的欧氏距的二维数组的首地址
n,m为数组的行数和列数
g为所求最小累积距离数组的首地址 
pr为保存g各个元素方向的结构体数组的首地址 */
void gArray(int *p,int n,int m,int *g,struct pointOritation *pr)
{
	//定义行标和列标变量i,j
	int i, j; 
	
    *(g+(n-1)*m)=(*(p+(n-1)*m))*2;	//计算g起始点的值及其上个节点的行标和列标(最左下角的点)即g[5][0] 
    (pr+(n-1)*m)->frontI = -1;
	(pr+(n-1)*m)->frontJ = -1;

    for (i=1; i<m; i++)//循环m-1次计算g最下面一横的值,(除g[5][0])(只有一个方向) 
    {
        *(g+(n-1)*m+i)=*(g+(n-1)*m+i-1)+*(p+(n-1)*m+i);  //求值 
        (pr+(n-1)*m+i)->frontI=n-1; 	// 求当前节点的最小累计距离的方向 
        (pr+(n-1)*m+i)->frontJ=i-1;     //保存方法为保存当前节点的上个节点的数组下标 
        // frontI为行标,frontJ为列标 
    }

    for (i=n-2; i>=0; i--)//循环n-1次最左边的一竖的值, (除g[5][0])(只有一个方向)
    {
        *(g+i*m)=*(g+(i+1)*m)+*(p+i*m);
        (pr+i*m)->frontI=i+1;
        (pr+i*m)->frontJ=0;
    }
    
    //计算剩余网格的G值   i为行标,j为列标 
    for (i=n-2; i>=0; i--)
    {
        for (j=1; j<m; j++)
        {
            int left,under,incline;  //分别表示当前节点三个方向上的累计距离值 
            left=*(g+i*m+j-1)+*(p+i*m+j);
            under=*(g+(i+1)*m+j)+*(p+i*m+j);
            incline=*(g+(i+1)*m+j-1)+(*(p+i*m+j))*2;

            //从左、下、斜三个方向选出最小的
            int min=left;
            *(g+i*m+j)=min;
            (pr+i*m+j)->frontI=i;
            (pr+i*m+j)->frontJ=j-1;

            if (min>under)
            {
                min=under;
                *(g+i*m+j)=min;
                (pr+i*m+j)->frontI=i+1;
                (pr+i*m+j)->frontJ=j;
            }
            if (min>incline)
            {
                min=incline;
                *(g+i*m+j)=min;
                (pr+i*m+j)->frontI=i+1;
                (pr+i*m+j)->frontJ=j-1;
            }
        }
    }
    
    //输出G数组
    printf("g矩阵如下:\n"); 
    for (i=0; i<n; i++)
    {
        for (j=0; j<m; j++)
        {
            printf("%d\t",*(g+i*m+j));
        }
		printf("\n");
    }
    
    //输出方向数组
    printf("方向矩阵如下:\n");
    for (i=0; i<n; i++)
    {
        for (j=0; j<m; j++)
        {
            printf("(%d,%d)\t",(pr+i*m+j)->frontI,(pr+i*m+j)->frontJ);
        }
		printf("\n");
    }
}

void printPath(struct pointOritation *po,int n,int m,int *g)
{
	//由于最短路径是从终点回溯找到起点,所以这里利用一个结构体数组实现正序输出路径
	struct temp_save{
		int i, j, distance;
	};
	struct temp_save temp[10];
	int t = 0;
	printf("路径如下:\n");
    int i=0,j=m-1; 
    while (1)
    {	
        int ii=(po+i*m+j)->frontI,jj=(po+i*m+j)->frontJ;
        temp[t].i = i;
        temp[t].j = j;
        temp[t].distance = *(g+i*m+j);
        t++;
        i=ii;
        j=jj;
        if(i==-1 && j==-1)
            break;
    }
    t--;
    while(t>=0){
    	printf("(%d, %d): 当前最小累积距离: %d\n", temp[t].i, temp[t].j, temp[t].distance);
    	t--;
	}
	printf("标准模板与匹配模板的最小累积距离=%d\n", temp[t+1].distance);
}
int main()
{
	//标准模板和匹配模板各元素之间的欧氏距离矩阵 
    int  d[6][4]={
                    {2,1,7,5},
                    {1,5,1,6},
                    {4,7,2,4},
                    {5,2,4,3},
                    {3,4,8,2},
                    {2,1,5,1},
                };
                
    //存放累积最小距离的矩阵g 
    int g[6][4];
    
    struct pointOritation pOritation[6][4];//用来存放g中当前节点的来源路径的结构体数组 
    
    //求出g和pOritation并打印 
    gArray(*d,6,4,*g,*pOritation);
    
    //打印路径即标准模板和匹配模板之间各元素的映射关系 
    printPath(*pOritation, 6, 4,*g);
    
    system("pause");
    return 0;
}

运行结果如下:
在这里插入图片描述

©️2020 CSDN 皮肤主题: 黑客帝国 设计师:上身试试 返回首页