BWT变换:通过某一种变换得到新的字符串
以英文单词为例
在其末尾我们给它添加一个美元符号"$"变成:
将字符串往右依次移动一个字符,重复上述工作变成:
取其最小正周期
我们对其排序,规定"$"比任何字母都要小。以字典顺序排序后得到:
取其最后一列
即为BWT变换。
排序后的字符串 BWT变换后的字符串
先在BWT变换后的字符串中找到美元符号"$",和它同一行的字母是B,我们先写下,$B找到B之后我们在右边一栏里找B,与其对应的是A,
然后记下$BA,
现在A的在左边是第三次出现的,故在右边一栏里找A,同样是第三次出现的,与之对应的是N,然后记下$BAN,左边的N
是第二次出现的,故在右边一栏里找N同样是第二次出现的,与之对应的是A,
然后记下$BANA,现在A的在左边是第二次出现的,故在右边,一栏里找A同样是第二次出现的,与之对应的是N,然后记下$BANAN
左边N的是第一次出现的,故在右边一栏里找N同样是第一次出现的,
与之对应的是A,然后记下$BANANA,现在的A在左边是第一次出现的,故在右边一栏里找A同样是第一次出现的,与之对应的是"$",结束。
写的很烂,只能凑合看了
还原:
#include<stdio.h>
#include<string.h>
#define N 1000
char str[N],st[N],bwt[N]; //bwt保存的是原始字符串,str是排序后的字符串
void PrintString(char* A)
{
int i;
for(i=0;i<strlen(A);i++)
printf("%c",A[i]);
}
void Swap(char* A,int i,int j)
{
char temp=A[i];
A[i]=A[j];
A[j]=temp;
}
void Sort(char* s)
{
int i,j=0;
char temp;
for(i=0;i<strlen(s);i++)
str[j++]=s[i];
str[j]='\0';
for(i=0;i<strlen(str);i++)
{
if(str[i]=='$')
{
Swap(str,i,0);
break ;
}
}
for(i=1;i<strlen(str)-1;i++)
{
for(j=i+1;j<strlen(str);j++)
{
if(str[i]>str[j])
{
Swap(str,i,j);
}
}
}
PrintString(str);
}
int FindInBwt(char* A,char ch,int n)
{
int i,count=0;
for(i=0;i<strlen(A);i++)
{
if(A[i]==ch )
{
count++;
if(count==n)
break;
}
}
return i;
}
int FindInAfterSort(char* A,char ch,int n)
{
int i,count=0;
for(i=0;i<=n;i++)
{
if(ch==A[i])
count++;
}
return count;
}
int main()
{
int i,k,n=1;
char ch='$';
fgets(bwt,sizeof(bwt),stdin);
bwt[strlen(bwt)-1]='\0';
Sort(bwt);
for(i=0;i<strlen(bwt);i++)
{
k=FindInBwt(bwt,ch,n);
st[i]=str[k];
n=FindInAfterSort(str,st[i],k);
ch=st[i];
if(st[i]=='$')
break;
}
st[++i]='\0';
printf("\n");
PrintString(st);
return 0;
}
压缩:
没想到其它办法,用矩阵太消耗空间了。
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
#define N 1000
char **str,bwt[N];
void MallocArray(int n)
{
int i;
str=(char **)malloc(n*sizeof(char*));
for(i=0;i<n;i++)
str[i]=(char *)malloc(n*sizeof(char));
}
void InitializeArray(char **S,int n)
{
int i,j;
for(i=0;i<n;i++)
S[0][i]=bwt[i];
for(i=1;i<n;i++)
{
char temp=S[i-1][n-1];
for(j=n-1;j>0;j--)
{
S[i][j]=S[i-1][j-1];
}
S[i][0]=temp;
}
}
void SortArray(char **S,int n)
{
int i,j;
char temp[N];
for(i=0;i<n;i++)
S[i][n]='\0';
for(i=0;i<n-1;i++)
{
for(j=i+1;j<n;j++)
{
if(strcmp(S[i],S[j])>0)
{
strcpy(temp,S[i]);
strcpy(S[i],S[j]);
strcpy(S[j],temp);
}
}
}
}
void ReplaceChar(char **S,int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
{
if(S[i][j]-'0'==-42)
S[i][j]='$'; // 将ASCII码==006的变成"$"
}
}
}
void PrintResult(char **S,int n)
{
int i;
for(i=0;i<n;i++)
printf("%c",S[i][0]);
printf("\n");
for(i=0;i<n;i++)
printf("%c",S[i][n-1]);
}
void FreeArray(char **S,int n)
{
int i;
for(i=0;i<n;i++)
free(S[i]);
free(S);
}
int main()
{
int i;
fgets(bwt,sizeof(bwt),stdin);
bwt[strlen(bwt)-1]=(char)6; // 由于"$"的ASCII码大于" " 故选择一个比其小的字符。
bwt[strlen(bwt)]='\0';
int len=strlen(bwt);
MallocArray(len+2);
InitializeArray(str,len);
SortArray(str,len);
ReplaceChar(str,len);
PrintResult(str,len);
FreeArray(str,len+2);
return 0;
}
运行结果: