合并有序数组问题:无法正确处理重复值与比较逻辑
合并降序去重数组的汇编问题修复
需求说明
需要合并两个元素为4字节int、降序排列且以0结尾的数组,结果存入mergedArray地址,要求新数组满足:
- 保持降序排列
- 以0结尾
- 每个值最多出现一次
现有代码在数组存在重复值时失效,尝试通过比较原数组与新数组的值跳过重复项,但该逻辑未起作用。
原代码
.global _start .section .text _start: mov $array1, %rax mov $array2, %rcx mov $mergedArray, %r8 xor %r14,%r14 loopcheck: #checks if arrays are finished movl (%rax), %r9d movl (%rcx), %r10d movl (%r8), %r11d testl %r9d, %r9d jz rest_of_array2 testl %r10d, %r10d jz rest_of_array1 loop: #the main loop cmp %r10d, %r9d jg add_r9d jmp add_r10d add_r9d: #add rax value cmp %r11d,%r9d jz remove_current_r9d mov %r9d, (%r8) lea 4(%r8), %r14 mov %r14 , %r8 remove_current_r9d: #adv rax lea 4(%rax), %r14 mov %r14, %rax jmp loopcheck add_r10d: #add rcx value cmp %r11d, %r10d jz remove_current_r10d mov %r10d, (%r8) lea 4(%r8),%r14 mov %r14, %r8 remove_current_r10d: #adv rcx lea 4(%rcx), %r14 mov %r14, %rcx jmp loopcheck rest_of_array2: #adding the rest of array 2 once array 1 is finished testl %r10d, %r10d jz end cmp %r10d,%r11d jz finish_loop2 movl %r10d, (%r8) lea 4(%r8),%r14 mov %r14, %r8 finish_loop2: lea 4(%rcx), %r14 mov %r14 ,%rcx movl (%rcx), %r10d movl (%r8), %r11d jmp rest_of_array2 rest_of_array1: #adding the rest of array 1 once array 2 is finished testl %r9d,%r9d jz end cmp %r9d,%r11d jz finish_loop1 movl %r9d, (%r8) lea 4(%r8),%r14 mov %r14, %r8 finish_loop1: lea 4(%rax),%r14 mov %r14 ,%rax movl (%rax), %r9d movl (%r8), %r11d jmp rest_of_array1 end: #ennd xor %r14,%r14 mov %r14, (%r8)
问题根源
- 去重逻辑的比较对象错误:代码中用
movl (%r8), %r11d获取比较值,但%r8始终指向下一个要写入的位置,而非最后一个已写入的元素。初始时mergedArray未初始化,%r11d是随机垃圾值;写入后,%r8已移动到下一个位置,该位置的值仍是未知的,导致比较完全失效。 - 未维护最后写入的元素状态:没有变量记录已写入数组的最后一个值,无法准确判断当前元素是否重复。
修复后的代码
.global _start .section .text _start: mov $array1, %rax # 指向array1当前元素 mov $array2, %rcx # 指向array2当前元素 mov $mergedArray, %r8 # 指向mergedArray的写入位置 movl $-1, %r11d # 初始化最后写入的值为-1(适配原数组非负特性,若含负数可改为0x80000000) loopcheck: movl (%rax), %r9d # 取array1当前元素 movl (%rcx), %r10d # 取array2当前元素 # 检查array1是否已遍历完(遇到0) testl %r9d, %r9d jz rest_of_array2 # 检查array2是否已遍历完(遇到0) testl %r10d, %r10d jz rest_of_array1 loop: # 比较两个数组当前元素,选择较大的优先处理 cmp %r10d, %r9d jg add_r9d jmp add_r10d add_r9d: # 检查当前元素是否与最后写入的元素重复 cmp %r11d, %r9d jz skip_r9d # 重复则跳过,直接移动array1指针 # 不重复则写入mergedArray mov %r9d, (%r8) mov %r9d, %r11d # 更新最后写入的值 lea 4(%r8), %r8 # 移动写入指针到下一个位置 skip_r9d: lea 4(%rax), %rax # 移动array1指针 jmp loopcheck add_r10d: # 检查当前元素是否与最后写入的元素重复 cmp %r11d, %r10d jz skip_r10d # 重复则跳过,直接移动array2指针 # 不重复则写入mergedArray mov %r10d, (%r8) mov %r10d, %r11d # 更新最后写入的值 lea 4(%r8), %r8 # 移动写入指针到下一个位置 skip_r10d: lea 4(%rcx), %rcx # 移动array2指针 jmp loopcheck rest_of_array2: # 处理array2剩余元素 testl %r10d, %r10d jz end cmp %r11d, %r10d jz skip_rest2 mov %r10d, (%r8) mov %r10d, %r11d lea 4(%r8), %r8 skip_rest2: lea 4(%rcx), %rcx movl (%rcx), %r10d jmp rest_of_array2 rest_of_array1: # 处理array1剩余元素 testl %r9d, %r9d jz end cmp %r11d, %r9d jz skip_rest1 mov %r9d, (%r8) mov %r9d, %r11d lea 4(%r8), %r8 skip_rest1: lea 4(%rax), %rax movl (%rax), %r9d jmp rest_of_array1 end: # 写入结束标记0 movl $0, (%r8)
关键修改点
- 新增
%r11d变量维护最后写入mergedArray的元素值,初始值根据数组元素范围调整,确保不会与有效元素重复。 - 所有去重比较逻辑改为和
%r11d(最后写入值)对比,而非%r8指向的未写入位置。 - 每次写入元素后,立即更新
%r11d为当前写入的值,保证后续比较准确。 - 简化指针移动逻辑,去掉冗余的
%r14中转,直接用lea更新寄存器。
内容的提问来源于stack exchange,提问作者a boi
相关产品推荐
相关产品推荐

