面试题答案
一键面试优化思路
- 减少内存访问次数:通过将数组元素加载到寄存器中进行操作,减少对内存的读写次数,因为寄存器访问速度远快于内存。
- 利用指令级并行:特定CPU指令集(如SSE)能够在一个指令周期内处理多个数据,利用这种特性提升排序的效率。
冒泡排序的C语言原始代码
void bubbleSort(int arr[], int n) {
int i, j, temp;
for (i = 0; i < n - 1; i++) {
for (j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
内联汇编优化关键代码片段(以x86架构为例)
void optimizedBubbleSort(int arr[], int n) {
int i, j, temp;
for (i = 0; i < n - 1; i++) {
for (j = 0; j < n - i - 1; j++) {
__asm__ volatile (
"movl (%[arr1]), %%eax\n\t"
"movl 4(%[arr2]), %%ebx\n\t"
"cmp %%eax, %%ebx\n\t"
"jle skip_swap\n\t"
"movl %%eax, 4(%[arr2])\n\t"
"movl %%ebx, (%[arr1])\n\t"
"skip_swap:\n\t"
:
: [arr1] "r" (&arr[j]), [arr2] "r" (&arr[j + 1])
: "eax", "ebx"
);
}
}
}
解释:
movl (%[arr1]), %%eax
:将arr[j]
的值加载到eax
寄存器。movl 4(%[arr2]), %%ebx
:将arr[j + 1]
的值加载到ebx
寄存器。cmp %%eax, %%ebx
:比较eax
和ebx
的值。jle skip_swap
:如果arr[j] <= arr[j + 1]
,则跳过交换。- 交换操作:将
eax
的值存入arr[j + 1]
,ebx
的值存入arr[j]
。
利用SSE指令集进一步提升性能
- 加载数据:使用SSE指令(如
movdqa
)将多个数组元素加载到XMM寄存器中,一次加载128位(4个32位整数)。 - 比较和交换:利用SSE的比较指令(如
pcmpeqd
)和数据操纵指令(如movd
和pshufd
)来并行比较和交换多个元素。 - 存储数据:使用
movdqa
将修改后的数据从XMM寄存器存储回内存。
示例代码片段:
#include <emmintrin.h>
void sseOptimizedBubbleSort(int arr[], int n) {
int i, j;
for (i = 0; i < n - 1; i++) {
for (j = 0; j < n - i - 1; j += 4) {
__m128i xmm1 = _mm_loadu_si128((__m128i *)&arr[j]);
__m128i xmm2 = _mm_loadu_si128((__m128i *)&arr[j + 4]);
__m128i cmp = _mm_cmpgt_epi32(xmm1, xmm2);
__m128i swapped = _mm_blendv_epi8(xmm1, xmm2, cmp);
__m128i other = _mm_blendv_epi8(xmm2, xmm1, cmp);
_mm_storeu_si128((__m128i *)&arr[j], swapped);
_mm_storeu_si128((__m128i *)&arr[j + 4], other);
}
}
}
解释:
_mm_loadu_si128
:从内存中加载128位数据到XMM寄存器。_mm_cmpgt_epi32
:比较两个XMM寄存器中的4个32位整数,返回比较结果。_mm_blendv_epi8
:根据比较结果交换两个XMM寄存器中的数据。_mm_storeu_si128
:将XMM寄存器中的128位数据存储回内存。