我正在x64 MASM中开发霍夫曼压缩的实现。我的C语法主要功能是:
void* huffCompress(void* lpDataStream, unsigned long long qwLength);
我使用的是Microsoft的Fastcall约定,其中参数通过RCX,RDX,R8和R9(堆栈上的其他任何东西)传递给被调用的函数。
我写过代码,生成的数组大小为256 * 3。每3个字节包含:
as STRUCT
word wFreq
byte bSymbol
as ENDS
然后,代码在lpDataStream上迭代两次。
使用数组中的索引初始化bSymbol
每个字节的wFreq递增
在下面的代码中,RBX是指向数组基础的指针,RSI是指向lpDataStream的指针,而RCX是qwLength。在输入以下代码之前,RAX必须为0。
_populateArray:
lodsb
lea rdx, qword ptr[rbx+rax*04h]
sub rdx, rax
inc word ptr[rdx]
loop _populateArray
然后,该函数遍历数组,对于wFreq不为零的每个元素,它从堆栈中减去13h(19个字节)。然后按照以下结构填充这19个字节。
nl STRUCT
qword pFLink
qword pBLink
dword dwFreq
byte bSymbol
nl ENDS
前两个qword是指向链接列表中下一个和上一个元素的正向和反向链接。
xor rax, rax
mov r10, rsp
mov rcx, rax ;rcx = pFLink
mov rdx, rax ;rdx = pBLink
_generateLinkedList:
cmp word ptr[rbx+rax], 0000h
je _notInitialised
sub rsp, 13h
;write and setup pBLink for next entry
mov qword ptr[rsp+pBLink], rdx
mov rdx, rsp
mov r8w, word ptr[rbx+rax]
mov r9b, byte ptr[rbx+rax+02h]
mov word ptr[rsp+wFreq], r8w ;write dFreq to linked list
mov byte ptr[rsp+bSymbol], r9b ;write bSymbol to linked list
cmp rcx, 00h ;if pFLink is not initialised it means this is the first entry
je _firstEntry
mov qword ptr[rsp+13h], rsp ;when rcx != 00h it means that there is an entry before this one "before" on stack remember
_firstEntry:
mov rcx, rsp
_notInitialised:
add rax, 03h
cmp rax, 300h
jna _generateLinkedList
上面的代码按需工作,为完整性起见我添加了它。 RBX仍指向该数组。
然后该函数对结果链表进行冒泡排序,并按升序排序。这意味着没有pBLink(没有向后链接)的元素的wFreq最低。这不是一个循环的双向链表。
实现霍夫曼压缩的下一步是创建一个wFreq等于两个最低频率之和的节点。
我的计划是执行以下操作:
将两个最低的wFreq值相加
在最低元素NULL中设置pFLink
使pFLink和pBLink均为第二低的(pHead-> pFLink)NULL
留出更多的堆栈空间(19个字节),并在末尾添加一个节点(这涉及到找到一个具有NULL pFLink的元素并将其更改为新节点。此外,新节点的wFreq为最低的两个加在一起。
这是问题所在。我需要使新节点的pFLink和pBLink指向两个最低的元素(在第2步和第3步中其指针为NULL的节点)。如果执行此操作,则新节点将无法连接到链表。
编辑:我认为上述选项会起作用,我将不得不重新整理排序算法,以便在添加新节点并需要对其进行排序时将其插入元素之间。该代码将意识到它已经找到了“新节点”,因为pBLink不正确。然后,它将知道下一个元素直接在“上方”(“新节点”上方19个字节)。我认为这可以在创建新节点期间完成,因为不需要将新节点放置在堆栈上的新空间中,可以将其与所需位置的元素交换。如果有更好的方法,我想听听,这是一个肮脏的解决方法。
我有一个想法,当排序功能找到一个节点,其中pBLink不指向前一个元素时,它应该通过从其指针中减去13h来向上移动下一个元素。这不起作用,因为新节点(通过将两个最低频率相加而创建的节点)可以在排序后的任何地方。
有什么方法可以解决此问题,而无需在nl结构中再添加两个qword?
答案 0 :(得分:1)
如果您对速度感兴趣,那么您需要首先考虑周密的算法选择,然后再考虑将其编写为汇编器。正确选择算法将提高数量级。然后在汇编器中编写它可能会为您带来一些小改进。
特别是,您需要更好的选择 进行排序,在这种情况下可能需要快速排序,并且您可以执行Huffman coding much more simply, in place,而无需重新排序链接列表。