网页资讯视频图片知道文库贴吧地图采购
进入贴吧全吧搜索

 
 
 
日一二三四五六
       
       
       
       
       
       

签到排名:今日本吧第个签到,

本吧因你更精彩,明天继续来努力!

本吧签到人数:0

一键签到
成为超级会员,使用一键签到
一键签到
本月漏签0次!
0
成为超级会员,赠送8张补签卡
如何使用?
点击日历上漏签日期,即可进行补签。
连续签到:天  累计签到:天
0
超级会员单次开通12个月以上,赠送连续签到卡3张
使用连续签到卡
07月25日漏签0天
c语言吧 关注:798,852贴子:4,357,543
  • 看贴

  • 图片

  • 吧主推荐

  • 视频

  • 游戏

  • 1 2 下一页 尾页
  • 38回复贴,共2页
  • ,跳到 页  
<<返回c语言吧
>0< 加载中...

BWT以及BWTS算法的一点总结及看法

  • 只看楼主
  • 收藏

  • 回复
  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼

本人是学电子的,集成电路方向,因为本人毕业设计是BWT的电路芯片设计,在C语言建模的过程中遇到问题,于是在此请教。@RichSelian 兄弟提出了建议并建议我看了BWTS。原帖是http://tieba.baidu.com/p/1465143311 下面是我在设计过程中的一点总结以及硬件实现的看法。因为本人是学硬件的,C语言仅仅是学过并在单片机中用过,因此其中我自己写的C语言模型性能很差,也请大家提出意见。
真正的硬件代码verilog我还没开始写,写完后我会在此贴出来。。。



  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼

首先对于BWT,其原理是很简单的,就是数组的逐项移位从而组成二维数组,排序后输出最后一列以及原数组所在的行数字即可。
建模完成后我发现排序算法对其速度的影响相当之大 ,例如处理一个751K的TXT文件,每次处理256个字符,冒泡排序用的时间是快速排序的十倍。然而,在硬件实现时却远非仿真器结果所示。因为硬件电路在工作时是受时钟控制并且信号是逐次后移的,因此,串行处理的排列方式并不好,会很慢并且会产生较大的延迟。例如冒泡排序,他只能在前面的比较完成后后面一步才能进行,如果把每次处理都看做一个电路模块,显然他们的逻辑关系是串行的。于是硬件实现时可以并行实现的方法就变得很好了,例如双调排序,奇偶排序,虽然在C语言的模拟器上速度都不快。硬件实现最好的是双调排序。在此附上一个我写的奇偶排序的代码:
void qsort(char v[][lenth]){
int flag=1;
while(flag!=0){
flag=0;
for(int i=0;i<lenth-1;i+=2){
if(strncmp(v[i],v[i+1],lenth)>0){
swap(v,i,i+1,lenth);
flag++;
}
}
for(int j=1;j<lenth-1;j+=2){
if(strncmp(v[j],v[j+1],lenth)>0){
swap(v,j,j+1,lenth);
flag++;
}
}
}
}
例如:奇数区的循环时:a[1],a[2]的比较与a[3],a[4]的比较是独立的,可以并行实现。。。
再来一个快速排序法:
void qsort(char v[][lenth],int left,int right){
int i,last;
if(left>=right) return;
swap(v,left,(left+right)/2,lenth);
last=left;
for(i=left+1;i<=right;i++)
if(strncmp(v[i],v[left],lenth)<0)
swap(v,++last,i,lenth);
swap(v,left,last,lenth);
qsort(v,left,last-1);
qsort(v,last+1,right);
}


2025-07-25 10:36:30
广告
不感兴趣
开通SVIP免广告
  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼

