local function fShallowCopy(tData)
local tOutput = {}
for k,v in ipairs(tData) do
tOutput[k] = v
end
return tOutput
end
local function fLexTblSort(tA,tB) --sorter for tables
for i=1,#tA do
if tA[i]~=tB[i] then
return tA[i]<tB[i]
end
end
return false
end
function fBWT(tData)
--setup--
local iSize = #tData
local tSolution = {}
local tSolved = {}
--key table--
for n=1,iSize do
tData[iSize] = fRemove(tData,1)
tSolution[n] = fShallowCopy(tData)
end
table.sort(tSolution,fLexTblSort)
--encode output--
for i=1,iSize do
tSolved[i] = tSolution[i][iSize]
end
--finalize--
for i=1,iSize do
if fIsEqual(tSolution[i],tData) then
return i,tSolved
end
end
return false
end
以上是我目前在Lua中实现BWT编码的代码。问题是因为表的大小和循环的长度需要很长时间才能运行。对于1000个字符的输入,平均编码时间约为1.15秒。有没有人建议更快的BWT编码功能?
最大的减速似乎出现在fLexTblSort和fShallowCopy中。我也将BWT功能都包括在内。
答案 0 :(得分:0)
如果我看对了,那么如果排序是快速排序,则算法的复杂度为O(n^2 log n)
。比较器函数fLexTblSort
为您比较的每对值获取O(n)
。
几年前,当我查看我的实施时,我看到可能的空间需要改进。您可以创建tData
的所有可能旋转,这也需要很长时间。我只使用单个数据块而且只存储了特定旋转的起始位置。你也使用了很多可以缩小的循环。
我的实施是在C中,但这个概念也可以在Lua中使用。你的Lua和C之间的一些混合伪代码的想法。
function fBWT(tData)
local n = #tData
local tSolution = {}
for(i = 0; i < n; i++)
tSolution[i] = i;
--table.sort(tSolution, fLexTblSort)
quicksort(tData, n, tSolution, 0, n)
for(i = 0; i < n; i++){
tSolved[i] = tData[(tSolution[i]+n-1)%n];
if( tSolution[i] == 0 )
I = i;
}
return I, tSolved
end
您还需要自己的排序功能,因为标准不能为此魔法提供足够的灵活性。 Quicksort是一个好主意(你可能会避免一些争论,但我只粘贴了我正在使用的C版本):
void swap(int array[], int left, int right){
int tmp = array[right];
array[right] = array[left];
array[left] = tmp;
}
void quicksort(uint8_t data[], int length, int array[], int left, int right){
if(left < right){
int boundary = left;
for(int i = left + 1; i < right; i++){
if( offset_compare(data, length, array, i, left) < 0 ){
swap(array, i, ++boundary);
}
}
swap(array, left, boundary);
quicksort(data, length, array, left, boundary);
quicksort(data, length, array, boundary + 1, right);
}
}
最后一步是你自己的比较器功能(类似于你原来的,但是在C轮上进行旋转):
/**
* compare one string (fixed length) with different rotations.
*/
int offset_compare(uint8_t *data, int length, int *array, int first, int second){
int res;
for(int i = 0; i < length; i++){
res = data[(array[first]+i)%length] - data[(array[second]+i)%length];
if( res != 0 ){
return res;
}
}
return 0;
}
这是我几年前提出的基本想法,对我有用。如果有不清楚或有些错误,请告诉我。