BWT(压缩与还原)

BWT(Burrows-Wheeler Transform)变换通过添加美元符号并进行字符串移动及排序来实现。在排序后取最后一列作为BWT结果。还原过程中,从BWT结果找到美元符号,按顺序找到对应字符,逐步构建原始字符串。压缩方面,由于BWT的特性,可以用于数据压缩,但直接使用矩阵操作可能空间消耗大。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

BWT(Burrows-Wheeler Transformation)

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;
}



运行结果




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值