但是BWT的算法虽然简单,却有一个棘手的问题,那就是常数index的存储,因为硬件实现的局限性,这个常数让我不知如何是好,于是RICH告诉我的BWTS便成为了我的方案之一:
下面是RICH给我的回信,我稍加修改后的内容:
这个算法是由Scott提出的,他并没有申请专利或者发表论文,而是直接在一个网站上发表的,我是通过一个网友的介绍得知这个算法的,算法目的就是为了消除BWT中的index,但原算法我也不太懂,他说的也不太明白,我就说一下Matt整理出来的算法。
正变换:
1.正变换需要用到标准Lyndon word划分:
一个长度为n的串A1A2A3...An经过旋转可以得到
A1A2A3...An
A2A3...AnA1
A3...AnA1A2
...
AnA1A2A3...
n个串,如果A1A2A3...An在这n个串中的字典序是最小的,那么A1A2A3...就是一个lyndon word
该划分实际上就是从字符串的第一个字符开始向后不断延伸,尽可能获得最长的lyndon word,然后对每一个Lyndon word按快处理。
将输入串分进行标准Lyndon word划分:以banana为例:
首先读入b,然后读入a,但是将ba旋转移位可以得到ab,显然ba>ab,所以ba就不是Lyndon word了,所以最长的Lyndon word就是[b].
再往后读入a,然后读入n,an经转换后可以得到na但是显然an最小,即为Lyndon word.,继续往后延伸,ana,显然ana经过逐次移位可以得到aan,所以ana不是Lyndon word,所以最长为[an]为Lyndon word,。。。。。。。。。。。
最后可得:
banana => [b][an][an][a]
2. 构造出所有Lyndon word的转置串,就是按每个Lyndon word块为单位对其进行循环移位(同BWT正变换),然后所有串字典排序(长度不够的先循环扩展),得到正变换结果(最后一列):
[aa]
[an]
[an]
[bb]
[na]
[na] => annbaa
逆变换:
1.求出输入串的每个符号的rank值(就是将输入进行稳定排序后符号所在的位置):
input rank index sorted
a 0 0 a
n 4 1 a
n 5 2 a
b 3 3 b
a 1 4 n
a 2 5 n
2.从某个出input[i]发,重复i = rank[i]这个过程,会发现走若干步后会回到原来的input[i],如i=1时:
1) i = 1
2) i = rank[1] = 4
3) i = rank[4] = 1(回到原来的input[i],形成环路)
这样就会得到一个环,然后按照rank从小到大,将这样的环都按顺序找出来:
[0] [14] [25] [3]
然后逆一下序变成:
[3] [25] [14] [0],对应到sorted表就得到原串banana
再给一个完整的例子:
bwts:
icanucan => [i][c][anuc][an] => [anan] => ncuciaan
[anuc]
[canu]
[cccc]
[iiii]
[nana]
[nuca]
[ucan]
unbwts:
input rank index sorted
n 5 0 a
c 2 1 a
u 7 2 c
c 3 3 c
i 4 4 i
a 0 5 n
a 1 6 n
n 6 7 u => [05] [1672] [3] [4] => [4] [3] [1672] [05]
i c anuc an => icanucan


  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼

我发现BWTS比BWT会复杂很多,但是其中很多部分可以实现并行模块,因此也有很高的价值。下面是我写的代码,很脑残,实现起来很慢,并且处理751k的txt文件时会有卡死现象发生,不知道什么原因,有知道的告诉我一下。因为只是前期建模,因此也木有弄得很漂亮,各位高手多指点。。。。
#include<stdio.h>
#include<string.h>
#include<iostream.h>
#include<ctime>
#include <stdlib.h>
#define lenth 64 //所处理的字符块的长度
//字符串复制函数
void copy1(char to[],char from[],int l1,int l2){
int k=0;
for(int i=l1;i<l2;i++){
to[k]=from[i];
k++;
}
}
//字符串比较函数
int strncmp(char s[],char t[],int lim){
for(;*s==*t;s++,t++)
if(*s=='\0'||--lim<=0)
return 0;
return *s-*t;
}
//单行字符串移位
void moveonechar(char s[],int lim){
char z;
z=s[0];
for(int f=0;f<lim;f++){
if(f<lim-1) s[f]=s[f+1];
else s[f]=z;
}
}
//字符串移位函数
void movechar(char s[],int lim,char **a){
char *c;
c=(char *)malloc(sizeof(char)*(lim));
copy1(c,s,0,lim);
for(int i=0;i<lim;i++){
for(int j=0;j<lim;j++)
a[i][j]=c[j];
moveonechar(c,lim);
}
}
//字符串交换函数,同时将记录字符串长度的数组也相应的置换
void swap(char a[][lenth],int b[],int i,int j,int l )
{
char c[lenth];
int k;
copy1(c,a[i],0,l);
copy1(a[i],a[j],0,l);
copy1(a[j],c,0,l);
k=b[i];
b[i]=b[j];
b[j]=k;
}
//数组排序
/*void qsort(char a[][lenth],int lim){
int z;
char c[lenth];
for(int i=0;i<lim;i++){
for(int j=i+1;j<lim;j++){
z=strncmp(a[i],a[j],lim);
if(z>0){
swap(a,i,j,lenth);
}
}
}
}*/
//快速排序
void qsort(char v[][lenth],int a[],int left,int right){
int i,last;
if(left>=right) return;
swap(v,a,left,(left+right)/2,lenth);
last=left;
for(i=left+1;i<=right;i++)
if(strncmp(v[i],v[left],lenth)<0)
swap(v,a,++last,i,lenth);
swap(v,a,left,last,lenth);
qsort(v,a,left,last-1);
qsort(v,a,last+1,right);
}
//奇偶排序
/*void qsort(char **v,int l){
int flag=1;
while(flag!=0){
flag=0;
for(int i=0;i<l-1;i+=2){
if(strncmp(v[i],v[i+1],l)>0){
swap(v,i,i+1,l);
flag++;
}
}
for(int j=1;j<l-1;j+=2){
if(strncmp(v[j],v[j+1],l)>0){
swap(v,j,j+1,l);
flag++;
}
}
}
}*/
//形成输出数组函数
void comout(char a[][lenth],char out[],int lim){
for(int i=0;i<lim;i++){
out[i]=a[i][lim-1];
}
}
int main(){
time_t begin,end;
begin=clock();
//getline(line,lenth);
FILE *read;
read=fopen("ab.txt","r+");
if(!read)
printf("can't open file\n");
char line[lenth],out[lenth];
int a[lenth];
int whilenum=0,cmp=0,c=1,reservei=0;
int linenum=0;
int resa[lenth];
//getline(line,lenth);
//putline(line,lenth);
char **b,*r,**rr,**layndown;
while ((fread(line , sizeof(char),lenth,read))==lenth)
{
b=(char **)malloc(sizeof(char*)*(1));



  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
layndown=(char **)malloc(sizeof(char*)*(lenth));
//line为读取的待处理数组,out为最终的处理结果
//数组a为记录主体处理部分while循环生成的每个layndown数组的元素个数
//动态数组b为layndown处理过程中的待判断动态字符快(是否为layndown)。layndown则为所记录的最长的layndown字符快
//
whilenum=0;cmp=0;c=1;reservei=0;
linenum=0;
//该while与for的嵌套动态循环完成了最长layndown模块的寻找
//实际上就是while完成待处理字符的逐个移动,linenum则是该移动的指针,for循环则是从该字符开始向后遍历,判断是否linenum与i之间
//的字符快是否为layndown word,并记录下最长的长度。在下一次while循环中则不需要再在layndown word中间移动了,直接从最长的layndown word
//后面开始
while(linenum<lenth){
for(int i=linenum;i<lenth;i++){
free(b);
b=(char **)malloc(sizeof(char*)*(i+1-linenum));//申请二维动态数组,因为要对待处理快进行循环移位,拓展成二维,以进行layndown的判断
for(int j=0;j<i-linenum+1;j++){ //完成二维数组的申请
b[j]=(char *)malloc(sizeof(char)*(i+1-linenum));
}
copy1(b[0],line,linenum,i+1); //将待处理的块拷贝入b数组中准备处理
movechar(b[0],i+1-linenum,b); //拓展成为二维
cmp=0;
c=0;
while(cmp==0&&c<i+1-linenum){ //该while循环则是完成是否是layndown word的判断
if(strncmp(b[0],b[c],i+1-linenum)>0){
cmp=1;
}
c++;
}
if(cmp==0) //仅仅记录下layndown word的长度,因为他是不断覆盖的,最终记录的就是最长的。。。
reservei=i;
}
//接下来的一小段代码则是完成将每次for循环中生成的最长layndown word读取出来,储存在layndown word中,数组a中则是其长度的储存
//其中whilenum是while循环次数的记录
r=(char *)malloc(sizeof(char)*(reservei+1-linenum));
copy1(r,b[0],0,reservei+1-linenum);
a[whilenum]=reservei+1-linenum;
layndown[whilenum]=(char *)malloc(sizeof(char)*(reservei+1-linenum));
copy1(layndown[whilenum],r,0,reservei+1-linenum);
whilenum++;
linenum=reservei+1;
free(r);
}
free(b);
//下面则是对生成的layndown word分别进行循环移位的拓展,并将其进一步拓展为lenth*lenth的二维数组,并进行排序,生成输出。
int sum=0;
char end[lenth][lenth]; //输出之前的二维数组都将保存在end中
//int resa[lenth]; //记录下end中每一行的实际长度(拓展为lenth*lenth的二维数组之前的长度)
for(int cend=0;cend<lenth;cend++){ //初始化一下
for(int cend1=0;cend1<lenth;cend1++){
end[cend][cend1]=0;
}
}
for(int endnum=0;endnum<whilenum;endnum++){ //申请对应长度的数组
rr=(char **)malloc(sizeof(char*)*(a[endnum]));
for(int rrn=0;rrn<a[endnum];rrn++){
rr[rrn]=(char *)malloc(sizeof(char)*(a[endnum]));
}
movechar(layndown[endnum],a[endnum],rr); //每一个layndown word的循环移位
//free(layndown);
int rri=0;
//对应的长度记录也要拓展
for(int toend=sum;toend<sum+a[endnum];toend++){
copy1(end[toend],rr[rri],0,a[endnum]);
resa[toend]=a[endnum];
rri++;
}
sum=sum+a[endnum];
free(rr);
}
free(layndown);
//倒数第二步的lenth*lenth的拓展
for(int stend=0;stend<lenth;stend++){
int mv=resa[stend];
int add=0;
for(;mv<lenth;mv++){
end[stend][mv]=end[stend][add];
add++;
}
}
qsort(end,resa,0,lenth-1); //排序
comout(end,out,lenth); //生成输出数组
//putline(out,lenth);
long pos_file = ftell(read);//ftell函数返回stream流的当前文件位置
fseek(read,pos_file - lenth, SEEK_SET);//重新设置流stream的文件位置,将位置设置在需要写入数据的地方
fwrite(out,sizeof(char),lenth,read);
pos_file = ftell(read);
fseek(read,pos_file,SEEK_SET);//重新设置位置,使得fgets函数从正确位置开始读
}
fclose(read);
printf("算法结束\n");
end=clock();
cout<<"runtime: "<<double(end-begin)/CLOCKS_PER_SEC<<endl;
return 0;
}


  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼

总的来说,BWT在硬件上实现的可能性很小。目前硬件上只有IBM用嵌入式做过。这个项目是中科院云处理系统的一部分,教授只是想考验下我,嘿嘿。我有个很强的师兄用verilog描述了一下,发现最终变成了一个文件内容的读写操作,几乎所有的时间都用在了读写上,并且消耗巨大。
多谢RICH兄弟以及C吧的帮助,努力学好C是我下一步的目标之一。。。
另外我正在写LZ77的模型,需要用到hash数组,我没有接触过,各位推荐一本描述数据结构(C语言)比较好的书吧,谢谢。


  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
自己顶一个。。。


  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
继续战术自顶。。。


2025-07-25 10:30:30
广告
不感兴趣
开通SVIP免广告
  • 我变成鱼了
  • 彩虹面包
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
64byte的块确实太。。一般来说BWT系列的变换至少要100KB级别的块才能体现出对LZ77的优势,分块大了排序的瓶颈才会表现出现
所以bwt/bwts的关键是提高后缀排序的效率,效率提不上的话很难在实际中应用


  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
这个我知道,但是硬件实现的话上kb的东西过于庞大,我做一年也完成不了,电路中大量的器件会导致后期布线时让人产生轻生的念头的,哈哈,我的目标是能实现功能就OK了。毕竟没有真正接触过工程上的东西。


  • bc12358
  • 彩虹面包
    13
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
很久没出现的[精],先插后看


  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
另外你有没有看到哪本数据结构的书里面对hash数组的描述比较好的,说下,谢谢。


  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
貌似不是。。。


  • chenxiaozi007
  • 低能力者
    5
该楼层疑似违规已被系统折叠 隐藏此楼查看此楼
插晚了。。。


登录百度账号

扫二维码下载贴吧客户端

下载贴吧APP
看高清直播、视频!
  • 贴吧页面意见反馈
  • 违规贴吧举报反馈通道
  • 贴吧违规信息处理公示
  • 1 2 下一页 尾页
  • 38回复贴,共2页
  • ,跳到 页  
<<返回c语言吧
分享到:
©2025 Baidu贴吧协议|隐私政策|吧主制度|意见反馈|网络谣言警示